Initial import of Fantomas client library (#6)
Some checks failed
.NET / build (Debug) (push) Has been cancelled
.NET / build (Release) (push) Has been cancelled
.NET / analyzers (push) Has been cancelled
.NET / build-nix (push) Has been cancelled
.NET / check-dotnet-format (push) Has been cancelled
.NET / check-nix-format (push) Has been cancelled
.NET / Check links (push) Has been cancelled
.NET / Check flake (push) Has been cancelled
.NET / nuget-pack (push) Has been cancelled
.NET / expected-pack (push) Has been cancelled
.NET / all-required-checks-complete (push) Has been cancelled

This commit is contained in:
Patrick Stevens
2024-10-04 15:13:49 +01:00
committed by GitHub
parent 0dad74819e
commit 8834d885de
41 changed files with 2915 additions and 5 deletions

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

View File

@@ -155,6 +155,11 @@ jobs:
with:
name: nuget-package-core
path: WoofWare.Whippet.Core/bin/Release/WoofWare.Whippet.Core.*.nupkg
- name: Upload NuGet artifact (Fantomas)
uses: actions/upload-artifact@v4
with:
name: nuget-package-fantomas
path: WoofWare.Whippet.Fantomas/bin/Release/WoofWare.Whippet.Fantomas.*.nupkg
expected-pack:
needs: [nuget-pack]
@@ -176,6 +181,14 @@ jobs:
- name: Check NuGet contents
# Verify that there is exactly one nupkg in the artifact that would be NuGet published
run: if [[ $(find packed-core -maxdepth 1 -name 'WoofWare.Whippet.Core.*.nupkg' -printf c | wc -c) -ne "1" ]]; then exit 1; fi
- name: Download NuGet artifact (Fantomas)
uses: actions/download-artifact@v4
with:
name: nuget-package-fantomas
path: packed-fantomas
- name: Check NuGet contents
# Verify that there is exactly one nupkg in the artifact that would be NuGet published
run: if [[ $(find packed-fantomas -maxdepth 1 -name 'WoofWare.Whippet.Fantomas.*.nupkg' -printf c | wc -c) -ne "1" ]]; then exit 1; fi
all-required-checks-complete:
needs: [check-dotnet-format, check-nix-format, build, build-nix, linkcheck, flake-check, nuget-pack, expected-pack, analyzers]

View File

@@ -0,0 +1,28 @@
namespace WoofWare.Whippet.Fantomas.Test
open NUnit.Framework
open WoofWare.Whippet.Fantomas
open ApiSurface
[<TestFixture>]
module TestSurface =
let coreAssembly = typeof<CompExprBinding>.Assembly
[<Test>]
let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical coreAssembly
(*
[<Test>]
// https://github.com/nunit/nunit3-vs-adapter/issues/876
let CheckVersionAgainstRemote () =
MonotonicVersion.validate assembly "WoofWare.Whippet.Fantomas"
*)
[<Test ; Explicit>]
let ``Update API surface`` () =
ApiSurface.writeAssemblyBaseline coreAssembly
[<Test>]
let ``Ensure public API is fully documented`` () =
DocCoverage.assertFullyDocumented coreAssembly

View File

@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<Compile Include="TestSurface.fs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ApiSurface" Version="4.1.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1"/>
<PackageReference Include="NUnit" Version="4.2.2"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WoofWare.Whippet.Fantomas\WoofWare.Whippet.Fantomas.fsproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,47 @@
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
CodeFormatter.FormatASTAsync (parseTree, cfg) |> Async.RunSynchronously |> Some

View File

@@ -0,0 +1,55 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
/// A little DSL for defining the contents of a computation expression.
/// Pass these to `SynExpr.createCompExpr`.
type CompExprBinding =
/// `let! {varName} = {rhs}`
| LetBang of varName : string * rhs : SynExpr
/// `let {varName} = {rhs}`
| Let of varName : string * rhs : SynExpr
/// `use {varName} = {rhs}`
| Use of varName : string * rhs : SynExpr
/// `do {body}`
| Do of body : SynExpr
(*
Potential API!
type internal CompExprBindings =
private
{
/// These are stored in reverse.
Bindings : CompExprBinding list
CompExprName : string
}
[<RequireQualifiedAccess>]
module internal CompExprBindings =
let make (name : string) : CompExprBindings =
{
Bindings = []
CompExprName = name
}
let thenDo (body : SynExpr) (bindings : CompExprBindings) =
{ bindings with
Bindings = (Do body :: bindings.Bindings)
}
let thenLet (varName : string) (value : SynExpr) (bindings : CompExprBindings) =
{ bindings with
Bindings = (Let (varName, value) :: bindings.Bindings)
}
let thenLetBang (varName : string) (value : SynExpr) (bindings : CompExprBindings) =
{ bindings with
Bindings = (LetBang (varName, value) :: bindings.Bindings)
}
let thenUse (varName : string) (value : SynExpr) (bindings : CompExprBindings) =
{ bindings with
Bindings = (LetBang (varName, value) :: bindings.Bindings)
}
*)

View File

@@ -0,0 +1,72 @@
namespace WoofWare.Whippet.Fantomas
open System
open System.Text
open System.Text.RegularExpressions
open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
/// Methods for manipulating the `Ident` type. This type indicates a variable or type identifier in many contexts:
/// whenever the AST needs to name something, it is usually with the `Ident` type.
[<RequireQualifiedAccess>]
module Ident =
/// "Cast" a string into an `Ident`. Probably don't put any weird characters in this; I don't know how well it will
/// work!
let inline create (s : string) = Ident (s, range0)
/// Fantomas bug, perhaps? "type" is not rendered as ``type``, although the ASTs are identical
/// apart from the ranges?
/// Awful hack: here is a function that does this sort of thing.
let createSanitisedParamName (s : string) =
match s with
| "type" -> create "type'"
| "private" -> create "private'"
| _ ->
let result = StringBuilder ()
for i = 0 to s.Length - 1 do
if Char.IsLetter s.[i] then
result.Append s.[i] |> ignore<StringBuilder>
elif Char.IsNumber s.[i] then
if result.Length > 0 then
result.Append s.[i] |> ignore<StringBuilder>
elif s.[i] = '_' || s.[i] = '-' then
result.Append '_' |> ignore<StringBuilder>
else
failwith $"could not convert to ident: %s{s}"
create (result.ToString ())
let private alnum = Regex @"^[a-zA-Z][a-zA-Z0-9]*$"
/// Create an `Ident` for this string, suitable for use as a type name. So, for example, we'll put it into
/// PascalCase if it was in snake_case, we'll remove non-alphanumeric characters, and so on.
let createSanitisedTypeName (s : string) : Ident =
let result = StringBuilder ()
let mutable capitalize = true
for i = 0 to s.Length - 1 do
if Char.IsLetter s.[i] then
if capitalize then
result.Append (Char.ToUpperInvariant s.[i]) |> ignore<StringBuilder>
capitalize <- false
else
result.Append s.[i] |> ignore<StringBuilder>
elif Char.IsNumber s.[i] then
if result.Length > 0 then
result.Append s.[i] |> ignore<StringBuilder>
elif s.[i] = '_' then
capitalize <- true
if result.Length = 0 then
failwith $"String %s{s} was not suitable as a type identifier"
Ident (result.ToString (), range0)
/// Create an Ident which is the same as the input but which has its initial char lowercased if it's a letter.
let lowerFirstLetter (x : Ident) : Ident =
let result = StringBuilder x.idText.Length
result.Append (Char.ToLowerInvariant x.idText.[0]) |> ignore
result.Append x.idText.[1..] |> ignore
create ((result : StringBuilder).ToString ())

View File

@@ -0,0 +1,20 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Xml
open Fantomas.FCS.Text.Range
/// Module for manipulating the PreXmlDoc AST type (which represents XML docstrings).
[<RequireQualifiedAccess>]
module PreXmlDoc =
/// Pass an arbitrary string in here, with newlines if you like, and we'll make sure it appears correctly.
let create (s : string) : PreXmlDoc =
let s = s.Split "\n"
for i = 0 to s.Length - 1 do
s.[i] <- " " + s.[i]
PreXmlDoc.Create (s, range0)
/// This is a light wrapper around Fantomas's `PreXmlDoc`; you should probably use `create` instead.
let create' (s : string seq) : PreXmlDoc =
PreXmlDoc.Create (Array.ofSeq s, range0)

View File

@@ -0,0 +1,33 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
/// Module for manipulating primitive types like `int` or `string`.
[<RequireQualifiedAccess>]
module Primitives =
/// Given e.g. "byte", returns "System.Byte".
let qualifyType (typeName : string) : LongIdent option =
match typeName with
| "float32"
| "single" -> [ "System" ; "Single" ] |> Some
| "float"
| "double" -> [ "System" ; "Double" ] |> Some
| "byte"
| "uint8" -> [ "System" ; "Byte" ] |> Some
| "sbyte"
| "int8" -> [ "System" ; "SByte" ] |> Some
| "int16" -> [ "System" ; "Int16" ] |> Some
| "int"
| "int32" -> [ "System" ; "Int32" ] |> Some
| "int64" -> [ "System" ; "Int64" ] |> Some
| "uint16" -> [ "System" ; "UInt16" ] |> Some
| "uint"
| "uint32" -> [ "System" ; "UInt32" ] |> Some
| "uint64" -> [ "System" ; "UInt64" ] |> Some
| "char" -> [ "System" ; "Char" ] |> Some
| "decimal" -> [ "System" ; "Decimal" ] |> Some
| "string" -> [ "System" ; "String" ] |> Some
| "bool" -> [ "System" ; "Boolean" ] |> Some
| _ -> None
|> Option.map (List.map (fun i -> (Ident (i, range0))))

View File

@@ -0,0 +1,9 @@
# WoofWare.Whippet.Fantomas
Helper methods to access [Fantomas](https://github.com/fsprojects/fantomas) from within a [Whippet](https://github.com/Smaug123/WoofWare.Whippet) plugin (or elsewhere).
This is *not* intended to be the long-term future of Whippet plugins.
I have created it for compatibility with my existing [Myriad](https://github.com/MoiraeSoftware/myriad) plugins ([WoofWare.Myriad](https://github.com/Smaug123/WoofWare.Myriad/)), to help the transition to Whippet.
As such, the version of Fantomas and the F# compiler is currently pinned to a rather old version.
Once I have migrated WoofWare.Myriad to Whippet, I will upgrade Fantomas here, and there will be breaking changes to the API.

View File

@@ -0,0 +1,350 @@
WoofWare.Whippet.Fantomas.Ast inherit obj
WoofWare.Whippet.Fantomas.Ast.parse [static method]: string -> Fantomas.FCS.Syntax.ParsedInput
WoofWare.Whippet.Fantomas.Ast.render [static method]: Fantomas.FCS.Syntax.SynModuleOrNamespace list -> string option
WoofWare.Whippet.Fantomas.CompExprBinding inherit obj - union type with 4 cases
WoofWare.Whippet.Fantomas.CompExprBinding+Do inherit WoofWare.Whippet.Fantomas.CompExprBinding
WoofWare.Whippet.Fantomas.CompExprBinding+Do.body [property]: [read-only] Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.CompExprBinding+Do.get_body [method]: unit -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.CompExprBinding+Let inherit WoofWare.Whippet.Fantomas.CompExprBinding
WoofWare.Whippet.Fantomas.CompExprBinding+Let.get_rhs [method]: unit -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.CompExprBinding+Let.get_varName [method]: unit -> string
WoofWare.Whippet.Fantomas.CompExprBinding+Let.rhs [property]: [read-only] Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.CompExprBinding+Let.varName [property]: [read-only] string
WoofWare.Whippet.Fantomas.CompExprBinding+LetBang inherit WoofWare.Whippet.Fantomas.CompExprBinding
WoofWare.Whippet.Fantomas.CompExprBinding+LetBang.get_rhs [method]: unit -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.CompExprBinding+LetBang.get_varName [method]: unit -> string
WoofWare.Whippet.Fantomas.CompExprBinding+LetBang.rhs [property]: [read-only] Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.CompExprBinding+LetBang.varName [property]: [read-only] string
WoofWare.Whippet.Fantomas.CompExprBinding+Tags inherit obj
WoofWare.Whippet.Fantomas.CompExprBinding+Tags.Do [static field]: int = 3
WoofWare.Whippet.Fantomas.CompExprBinding+Tags.Let [static field]: int = 1
WoofWare.Whippet.Fantomas.CompExprBinding+Tags.LetBang [static field]: int = 0
WoofWare.Whippet.Fantomas.CompExprBinding+Tags.Use [static field]: int = 2
WoofWare.Whippet.Fantomas.CompExprBinding+Use inherit WoofWare.Whippet.Fantomas.CompExprBinding
WoofWare.Whippet.Fantomas.CompExprBinding+Use.get_rhs [method]: unit -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.CompExprBinding+Use.get_varName [method]: unit -> string
WoofWare.Whippet.Fantomas.CompExprBinding+Use.rhs [property]: [read-only] Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.CompExprBinding+Use.varName [property]: [read-only] string
WoofWare.Whippet.Fantomas.CompExprBinding.get_IsDo [method]: unit -> bool
WoofWare.Whippet.Fantomas.CompExprBinding.get_IsLet [method]: unit -> bool
WoofWare.Whippet.Fantomas.CompExprBinding.get_IsLetBang [method]: unit -> bool
WoofWare.Whippet.Fantomas.CompExprBinding.get_IsUse [method]: unit -> bool
WoofWare.Whippet.Fantomas.CompExprBinding.get_Tag [method]: unit -> int
WoofWare.Whippet.Fantomas.CompExprBinding.IsDo [property]: [read-only] bool
WoofWare.Whippet.Fantomas.CompExprBinding.IsLet [property]: [read-only] bool
WoofWare.Whippet.Fantomas.CompExprBinding.IsLetBang [property]: [read-only] bool
WoofWare.Whippet.Fantomas.CompExprBinding.IsUse [property]: [read-only] bool
WoofWare.Whippet.Fantomas.CompExprBinding.NewDo [static method]: Fantomas.FCS.Syntax.SynExpr -> WoofWare.Whippet.Fantomas.CompExprBinding
WoofWare.Whippet.Fantomas.CompExprBinding.NewLet [static method]: (string, Fantomas.FCS.Syntax.SynExpr) -> WoofWare.Whippet.Fantomas.CompExprBinding
WoofWare.Whippet.Fantomas.CompExprBinding.NewLetBang [static method]: (string, Fantomas.FCS.Syntax.SynExpr) -> WoofWare.Whippet.Fantomas.CompExprBinding
WoofWare.Whippet.Fantomas.CompExprBinding.NewUse [static method]: (string, Fantomas.FCS.Syntax.SynExpr) -> WoofWare.Whippet.Fantomas.CompExprBinding
WoofWare.Whippet.Fantomas.CompExprBinding.Tag [property]: [read-only] int
WoofWare.Whippet.Fantomas.Ident inherit obj
WoofWare.Whippet.Fantomas.Ident.create [static method]: string -> Fantomas.FCS.Syntax.Ident
WoofWare.Whippet.Fantomas.Ident.createSanitisedParamName [static method]: string -> Fantomas.FCS.Syntax.Ident
WoofWare.Whippet.Fantomas.Ident.createSanitisedTypeName [static method]: string -> Fantomas.FCS.Syntax.Ident
WoofWare.Whippet.Fantomas.Ident.lowerFirstLetter [static method]: Fantomas.FCS.Syntax.Ident -> Fantomas.FCS.Syntax.Ident
WoofWare.Whippet.Fantomas.PreXmlDoc inherit obj
WoofWare.Whippet.Fantomas.PreXmlDoc.create [static method]: string -> Fantomas.FCS.Xml.PreXmlDoc
WoofWare.Whippet.Fantomas.PreXmlDoc.create' [static method]: string seq -> Fantomas.FCS.Xml.PreXmlDoc
WoofWare.Whippet.Fantomas.Primitives inherit obj
WoofWare.Whippet.Fantomas.Primitives.qualifyType [static method]: string -> Fantomas.FCS.Syntax.Ident list option
WoofWare.Whippet.Fantomas.SynArgInfo inherit obj
WoofWare.Whippet.Fantomas.SynArgInfo.empty [static property]: [read-only] Fantomas.FCS.Syntax.SynArgInfo
WoofWare.Whippet.Fantomas.SynArgInfo.get_empty [static method]: unit -> Fantomas.FCS.Syntax.SynArgInfo
WoofWare.Whippet.Fantomas.SynArgPats inherit obj
WoofWare.Whippet.Fantomas.SynArgPats.create [static method]: Fantomas.FCS.Syntax.SynPat list -> Fantomas.FCS.Syntax.SynArgPats
WoofWare.Whippet.Fantomas.SynArgPats.createNamed [static method]: string list -> Fantomas.FCS.Syntax.SynArgPats
WoofWare.Whippet.Fantomas.SynAttribute inherit obj
WoofWare.Whippet.Fantomas.SynAttribute.autoOpen [static property]: [read-only] Fantomas.FCS.Syntax.SynAttribute
WoofWare.Whippet.Fantomas.SynAttribute.compilationRepresentation [static property]: [read-only] Fantomas.FCS.Syntax.SynAttribute
WoofWare.Whippet.Fantomas.SynAttribute.create [static method]: Fantomas.FCS.Syntax.SynLongIdent -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynAttribute
WoofWare.Whippet.Fantomas.SynAttribute.get_autoOpen [static method]: unit -> Fantomas.FCS.Syntax.SynAttribute
WoofWare.Whippet.Fantomas.SynAttribute.get_compilationRepresentation [static method]: unit -> Fantomas.FCS.Syntax.SynAttribute
WoofWare.Whippet.Fantomas.SynAttribute.get_requireQualifiedAccess [static method]: unit -> Fantomas.FCS.Syntax.SynAttribute
WoofWare.Whippet.Fantomas.SynAttribute.requireQualifiedAccess [static property]: [read-only] Fantomas.FCS.Syntax.SynAttribute
WoofWare.Whippet.Fantomas.SynAttributes inherit obj
WoofWare.Whippet.Fantomas.SynAttributes.ofAttrs [static method]: Fantomas.FCS.Syntax.SynAttribute list -> Fantomas.FCS.Syntax.SynAttributeList list
WoofWare.Whippet.Fantomas.SynBinding inherit obj
WoofWare.Whippet.Fantomas.SynBinding.basic [static method]: Fantomas.FCS.Syntax.Ident list -> Fantomas.FCS.Syntax.SynPat list -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynBinding
WoofWare.Whippet.Fantomas.SynBinding.makeInline [static method]: Fantomas.FCS.Syntax.SynBinding -> Fantomas.FCS.Syntax.SynBinding
WoofWare.Whippet.Fantomas.SynBinding.makeInstanceMember [static method]: Fantomas.FCS.Syntax.SynBinding -> Fantomas.FCS.Syntax.SynBinding
WoofWare.Whippet.Fantomas.SynBinding.makeNotInline [static method]: Fantomas.FCS.Syntax.SynBinding -> Fantomas.FCS.Syntax.SynBinding
WoofWare.Whippet.Fantomas.SynBinding.makeStaticMember [static method]: Fantomas.FCS.Syntax.SynBinding -> Fantomas.FCS.Syntax.SynBinding
WoofWare.Whippet.Fantomas.SynBinding.setInline [static method]: bool -> Fantomas.FCS.Syntax.SynBinding -> Fantomas.FCS.Syntax.SynBinding
WoofWare.Whippet.Fantomas.SynBinding.triviaZero [static method]: bool -> Fantomas.FCS.SyntaxTrivia.SynBindingTrivia
WoofWare.Whippet.Fantomas.SynBinding.withAccessibility [static method]: Fantomas.FCS.Syntax.SynAccess option -> Fantomas.FCS.Syntax.SynBinding -> Fantomas.FCS.Syntax.SynBinding
WoofWare.Whippet.Fantomas.SynBinding.withMutability [static method]: bool -> Fantomas.FCS.Syntax.SynBinding -> Fantomas.FCS.Syntax.SynBinding
WoofWare.Whippet.Fantomas.SynBinding.withRecursion [static method]: bool -> Fantomas.FCS.Syntax.SynBinding -> Fantomas.FCS.Syntax.SynBinding
WoofWare.Whippet.Fantomas.SynBinding.withReturnAnnotation [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynBinding -> Fantomas.FCS.Syntax.SynBinding
WoofWare.Whippet.Fantomas.SynBinding.withXmlDoc [static method]: Fantomas.FCS.Xml.PreXmlDoc -> Fantomas.FCS.Syntax.SynBinding -> Fantomas.FCS.Syntax.SynBinding
WoofWare.Whippet.Fantomas.SynComponentInfo inherit obj
WoofWare.Whippet.Fantomas.SynComponentInfo.addAttributes [static method]: Fantomas.FCS.Syntax.SynAttribute list -> Fantomas.FCS.Syntax.SynComponentInfo -> Fantomas.FCS.Syntax.SynComponentInfo
WoofWare.Whippet.Fantomas.SynComponentInfo.create [static method]: Fantomas.FCS.Syntax.Ident -> Fantomas.FCS.Syntax.SynComponentInfo
WoofWare.Whippet.Fantomas.SynComponentInfo.createLong [static method]: Fantomas.FCS.Syntax.Ident list -> Fantomas.FCS.Syntax.SynComponentInfo
WoofWare.Whippet.Fantomas.SynComponentInfo.setAccessibility [static method]: Fantomas.FCS.Syntax.SynAccess option -> Fantomas.FCS.Syntax.SynComponentInfo -> Fantomas.FCS.Syntax.SynComponentInfo
WoofWare.Whippet.Fantomas.SynComponentInfo.setGenerics [static method]: Fantomas.FCS.Syntax.SynTyparDecls option -> Fantomas.FCS.Syntax.SynComponentInfo -> Fantomas.FCS.Syntax.SynComponentInfo
WoofWare.Whippet.Fantomas.SynComponentInfo.withAccessibility [static method]: Fantomas.FCS.Syntax.SynAccess -> Fantomas.FCS.Syntax.SynComponentInfo -> Fantomas.FCS.Syntax.SynComponentInfo
WoofWare.Whippet.Fantomas.SynComponentInfo.withDocString [static method]: Fantomas.FCS.Xml.PreXmlDoc -> Fantomas.FCS.Syntax.SynComponentInfo -> Fantomas.FCS.Syntax.SynComponentInfo
WoofWare.Whippet.Fantomas.SynComponentInfo.withGenerics [static method]: Fantomas.FCS.Syntax.SynTyparDecl list -> Fantomas.FCS.Syntax.SynComponentInfo -> Fantomas.FCS.Syntax.SynComponentInfo
WoofWare.Whippet.Fantomas.SynConstExt inherit obj
WoofWare.Whippet.Fantomas.SynConstExt.SynConst.Create.Static [static method]: string -> Fantomas.FCS.Syntax.SynConst
WoofWare.Whippet.Fantomas.SynExpr inherit obj
WoofWare.Whippet.Fantomas.SynExpr.applyFunction [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.applyTo [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.arrayIndexRange [static method]: Fantomas.FCS.Syntax.SynExpr option -> Fantomas.FCS.Syntax.SynExpr option -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.arrayLiteral [static method]: Fantomas.FCS.Syntax.SynExpr list -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.assign [static method]: Fantomas.FCS.Syntax.SynLongIdent -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.assignIndex [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.awaitTask [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.booleanAnd [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.booleanOr [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.callGenericMethod [static method]: Fantomas.FCS.Syntax.SynLongIdent -> Fantomas.FCS.Syntax.SynType list -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.callGenericMethod' [static method]: string -> string -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.callMethod [static method]: string -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.callMethodArg [static method]: string -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createCompExpr [static method]: string -> Fantomas.FCS.Syntax.SynExpr -> WoofWare.Whippet.Fantomas.CompExprBinding list -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createDo [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createForEach [static method]: Fantomas.FCS.Syntax.SynPat -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createIdent [static method]: string -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createIdent' [static method]: Fantomas.FCS.Syntax.Ident -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createLambda [static method]: string -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createLet [static method]: Fantomas.FCS.Syntax.SynBinding list -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createLongIdent [static method]: string list -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createLongIdent' [static method]: Fantomas.FCS.Syntax.Ident list -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createLongIdent'' [static method]: Fantomas.FCS.Syntax.SynLongIdent -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createMatch [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynMatchClause list -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createNew [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createNull [static method]: unit -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createThunk [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.createWhile [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.dotGet [static method]: string -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.equals [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.get_reraise [static method]: unit -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.greaterThan [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.greaterThanOrEqual [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.ifThenElse [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.index [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.lessThan [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.lessThanOrEqual [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.listCons [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.listLiteral [static method]: Fantomas.FCS.Syntax.SynExpr list -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.minus [static method]: Fantomas.FCS.Syntax.SynLongIdent -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.minusN [static method]: Fantomas.FCS.Syntax.SynLongIdent -> int -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.paren [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.pipeThroughFunction [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.pipeThroughTryWith [static method]: Fantomas.FCS.Syntax.SynPat -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.plus [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.reraise [static property]: [read-only] Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.sequential [static method]: Fantomas.FCS.Syntax.SynExpr list -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.startAsTask [static method]: Fantomas.FCS.Syntax.Ident -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.stripOptionalParen [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.times [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.toString [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.tuple [static method]: Fantomas.FCS.Syntax.SynExpr list -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.tupleNoParen [static method]: Fantomas.FCS.Syntax.SynExpr list -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.typeAnnotate [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.typeApp [static method]: Fantomas.FCS.Syntax.SynType list -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExpr.upcast' [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExprExtensions inherit obj
WoofWare.Whippet.Fantomas.SynExprExtensions.SynExpr.CreateConst.Static [static method]: bool -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExprExtensions.SynExpr.CreateConst.Static [static method]: char -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExprExtensions.SynExpr.CreateConst.Static [static method]: int -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExprExtensions.SynExpr.CreateConst.Static [static method]: string -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExprExtensions.SynExpr.CreateConst.Static [static method]: unit -> Fantomas.FCS.Syntax.SynExpr
WoofWare.Whippet.Fantomas.SynExprLetOrUseTrivia inherit obj
WoofWare.Whippet.Fantomas.SynExprLetOrUseTrivia.empty [static property]: [read-only] Fantomas.FCS.SyntaxTrivia.SynExprLetOrUseTrivia
WoofWare.Whippet.Fantomas.SynExprLetOrUseTrivia.get_empty [static method]: unit -> Fantomas.FCS.SyntaxTrivia.SynExprLetOrUseTrivia
WoofWare.Whippet.Fantomas.SynField inherit obj
WoofWare.Whippet.Fantomas.SynField.extract [static method]: Fantomas.FCS.Syntax.SynField -> Fantomas.FCS.Syntax.Ident option WoofWare.Whippet.Fantomas.SynFieldData
WoofWare.Whippet.Fantomas.SynField.extractWithIdent [static method]: Fantomas.FCS.Syntax.SynField -> Fantomas.FCS.Syntax.Ident WoofWare.Whippet.Fantomas.SynFieldData
WoofWare.Whippet.Fantomas.SynField.make [static method]: Fantomas.FCS.Syntax.Ident option WoofWare.Whippet.Fantomas.SynFieldData -> Fantomas.FCS.Syntax.SynField
WoofWare.Whippet.Fantomas.SynField.mapIdent [static method]: ('a -> 'b) -> 'a WoofWare.Whippet.Fantomas.SynFieldData -> 'b WoofWare.Whippet.Fantomas.SynFieldData
WoofWare.Whippet.Fantomas.SynField.withDocString [static method]: Fantomas.FCS.Xml.PreXmlDoc -> Fantomas.FCS.Syntax.SynField -> Fantomas.FCS.Syntax.SynField
WoofWare.Whippet.Fantomas.SynFieldData`1 inherit obj
WoofWare.Whippet.Fantomas.SynFieldData`1..ctor [constructor]: (Fantomas.FCS.Syntax.SynAttribute list, 'Ident, Fantomas.FCS.Syntax.SynType)
WoofWare.Whippet.Fantomas.SynFieldData`1.Attrs [property]: [read-only] Fantomas.FCS.Syntax.SynAttribute list
WoofWare.Whippet.Fantomas.SynFieldData`1.get_Attrs [method]: unit -> Fantomas.FCS.Syntax.SynAttribute list
WoofWare.Whippet.Fantomas.SynFieldData`1.get_Ident [method]: unit -> 'Ident
WoofWare.Whippet.Fantomas.SynFieldData`1.get_Type [method]: unit -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynFieldData`1.Ident [property]: [read-only] 'Ident
WoofWare.Whippet.Fantomas.SynFieldData`1.Type [property]: [read-only] Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynIdent inherit obj
WoofWare.Whippet.Fantomas.SynIdent.createI [static method]: Fantomas.FCS.Syntax.Ident -> Fantomas.FCS.Syntax.SynIdent
WoofWare.Whippet.Fantomas.SynIdent.createS [static method]: string -> Fantomas.FCS.Syntax.SynIdent
WoofWare.Whippet.Fantomas.SynLongIdent inherit obj
WoofWare.Whippet.Fantomas.SynLongIdent.booleanAnd [static property]: [read-only] Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.booleanOr [static property]: [read-only] Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.create [static method]: Fantomas.FCS.Syntax.Ident list -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.createI [static method]: Fantomas.FCS.Syntax.Ident -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.createS [static method]: string -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.createS' [static method]: string list -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.eq [static property]: [read-only] Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.geq [static property]: [read-only] Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.get_booleanAnd [static method]: unit -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.get_booleanOr [static method]: unit -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.get_eq [static method]: unit -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.get_geq [static method]: unit -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.get_gt [static method]: unit -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.get_leq [static method]: unit -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.get_lt [static method]: unit -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.get_pipe [static method]: unit -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.get_plus [static method]: unit -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.get_sub [static method]: unit -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.get_times [static method]: unit -> Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.gt [static property]: [read-only] Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.isArray [static method]: Fantomas.FCS.Syntax.SynLongIdent -> bool
WoofWare.Whippet.Fantomas.SynLongIdent.isChoice [static method]: Fantomas.FCS.Syntax.SynLongIdent -> bool
WoofWare.Whippet.Fantomas.SynLongIdent.isDictionary [static method]: Fantomas.FCS.Syntax.SynLongIdent -> bool
WoofWare.Whippet.Fantomas.SynLongIdent.isIDictionary [static method]: Fantomas.FCS.Syntax.SynLongIdent -> bool
WoofWare.Whippet.Fantomas.SynLongIdent.isList [static method]: Fantomas.FCS.Syntax.SynLongIdent -> bool
WoofWare.Whippet.Fantomas.SynLongIdent.isMap [static method]: Fantomas.FCS.Syntax.SynLongIdent -> bool
WoofWare.Whippet.Fantomas.SynLongIdent.isNullable [static method]: Fantomas.FCS.Syntax.SynLongIdent -> bool
WoofWare.Whippet.Fantomas.SynLongIdent.isOption [static method]: Fantomas.FCS.Syntax.SynLongIdent -> bool
WoofWare.Whippet.Fantomas.SynLongIdent.isReadOnlyDictionary [static method]: Fantomas.FCS.Syntax.SynLongIdent -> bool
WoofWare.Whippet.Fantomas.SynLongIdent.isResponse [static method]: Fantomas.FCS.Syntax.SynLongIdent -> bool
WoofWare.Whippet.Fantomas.SynLongIdent.isUnit [static method]: Fantomas.FCS.Syntax.SynLongIdent -> bool
WoofWare.Whippet.Fantomas.SynLongIdent.leq [static property]: [read-only] Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.lt [static property]: [read-only] Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.pipe [static property]: [read-only] Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.plus [static property]: [read-only] Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.sub [static property]: [read-only] Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.times [static property]: [read-only] Fantomas.FCS.Syntax.SynLongIdent
WoofWare.Whippet.Fantomas.SynLongIdent.toString [static method]: Fantomas.FCS.Syntax.SynLongIdent -> string
WoofWare.Whippet.Fantomas.SynMatchClause inherit obj
WoofWare.Whippet.Fantomas.SynMatchClause.create [static method]: Fantomas.FCS.Syntax.SynPat -> Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynMatchClause
WoofWare.Whippet.Fantomas.SynMatchClause.withWhere [static method]: Fantomas.FCS.Syntax.SynExpr -> Fantomas.FCS.Syntax.SynMatchClause -> Fantomas.FCS.Syntax.SynMatchClause
WoofWare.Whippet.Fantomas.SynMemberDefn inherit obj
WoofWare.Whippet.Fantomas.SynMemberDefn.abstractMember [static method]: Fantomas.FCS.Syntax.SynAttribute list -> Fantomas.FCS.Syntax.SynIdent -> Fantomas.FCS.Syntax.SynTyparDecls option -> Fantomas.FCS.Syntax.SynValInfo -> Fantomas.FCS.Xml.PreXmlDoc -> Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynMemberDefn
WoofWare.Whippet.Fantomas.SynMemberDefn.memberImplementation [static method]: Fantomas.FCS.Syntax.SynBinding -> Fantomas.FCS.Syntax.SynMemberDefn
WoofWare.Whippet.Fantomas.SynMemberDefn.staticMember [static method]: Fantomas.FCS.Syntax.SynBinding -> Fantomas.FCS.Syntax.SynMemberDefn
WoofWare.Whippet.Fantomas.SynModuleDecl inherit obj
WoofWare.Whippet.Fantomas.SynModuleDecl.createLet [static method]: Fantomas.FCS.Syntax.SynBinding -> Fantomas.FCS.Syntax.SynModuleDecl
WoofWare.Whippet.Fantomas.SynModuleDecl.createLets [static method]: Fantomas.FCS.Syntax.SynBinding list -> Fantomas.FCS.Syntax.SynModuleDecl
WoofWare.Whippet.Fantomas.SynModuleDecl.createTypes [static method]: Fantomas.FCS.Syntax.SynTypeDefn list -> Fantomas.FCS.Syntax.SynModuleDecl
WoofWare.Whippet.Fantomas.SynModuleDecl.nestedModule [static method]: Fantomas.FCS.Syntax.SynComponentInfo -> Fantomas.FCS.Syntax.SynModuleDecl list -> Fantomas.FCS.Syntax.SynModuleDecl
WoofWare.Whippet.Fantomas.SynModuleDecl.openAny [static method]: Fantomas.FCS.Syntax.SynOpenDeclTarget -> Fantomas.FCS.Syntax.SynModuleDecl
WoofWare.Whippet.Fantomas.SynModuleOrNamespace inherit obj
WoofWare.Whippet.Fantomas.SynModuleOrNamespace.createNamespace [static method]: Fantomas.FCS.Syntax.Ident list -> Fantomas.FCS.Syntax.SynModuleDecl list -> Fantomas.FCS.Syntax.SynModuleOrNamespace
WoofWare.Whippet.Fantomas.SynPat inherit obj
WoofWare.Whippet.Fantomas.SynPat.annotateType [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynPat -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.annotateTypeNoParen [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynPat -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.anon [static property]: [read-only] Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.createConst [static method]: Fantomas.FCS.Syntax.SynConst -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.createNull [static property]: [read-only] Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.emptyArray [static property]: [read-only] Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.emptyList [static property]: [read-only] Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.get_anon [static method]: unit -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.get_createNull [static method]: unit -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.get_emptyArray [static method]: unit -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.get_emptyList [static method]: unit -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.get_unit [static method]: unit -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.identWithArgs [static method]: Fantomas.FCS.Syntax.Ident list -> Fantomas.FCS.Syntax.SynArgPats -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.listCons [static method]: Fantomas.FCS.Syntax.SynPat -> Fantomas.FCS.Syntax.SynPat -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.named [static method]: string -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.namedI [static method]: Fantomas.FCS.Syntax.Ident -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.nameWithArgs [static method]: string -> Fantomas.FCS.Syntax.SynPat list -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.paren [static method]: Fantomas.FCS.Syntax.SynPat -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.tuple [static method]: Fantomas.FCS.Syntax.SynPat list -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.tupleNoParen [static method]: Fantomas.FCS.Syntax.SynPat list -> Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynPat.unit [static property]: [read-only] Fantomas.FCS.Syntax.SynPat
WoofWare.Whippet.Fantomas.SynSimplePat inherit obj
WoofWare.Whippet.Fantomas.SynSimplePat.createId [static method]: Fantomas.FCS.Syntax.Ident -> Fantomas.FCS.Syntax.SynSimplePat
WoofWare.Whippet.Fantomas.SynSimplePats inherit obj
WoofWare.Whippet.Fantomas.SynSimplePats.create [static method]: Fantomas.FCS.Syntax.SynSimplePat list -> Fantomas.FCS.Syntax.SynSimplePats
WoofWare.Whippet.Fantomas.SynType inherit obj
WoofWare.Whippet.Fantomas.SynType.anon [static property]: [read-only] Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.app [static method]: string -> Fantomas.FCS.Syntax.SynType list -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.app' [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType list -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.appPostfix [static method]: string -> Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.appPostfix' [static method]: string list -> Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.array [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.bool [static property]: [read-only] Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.createLongIdent [static method]: Fantomas.FCS.Syntax.Ident list -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.createLongIdent' [static method]: string list -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.funFromDomain [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.get_anon [static method]: unit -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.get_bool [static method]: unit -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.get_int [static method]: unit -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.get_obj [static method]: unit -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.get_string [static method]: unit -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.get_unit [static method]: unit -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.getType [static method]: Fantomas.FCS.Syntax.SynType -> ((Fantomas.FCS.Syntax.SynType * bool) list * Fantomas.FCS.Syntax.SynType)
WoofWare.Whippet.Fantomas.SynType.int [static property]: [read-only] Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.list [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.named [static method]: string -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.obj [static property]: [read-only] Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.option [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.paren [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.primitiveToHumanReadableString [static method]: Fantomas.FCS.Syntax.Ident list -> string
WoofWare.Whippet.Fantomas.SynType.provablyEqual [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType -> bool
WoofWare.Whippet.Fantomas.SynType.signatureParamOfType [static method]: Fantomas.FCS.Syntax.SynAttribute list -> Fantomas.FCS.Syntax.SynType -> bool -> Fantomas.FCS.Syntax.Ident option -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.string [static property]: [read-only] Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.stripOptionalParen [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.task [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.toFun [static method]: Fantomas.FCS.Syntax.SynType list -> Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.toHumanReadableString [static method]: Fantomas.FCS.Syntax.SynType -> string
WoofWare.Whippet.Fantomas.SynType.tupleNoParen [static method]: Fantomas.FCS.Syntax.SynType list -> Fantomas.FCS.Syntax.SynType option
WoofWare.Whippet.Fantomas.SynType.unit [static property]: [read-only] Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynType.var [static method]: Fantomas.FCS.Syntax.SynTypar -> Fantomas.FCS.Syntax.SynType
WoofWare.Whippet.Fantomas.SynTypeDefn inherit obj
WoofWare.Whippet.Fantomas.SynTypeDefn.create [static method]: Fantomas.FCS.Syntax.SynComponentInfo -> Fantomas.FCS.Syntax.SynTypeDefnRepr -> Fantomas.FCS.Syntax.SynTypeDefn
WoofWare.Whippet.Fantomas.SynTypeDefn.getAttribute [static method]: string -> Fantomas.FCS.Syntax.SynTypeDefn -> Fantomas.FCS.Syntax.SynAttribute option
WoofWare.Whippet.Fantomas.SynTypeDefn.getName [static method]: Fantomas.FCS.Syntax.SynTypeDefn -> Fantomas.FCS.Syntax.Ident list
WoofWare.Whippet.Fantomas.SynTypeDefn.hasAttribute [static method]: string -> Fantomas.FCS.Syntax.SynTypeDefn -> bool
WoofWare.Whippet.Fantomas.SynTypeDefn.withMemberDefns [static method]: Fantomas.FCS.Syntax.SynMemberDefn list -> Fantomas.FCS.Syntax.SynTypeDefn -> Fantomas.FCS.Syntax.SynTypeDefn
WoofWare.Whippet.Fantomas.SynTypeDefnRepr inherit obj
WoofWare.Whippet.Fantomas.SynTypeDefnRepr.augmentation [static method]: unit -> Fantomas.FCS.Syntax.SynTypeDefnRepr
WoofWare.Whippet.Fantomas.SynTypeDefnRepr.interfaceType [static method]: Fantomas.FCS.Syntax.SynMemberDefn list -> Fantomas.FCS.Syntax.SynTypeDefnRepr
WoofWare.Whippet.Fantomas.SynTypeDefnRepr.record [static method]: Fantomas.FCS.Syntax.SynField list -> Fantomas.FCS.Syntax.SynTypeDefnRepr
WoofWare.Whippet.Fantomas.SynTypeDefnRepr.recordWithAccess [static method]: Fantomas.FCS.Syntax.SynAccess option -> Fantomas.FCS.Syntax.SynField list -> Fantomas.FCS.Syntax.SynTypeDefnRepr
WoofWare.Whippet.Fantomas.SynTypeDefnRepr.union [static method]: Fantomas.FCS.Syntax.SynUnionCase list -> Fantomas.FCS.Syntax.SynTypeDefnRepr
WoofWare.Whippet.Fantomas.SynTypeDefnRepr.unionWithAccess [static method]: Fantomas.FCS.Syntax.SynAccess option -> Fantomas.FCS.Syntax.SynUnionCase list -> Fantomas.FCS.Syntax.SynTypeDefnRepr
WoofWare.Whippet.Fantomas.SynTypePatterns inherit obj
WoofWare.Whippet.Fantomas.SynTypePatterns.|ArrayType|_| [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType option
WoofWare.Whippet.Fantomas.SynTypePatterns.|BigInt|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|Byte|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|ChoiceType|_| [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType list option
WoofWare.Whippet.Fantomas.SynTypePatterns.|DateOnly|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|DateTimeOffset|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|DateTime|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|DictionaryType|_| [static method]: Fantomas.FCS.Syntax.SynType -> (Fantomas.FCS.Syntax.SynType * Fantomas.FCS.Syntax.SynType) option
WoofWare.Whippet.Fantomas.SynTypePatterns.|DirectoryInfo|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|FileInfo|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|Guid|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|HttpContent|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|HttpResponseMessage|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|IDictionaryType|_| [static method]: Fantomas.FCS.Syntax.SynType -> (Fantomas.FCS.Syntax.SynType * Fantomas.FCS.Syntax.SynType) option
WoofWare.Whippet.Fantomas.SynTypePatterns.|IReadOnlyDictionaryType|_| [static method]: Fantomas.FCS.Syntax.SynType -> (Fantomas.FCS.Syntax.SynType * Fantomas.FCS.Syntax.SynType) option
WoofWare.Whippet.Fantomas.SynTypePatterns.|JsonNode|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|ListType|_| [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType option
WoofWare.Whippet.Fantomas.SynTypePatterns.|MapType|_| [static method]: Fantomas.FCS.Syntax.SynType -> (Fantomas.FCS.Syntax.SynType * Fantomas.FCS.Syntax.SynType) option
WoofWare.Whippet.Fantomas.SynTypePatterns.|Measure|_| [static method]: Fantomas.FCS.Syntax.SynType -> (Fantomas.FCS.Syntax.Ident * Fantomas.FCS.Syntax.Ident list) option
WoofWare.Whippet.Fantomas.SynTypePatterns.|NullableType|_| [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType option
WoofWare.Whippet.Fantomas.SynTypePatterns.|NumberType|_| [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.Ident list option
WoofWare.Whippet.Fantomas.SynTypePatterns.|OptionType|_| [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType option
WoofWare.Whippet.Fantomas.SynTypePatterns.|PrimitiveType|_| [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.Ident list option
WoofWare.Whippet.Fantomas.SynTypePatterns.|RestEaseResponseType|_| [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType option
WoofWare.Whippet.Fantomas.SynTypePatterns.|Stream|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|String|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|Task|_| [static method]: Fantomas.FCS.Syntax.SynType -> Fantomas.FCS.Syntax.SynType option
WoofWare.Whippet.Fantomas.SynTypePatterns.|TimeSpan|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|UnitType|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynTypePatterns.|Uri|_| [static method]: Fantomas.FCS.Syntax.SynType -> unit option
WoofWare.Whippet.Fantomas.SynUnionCase inherit obj
WoofWare.Whippet.Fantomas.SynUnionCase.create [static method]: Fantomas.FCS.Syntax.Ident option WoofWare.Whippet.Fantomas.UnionCase -> Fantomas.FCS.Syntax.SynUnionCase
WoofWare.Whippet.Fantomas.SynValInfo inherit obj
WoofWare.Whippet.Fantomas.SynValInfo.empty [static property]: [read-only] Fantomas.FCS.Syntax.SynValInfo
WoofWare.Whippet.Fantomas.SynValInfo.get_empty [static method]: unit -> Fantomas.FCS.Syntax.SynValInfo
WoofWare.Whippet.Fantomas.UnionCase`1 inherit obj
WoofWare.Whippet.Fantomas.UnionCase`1..ctor [constructor]: (Fantomas.FCS.Syntax.Ident, Fantomas.FCS.Xml.PreXmlDoc option, Fantomas.FCS.Syntax.SynAccess option, Fantomas.FCS.Syntax.SynAttribute list, 'ident WoofWare.Whippet.Fantomas.SynFieldData list)
WoofWare.Whippet.Fantomas.UnionCase`1.Access [property]: [read-only] Fantomas.FCS.Syntax.SynAccess option
WoofWare.Whippet.Fantomas.UnionCase`1.Attributes [property]: [read-only] Fantomas.FCS.Syntax.SynAttribute list
WoofWare.Whippet.Fantomas.UnionCase`1.Fields [property]: [read-only] 'ident WoofWare.Whippet.Fantomas.SynFieldData list
WoofWare.Whippet.Fantomas.UnionCase`1.get_Access [method]: unit -> Fantomas.FCS.Syntax.SynAccess option
WoofWare.Whippet.Fantomas.UnionCase`1.get_Attributes [method]: unit -> Fantomas.FCS.Syntax.SynAttribute list
WoofWare.Whippet.Fantomas.UnionCase`1.get_Fields [method]: unit -> 'ident WoofWare.Whippet.Fantomas.SynFieldData list
WoofWare.Whippet.Fantomas.UnionCase`1.get_Name [method]: unit -> Fantomas.FCS.Syntax.Ident
WoofWare.Whippet.Fantomas.UnionCase`1.get_XmlDoc [method]: unit -> Fantomas.FCS.Xml.PreXmlDoc option
WoofWare.Whippet.Fantomas.UnionCase`1.Name [property]: [read-only] Fantomas.FCS.Syntax.Ident
WoofWare.Whippet.Fantomas.UnionCase`1.XmlDoc [property]: [read-only] Fantomas.FCS.Xml.PreXmlDoc option

View File

@@ -0,0 +1,10 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
/// Module for manipulating the SynArgInfo AST type (which represents a single argument, possibly within a tuple,
/// in a `let` binding).
[<RequireQualifiedAccess>]
module SynArgInfo =
/// No arguments.
let empty = SynArgInfo.SynArgInfo ([], false, None)

View File

@@ -0,0 +1,36 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
/// Methods for manipulating SynArgPats, a type which represents the arguments to a pattern.
[<RequireQualifiedAccess>]
module SynArgPats =
/// Create a SynArgPats which represents the tuple of the given case names.
/// For example, this specifies the `(a, b, c)` in the pattern match arm `| Foo (a, b, c)`.
let createNamed (caseNames : string list) : SynArgPats =
match caseNames.Length with
| 0 -> SynArgPats.Pats []
| 1 ->
SynPat.Named (SynIdent.createS caseNames.[0], false, None, range0)
|> List.singleton
|> SynArgPats.Pats
| len ->
caseNames
|> List.map (fun name -> SynPat.Named (SynIdent.createS name, false, None, range0))
|> fun t -> SynPat.Tuple (false, t, List.replicate (len - 1) range0, range0)
|> fun t -> SynPat.Paren (t, range0)
|> List.singleton
|> SynArgPats.Pats
/// Create a SynArgPats representing the tuple of the given patterns.
/// For example, if the input `SynPat`s are `[Named "a" ; Named "b" ; Named "c"]`, then this would
/// specify the `(a, b, c)` in the pattern match arm `| Foo (a, b, c)`.
let create (pats : SynPat list) : SynArgPats =
match pats.Length with
| 0 -> SynArgPats.Pats []
| 1 -> [ pats.[0] ] |> SynArgPats.Pats
| len ->
SynPat.Paren (SynPat.Tuple (false, pats, List.replicate (len - 1) range0, range0), range0)
|> List.singleton
|> SynArgPats.Pats

View File

@@ -0,0 +1,32 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
/// Methods for manipulating `SynAttribute`, which represents a single attribute such as `[<Foo("bar")>]`.
[<RequireQualifiedAccess>]
module SynAttribute =
/// Create an attribute. If you want no arguments, use `SynExpr.CreateConst ()` as the `arg`.
let inline create (typeName : SynLongIdent) (arg : SynExpr) : SynAttribute =
{
TypeName = typeName
ArgExpr = arg
Target = None
AppliesToGetterAndSetter = false
Range = range0
}
/// The `[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]` attribute, for use on modules.
let compilationRepresentation : SynAttribute =
[ "CompilationRepresentationFlags" ; "ModuleSuffix" ]
|> SynExpr.createLongIdent
|> SynExpr.paren
|> create (SynLongIdent.createS "CompilationRepresentation")
/// The `[<RequireQualifiedAccess>]` attribute.
let requireQualifiedAccess : SynAttribute =
create (SynLongIdent.createS "RequireQualifiedAccess") (SynExpr.CreateConst ())
/// The `[<AutoOpen>]` attribute.
let autoOpen : SynAttribute =
create (SynLongIdent.createS "AutoOpen") (SynExpr.CreateConst ())

View File

@@ -0,0 +1,19 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
/// Module for manipulating the AST `SynAttributes` type. This represents a collection of `[<FooAttribute>]` objects:
/// if you have `[<A>] [<B ; C>] foo` then the SynAttributes contains two elements, `[A]` and `[B ; C]`, each of which
/// is a list of attributes.
[<RequireQualifiedAccess>]
module SynAttributes =
/// Build a SynAttributes of the form `[<A>] [<B>] [<C>]`, i.e. one `[<>]` for each input attribute.
let ofAttrs (attrs : SynAttribute list) : SynAttributes =
attrs
|> List.map (fun a ->
{
Attributes = [ a ]
Range = range0
}
)

View File

@@ -0,0 +1,253 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Xml
open Fantomas.FCS.Text.Range
/// Methods for manipulating `SynBinding`, which represents a `let`-binding or a member definition.
[<RequireQualifiedAccess>]
module SynBinding =
let rec private stripParen (pat : SynPat) =
match pat with
| SynPat.Paren (p, _) -> stripParen p
| _ -> pat
let rec private getName (pat : SynPat) : Ident option =
match stripParen pat with
| SynPat.Named (SynIdent.SynIdent (name, _), _, _, _) -> Some name
| SynPat.Typed (pat, _, _) -> getName pat
| SynPat.LongIdent (SynLongIdent.SynLongIdent (longIdent, _, _), _, _, _, _, _) ->
match longIdent with
| [ x ] -> Some x
| _ -> failwithf "got long ident %O ; can only get the name of a long ident with one component" longIdent
| _ -> None
let private getArgInfo (pat : SynPat) : SynArgInfo list =
// TODO: this only copes with one layer of tupling
match stripParen pat with
| SynPat.Tuple (_, pats, _, _) -> pats |> List.map (fun pat -> SynArgInfo.SynArgInfo ([], false, getName pat))
| pat -> [ SynArgInfo.SynArgInfo (SynAttributes.Empty, false, getName pat) ]
/// The basic `SynBindingTrivia` which means "there's nothing special about this binding".
/// You tell us whether this is a `member Foo = ...` versus a `let foo = ...`.
let triviaZero (isMember : bool) : SynBindingTrivia =
{
SynBindingTrivia.EqualsRange = Some range0
InlineKeyword = None
LeadingKeyword =
if isMember then
SynLeadingKeyword.Member range0
else
SynLeadingKeyword.Let range0
}
/// A simple binding:
/// `let {name} {args} = {body}`
///
/// If you want this to become an instance member, you need to make sure the `this.` is present as a component
/// of the `name`.
let basic (name : LongIdent) (args : SynPat list) (body : SynExpr) : SynBinding =
let valInfo : SynValInfo =
args
|> List.map getArgInfo
|> fun x -> SynValInfo.SynValInfo (x, SynArgInfo.SynArgInfo ([], false, None))
SynBinding.SynBinding (
None,
SynBindingKind.Normal,
false,
false,
[],
PreXmlDoc.Empty,
SynValData.SynValData (None, valInfo, None),
SynPat.identWithArgs name (SynArgPats.Pats args),
None,
body,
range0,
DebugPointAtBinding.Yes range0,
triviaZero false
)
/// Set the mutability of this binding: `let mutable i = ...` (or remove the word `mutable`, if `mut` is false).
let withMutability (mut : bool) (binding : SynBinding) : SynBinding =
match binding with
| SynBinding (pat, kind, inl, _, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia) ->
SynBinding (pat, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia)
/// Set the `rec` keyword on this binding: `let rec foo = ...` (or remove the word `rec`, if `isRec` is false).
let withRecursion (isRec : bool) (binding : SynBinding) : SynBinding =
match binding with
| SynBinding (pat, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia) ->
let trivia =
{ trivia with
LeadingKeyword =
match trivia.LeadingKeyword with
| SynLeadingKeyword.Let _ ->
if isRec then
SynLeadingKeyword.LetRec (range0, range0)
else
trivia.LeadingKeyword
| SynLeadingKeyword.LetRec _ ->
if isRec then
trivia.LeadingKeyword
else
trivia.LeadingKeyword
| existing ->
failwith
$"WoofWare.Whippet.Fantomas doesn't yet let you adjust the recursion modifier on a binding with modifier %O{existing}"
}
SynBinding (pat, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia)
/// Override the accessibility modifier on this binding, or clear it: `let private foo = ...`
let withAccessibility (acc : SynAccess option) (binding : SynBinding) : SynBinding =
match binding with
| SynBinding (_, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia) ->
let headPat =
match headPat with
| SynPat.LongIdent (ident, extra, options, argPats, _, range) ->
SynPat.LongIdent (ident, extra, options, argPats, acc, range)
| _ -> failwithf "unrecognised head pattern: %O" headPat
SynBinding (acc, kind, inl, mut, attrs, xml, valData, headPat, returnInfo, expr, range, debugPoint, trivia)
/// Set the XML docstring on this binding: `/// blah\nlet foo = ...`
let withXmlDoc (doc : PreXmlDoc) (binding : SynBinding) : SynBinding =
match binding with
| SynBinding (acc, kind, inl, mut, attrs, _, valData, headPat, returnInfo, expr, range, debugPoint, trivia) ->
SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, returnInfo, expr, range, debugPoint, trivia)
/// Set the return type annotation: `let foo : int = ...`
let withReturnAnnotation (ty : SynType) (binding : SynBinding) : SynBinding =
match binding with
| SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, _, expr, range, debugPoint, trivia) ->
let retInfo =
SynBindingReturnInfo.SynBindingReturnInfo (
ty,
range0,
[],
{
ColonRange = Some range0
}
)
SynBinding (
acc,
kind,
inl,
mut,
attrs,
doc,
valData,
headPat,
Some retInfo,
expr,
range,
debugPoint,
trivia
)
/// Make the definition an `inline` definition: `let inline foo = ...`
let inline makeInline (binding : SynBinding) : SynBinding =
match binding with
| SynBinding (acc, kind, _, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) ->
SynBinding (
acc,
kind,
true,
mut,
attrs,
doc,
valData,
headPat,
ret,
expr,
range,
debugPoint,
{ trivia with
InlineKeyword = Some range0
}
)
/// Make the definition not be an `inline` definition: that is, turn `let inline foo = ...` into `let foo = ...`.
/// This is a no-op if the binding is already not inline.
let inline makeNotInline (binding : SynBinding) : SynBinding =
match binding with
| SynBinding (acc, kind, _, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) ->
SynBinding (
acc,
kind,
false,
mut,
attrs,
doc,
valData,
headPat,
ret,
expr,
range,
debugPoint,
{ trivia with
InlineKeyword = None
}
)
/// Set or remove the `inline` keyword on the given binding.
let inline setInline (isInline : bool) (binding : SynBinding) : SynBinding =
if isInline then
makeInline binding
else
makeNotInline binding
/// Convert this member definition to a `static` member.
let makeStaticMember (binding : SynBinding) : SynBinding =
let memberFlags =
{
SynMemberFlags.IsInstance = false
SynMemberFlags.IsDispatchSlot = false
SynMemberFlags.IsOverrideOrExplicitImpl = false
SynMemberFlags.IsFinal = false
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
SynMemberFlags.MemberKind = SynMemberKind.Member
}
match binding with
| SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) ->
let valData =
match valData with
| SynValData.SynValData (_, valInfo, _) -> SynValData.SynValData (Some memberFlags, valInfo, None)
let trivia =
{ trivia with
LeadingKeyword = SynLeadingKeyword.StaticMember (range0, range0)
}
SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia)
/// Convert this member definition to an instance member, `member this.Foo = ...`.
/// You need to make sure the `this` is present in the name of the binding.
let makeInstanceMember (binding : SynBinding) : SynBinding =
let memberFlags =
{
SynMemberFlags.IsInstance = true
SynMemberFlags.IsDispatchSlot = false
SynMemberFlags.IsOverrideOrExplicitImpl = true
SynMemberFlags.IsFinal = false
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
SynMemberFlags.MemberKind = SynMemberKind.Member
}
match binding with
| SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia) ->
let valData =
match valData with
| SynValData.SynValData (_, valInfo, _) -> SynValData.SynValData (Some memberFlags, valInfo, None)
let trivia =
{ trivia with
LeadingKeyword = SynLeadingKeyword.Member range0
}
SynBinding (acc, kind, inl, mut, attrs, doc, valData, headPat, ret, expr, range, debugPoint, trivia)

View File

@@ -0,0 +1,63 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.Xml
open Fantomas.FCS.Text.Range
/// Methods for manipulating `SynComponentInfo`, which is like the "front matter" for a type definition.
/// It specifies type parameters, docstrings, name, etc.
[<RequireQualifiedAccess>]
module SynComponentInfo =
/// Create the most basic possible SynComponentInfo, specifying only its name.
let inline createLong (name : LongIdent) =
SynComponentInfo.SynComponentInfo ([], None, [], name, PreXmlDoc.Empty, false, None, range0)
/// Create the most basic possible SynComponentInfo, specifying only its name.
/// (Don't put full stops in this `name`; use `createLong` if you want to qualify the name further.)
let inline create (name : Ident) = createLong [ name ]
/// Add a docstring to this type definition front matter.
let inline withDocString (doc : PreXmlDoc) (i : SynComponentInfo) : SynComponentInfo =
match i with
| SynComponentInfo.SynComponentInfo (attrs, typars, constraints, name, _, postfix, access, range) ->
SynComponentInfo (attrs, typars, constraints, name, doc, postfix, access, range)
/// Specify that this type definition has generic type parameters.
/// This is the fully general method; you might find it more ergonomic to use the more specialised `withGenerics`
/// instead.
let inline setGenerics (typars : SynTyparDecls option) (i : SynComponentInfo) : SynComponentInfo =
match i with
| SynComponentInfo.SynComponentInfo (attrs, _, constraints, name, doc, postfix, access, range) ->
SynComponentInfo (attrs, typars, constraints, name, doc, postfix, access, range)
/// Specify that this type definition has these generic type parameters.
let inline withGenerics (typars : SynTyparDecl list) (i : SynComponentInfo) : SynComponentInfo =
let inner =
if typars.IsEmpty then
None
else
Some (SynTyparDecls.PostfixList (typars, [], range0))
setGenerics inner i
/// Specify that this type definition has this accessibility modifier (or no accessibility modifier).
let inline setAccessibility (acc : SynAccess option) (i : SynComponentInfo) : SynComponentInfo =
match i with
| SynComponentInfo.SynComponentInfo (attrs, typars, constraints, name, doc, postfix, _, range) ->
SynComponentInfo.SynComponentInfo (attrs, typars, constraints, name, doc, postfix, acc, range)
/// Specify that this type definition has this accessibility modifier.
let inline withAccessibility (acc : SynAccess) (i : SynComponentInfo) : SynComponentInfo =
setAccessibility (Some acc) i
/// Prepend these attributes to the type definition: `[<Foo>] type Blah = ...`.
let inline addAttributes (attrs : SynAttribute list) (i : SynComponentInfo) : SynComponentInfo =
match i with
| SynComponentInfo.SynComponentInfo (oldAttrs, typars, constraints, name, doc, postfix, acc, range) ->
let attrs =
{
SynAttributeList.Attributes = attrs
SynAttributeList.Range = range0
}
SynComponentInfo.SynComponentInfo ((attrs :: oldAttrs), typars, constraints, name, doc, postfix, acc, range)

View File

@@ -0,0 +1,12 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
/// Extension methods for creating SynConst AST objects (which represent literal constants such as `3` or `"hi"`).
[<AutoOpen>]
module SynConstExt =
type SynConst with
/// Create the constant string with this value.
static member Create (s : string) : SynConst =
SynConst.String (s, SynStringKind.Regular, range0)

View File

@@ -0,0 +1,415 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Text.Range
/// Extension methods to hold `SynExpr.CreateConst`.
[<AutoOpen>]
module SynExprExtensions =
type SynExpr with
/// Create the constant expression which is the given string.
/// For example, create the F# expression `"hi"` by calling `SynExpr.CreateConst "hi"`.
static member CreateConst (s : string) : SynExpr =
SynExpr.Const (SynConst.Create s, range0)
/// Create the constant unit expression.
static member CreateConst () : SynExpr = SynExpr.Const (SynConst.Unit, range0)
/// Create the constant expression which is the given bool.
/// For example, create the F# expression `false` by calling `SynExpr.CreateConst false`.
static member CreateConst (b : bool) : SynExpr = SynExpr.Const (SynConst.Bool b, range0)
/// Create the constant expression which is the given char.
/// For example, create the F# expression `'c'` by calling `SynExpr.CreateConst 'c'`.
///
/// There appears to be a bug in Fantomas in at least one version, causing incorrect formatting when this is
/// done naively; so this function instead gives you `(char {appropriate-integer})`.
static member CreateConst (c : char) : SynExpr =
// apparent Fantomas bug: `IndexOf '?'` gets formatted as `IndexOf ?` which is clearly wrong
SynExpr.App (
ExprAtomicFlag.NonAtomic,
false,
SynExpr.Ident (Ident.create "char"),
SynExpr.CreateConst (int c),
range0
)
|> fun e -> SynExpr.Paren (e, range0, Some range0, range0)
/// Create the constant expression which is the given int.
/// For example, create the F# expression `3` by calling `SynExpr.CreateConst 3`.
static member CreateConst (i : int32) : SynExpr =
SynExpr.Const (SynConst.Int32 i, range0)
/// Methods for manipulating `SynExpr`, which represents an F# expression.
[<RequireQualifiedAccess>]
module SynExpr =
/// {f} {x}
let applyFunction (f : SynExpr) (x : SynExpr) : SynExpr =
SynExpr.App (ExprAtomicFlag.NonAtomic, false, f, x, range0)
/// {f} {x}
let inline applyTo (x : SynExpr) (f : SynExpr) : SynExpr = applyFunction f x
let inline private createAppInfix (f : SynExpr) (x : SynExpr) =
SynExpr.App (ExprAtomicFlag.NonAtomic, true, f, x, range0)
/// An expression which is just "this name".
/// For example, `Foo.Blah`.
let inline createLongIdent'' (ident : SynLongIdent) : SynExpr =
SynExpr.LongIdent (false, ident, None, range0)
/// An expression which is just "this name".
/// For example, `Foo.Blah`.
let inline createLongIdent' (ident : Ident list) : SynExpr =
createLongIdent'' (SynLongIdent.create ident)
/// An expression which is just "this name".
/// For example, `Foo.Blah`.
let inline createLongIdent (ident : string list) : SynExpr =
createLongIdent' (ident |> List.map Ident.create)
/// {expr} |> {func}
let pipeThroughFunction (func : SynExpr) (expr : SynExpr) : SynExpr =
createAppInfix (createLongIdent'' SynLongIdent.pipe) expr |> applyTo func
/// if {cond} then {trueBranch} else {falseBranch}
/// Note that this function puts the trueBranch last, for pipelining convenience:
/// we assume that the `else` branch is more like an error case and is less interesting.
let ifThenElse (cond : SynExpr) (falseBranch : SynExpr) (trueBranch : SynExpr) : SynExpr =
SynExpr.IfThenElse (
cond,
trueBranch,
Some falseBranch,
DebugPointAtBinding.Yes range0,
false,
range0,
{
IfKeyword = range0
IsElif = false
ThenKeyword = range0
ElseKeyword = Some range0
IfToThenRange = range0
}
)
/// try {body} with | {exc} as exc -> {handler}
let pipeThroughTryWith (exc : SynPat) (handler : SynExpr) (body : SynExpr) : SynExpr =
let clause =
SynMatchClause.create (SynPat.As (exc, SynPat.named "exc", range0)) handler
SynExpr.TryWith (
body,
[ clause ],
range0,
DebugPointAtTry.Yes range0,
DebugPointAtWith.Yes range0,
{
TryKeyword = range0
TryToWithRange = range0
WithKeyword = range0
WithToEndRange = range0
}
)
/// {a} = {b}
let equals (a : SynExpr) (b : SynExpr) =
createAppInfix (createLongIdent'' SynLongIdent.eq) a |> applyTo b
/// {a} && {b}
let booleanAnd (a : SynExpr) (b : SynExpr) =
createAppInfix (createLongIdent'' SynLongIdent.booleanAnd) a |> applyTo b
/// {a} || {b}
let booleanOr (a : SynExpr) (b : SynExpr) =
createAppInfix (createLongIdent'' SynLongIdent.booleanOr) a |> applyTo b
/// {a} + {b}
let plus (a : SynExpr) (b : SynExpr) =
createAppInfix (createLongIdent'' SynLongIdent.plus) a |> applyTo b
/// {a} * {b}
let times (a : SynExpr) (b : SynExpr) =
createAppInfix (createLongIdent'' SynLongIdent.times) a |> applyTo b
/// Strip all outer parentheses from the expression: `((e))` -> `e`.
let rec stripOptionalParen (expr : SynExpr) : SynExpr =
match expr with
| SynExpr.Paren (expr, _, _, _) -> stripOptionalParen expr
| expr -> expr
/// {obj}.{field}
let dotGet (field : string) (obj : SynExpr) : SynExpr =
SynExpr.DotGet (
obj,
range0,
SynLongIdent.SynLongIdent (id = [ Ident.create field ], dotRanges = [], trivia = [ None ]),
range0
)
/// {obj}.{meth} {arg}
let callMethodArg (meth : string) (arg : SynExpr) (obj : SynExpr) : SynExpr = dotGet meth obj |> applyTo arg
/// {obj}.{meth}()
let callMethod (meth : string) (obj : SynExpr) : SynExpr =
callMethodArg meth (SynExpr.CreateConst ()) obj
/// `{operand}<{types}>`
let typeApp (types : SynType list) (operand : SynExpr) =
SynExpr.TypeApp (operand, range0, types, List.replicate (types.Length - 1) range0, Some range0, range0, range0)
/// {obj}.{meth}<types,...>()
let callGenericMethod (meth : SynLongIdent) (types : SynType list) (obj : SynExpr) : SynExpr =
SynExpr.DotGet (obj, range0, meth, range0)
|> typeApp types
|> applyTo (SynExpr.CreateConst ())
/// {obj}.{meth}<ty>()
let callGenericMethod' (meth : string) (ty : string) (obj : SynExpr) : SynExpr =
callGenericMethod (SynLongIdent.createS meth) [ SynType.createLongIdent' [ ty ] ] obj
/// {obj}.[{property}]
let inline index (property : SynExpr) (obj : SynExpr) : SynExpr =
SynExpr.DotIndexedGet (obj, property, range0, range0)
/// `{arr}.[{start} .. {end}]`
///
/// You can set either the start or end to None to omit them from the range.
let inline arrayIndexRange (start : SynExpr option) (endRange : SynExpr option) (arr : SynExpr) : SynExpr =
SynExpr.DotIndexedGet (
arr,
(SynExpr.IndexRange (start, range0, endRange, range0, range0, range0)),
range0,
range0
)
/// Wraps the expression in parentheses: `({e})`
let inline paren (e : SynExpr) : SynExpr =
SynExpr.Paren (e, range0, Some range0, range0)
/// (fun {varName} -> {body})
let createLambda (varName : string) (body : SynExpr) : SynExpr =
let parsedDataPat = [ SynPat.named varName ]
SynExpr.Lambda (
false,
false,
SynSimplePats.create [ SynSimplePat.createId (Ident.create varName) ],
body,
Some (parsedDataPat, body),
range0,
{
ArrowRange = Some range0
}
)
|> paren
/// `(fun () -> {body})`
let createThunk (body : SynExpr) : SynExpr =
SynExpr.Lambda (
false,
false,
SynSimplePats.create [],
body,
Some ([ SynPat.unit ], body),
range0,
{
ArrowRange = Some range0
}
)
|> paren
/// Just the plain expression `s`, referring to a variable.
let inline createIdent (s : string) : SynExpr = SynExpr.Ident (Ident (s, range0))
/// Just the plain expression `x`, referring to a variable.
let inline createIdent' (i : Ident) : SynExpr = SynExpr.Ident i
/// `{arg1}, {arg2}, ...`
let tupleNoParen (args : SynExpr list) : SynExpr =
SynExpr.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
/// `({arg1}, {arg2}, ...)`
let inline tuple (args : SynExpr list) = args |> tupleNoParen |> paren
/// {body} |> fun a -> Async.StartAsTask (a, ?cancellationToken=ct)
let startAsTask (ct : Ident) (body : SynExpr) =
let lambda =
[
createIdent "a"
equals
(SynExpr.LongIdent (true, SynLongIdent.createS "cancellationToken", None, range0))
(createIdent' ct)
]
|> tuple
|> applyFunction (createLongIdent [ "Async" ; "StartAsTask" ])
|> createLambda "a"
pipeThroughFunction lambda body
/// `for {pat} in {enumExpr} do {body}`
let inline createForEach (pat : SynPat) (enumExpr : SynExpr) (body : SynExpr) : SynExpr =
SynExpr.ForEach (
DebugPointAtFor.No,
DebugPointAtInOrTo.No,
SeqExprOnly.SeqExprOnly false,
true,
pat,
enumExpr,
body,
range0
)
/// `let {binding1 = binding1}; let {binding2 = binding2}; {body}
let inline createLet (bindings : SynBinding list) (body : SynExpr) : SynExpr =
SynExpr.LetOrUse (false, false, bindings, body, range0, SynExprLetOrUseTrivia.empty)
/// `do {body}`
let inline createDo (body : SynExpr) : SynExpr = SynExpr.Do (body, range0)
/// `match {matchOn} with {cases}`
let inline createMatch (matchOn : SynExpr) (cases : SynMatchClause list) : SynExpr =
SynExpr.Match (
DebugPointAtBinding.Yes range0,
matchOn,
cases,
range0,
{
MatchKeyword = range0
WithKeyword = range0
}
)
/// `{expr} : {ty}`
let typeAnnotate (ty : SynType) (expr : SynExpr) : SynExpr = SynExpr.Typed (expr, ty, range0)
/// `new {ty} ({args})`
let inline createNew (ty : SynType) (args : SynExpr) : SynExpr =
SynExpr.New (false, ty, paren args, range0)
/// `while {cond} do {body}`
let inline createWhile (cond : SynExpr) (body : SynExpr) : SynExpr =
SynExpr.While (DebugPointAtWhile.Yes range0, cond, body, range0)
/// `null`
let inline createNull () : SynExpr = SynExpr.Null range0
/// `reraise ()`
let reraise : SynExpr = createIdent "reraise" |> applyTo (SynExpr.CreateConst ())
/// Semantically this is:
/// {elt1} ; {elt2} ; ...
/// except we probably end up formatting without the semicolons.
let sequential (exprs : SynExpr list) : SynExpr =
exprs
|> List.reduce (fun a b -> SynExpr.Sequential (DebugPointAtSequential.SuppressNeither, false, a, b, range0))
/// [ {elt1} ; {elt2} ; ... ]
let listLiteral (elts : SynExpr list) : SynExpr =
SynExpr.ArrayOrListComputed (false, sequential elts, range0)
/// [| {elt1} ; {elt2} ; ... |]
let arrayLiteral (elts : SynExpr list) : SynExpr =
SynExpr.ArrayOrListComputed (true, sequential elts, range0)
/// {compExpr} { {lets} ; return {ret} }
let createCompExpr (compExpr : string) (retBody : SynExpr) (lets : CompExprBinding list) : SynExpr =
let retStatement = SynExpr.YieldOrReturn ((false, true), retBody, range0)
let contents : SynExpr =
(retStatement, List.rev lets)
||> List.fold (fun state binding ->
match binding with
| LetBang (lhs, rhs) ->
SynExpr.LetOrUseBang (
DebugPointAtBinding.Yes range0,
false,
true,
SynPat.named lhs,
rhs,
[],
state,
range0,
{
EqualsRange = Some range0
}
)
| Let (lhs, rhs) -> createLet [ SynBinding.basic [ Ident.create lhs ] [] rhs ] state
| Use (lhs, rhs) ->
SynExpr.LetOrUse (
false,
true,
[ SynBinding.basic [ Ident.create lhs ] [] rhs ],
state,
range0,
{
SynExprLetOrUseTrivia.InKeyword = None
}
)
| Do body -> sequential [ SynExpr.Do (body, range0) ; state ]
)
applyFunction (createIdent compExpr) (SynExpr.ComputationExpr (false, contents, range0))
/// {expr} |> Async.AwaitTask
let awaitTask (expr : SynExpr) : SynExpr =
expr |> pipeThroughFunction (createLongIdent [ "Async" ; "AwaitTask" ])
/// {ident}.ToString ()
/// with special casing for some types like DateTime
let toString (ty : SynType) (ident : SynExpr) =
match ty with
| DateOnly -> ident |> callMethodArg "ToString" (SynExpr.CreateConst "yyyy-MM-dd")
| DateTime -> ident |> callMethodArg "ToString" (SynExpr.CreateConst "yyyy-MM-ddTHH:mm:ss")
| _ -> callMethod "ToString" ident
/// {e} :> {ty}
let upcast' (ty : SynType) (e : SynExpr) = SynExpr.Upcast (e, ty, range0)
/// {ident} - {rhs}
let minus (ident : SynLongIdent) (rhs : SynExpr) : SynExpr =
createAppInfix (createLongIdent'' SynLongIdent.sub) (createLongIdent'' ident)
|> applyTo rhs
/// {ident} - {n}
let minusN (ident : SynLongIdent) (n : int) : SynExpr = minus ident (SynExpr.CreateConst n)
/// {y} > {x}
let greaterThan (x : SynExpr) (y : SynExpr) : SynExpr =
createAppInfix (createLongIdent'' SynLongIdent.gt) y |> applyTo x
/// {y} < {x}
let lessThan (x : SynExpr) (y : SynExpr) : SynExpr =
createAppInfix (createLongIdent'' SynLongIdent.lt) y |> applyTo x
/// {y} >= {x}
let greaterThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr =
createAppInfix (createLongIdent'' SynLongIdent.geq) y |> applyTo x
/// {y} <= {x}
let lessThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr =
createAppInfix (createLongIdent'' SynLongIdent.leq) y |> applyTo x
/// {x} :: {y}
let listCons (x : SynExpr) (y : SynExpr) : SynExpr =
createAppInfix
(SynExpr.LongIdent (
false,
SynLongIdent.SynLongIdent (
[ Ident.create "op_ColonColon" ],
[],
[ Some (IdentTrivia.OriginalNotation "::") ]
),
None,
range0
))
(tupleNoParen [ x ; y ])
|> paren
/// `{lhs} <- {rhs}`
let assign (lhs : SynLongIdent) (rhs : SynExpr) : SynExpr = SynExpr.LongIdentSet (lhs, rhs, range0)
/// `{lhs}.[{index}] <- {rhs}`
let assignIndex (lhs : SynExpr) (index : SynExpr) (rhs : SynExpr) : SynExpr =
SynExpr.DotIndexedSet (lhs, index, rhs, range0, range0, range0)

View File

@@ -0,0 +1,13 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.SyntaxTrivia
/// Methods for manipulating SynExprLetOrUseTrivia, which gives non-semantically-relevant information about the
/// formatting of a `let` or `use` binding.
[<RequireQualifiedAccess>]
module SynExprLetOrUseTrivia =
/// Specify that this is just a plain `let` or `use` binding. You basically always want this.
let empty : SynExprLetOrUseTrivia =
{
InKeyword = None
}

View File

@@ -0,0 +1,80 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Text.Range
open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Xml
/// The data needed to reconstitute a single piece of data within a union field, or a single record field.
/// This is generic on whether the field is identified. For example, in `type Foo = Blah of int`, the `int`
/// field is not identified; whereas in `type Foo = Blah of baz : int`, it is identified.
type SynFieldData<'Ident> =
{
/// Attributes on this field. I think you can only get these if this is a *record* field.
Attrs : SynAttribute list
/// The identifier of this field (see docstring for SynFieldData).
Ident : 'Ident
/// The type of the data contained in this field. For example, `type Foo = { Blah : int }`
/// has this being `int`.
Type : SynType
}
/// Methods for manipulating `SynField`, which represents a field of a record or union.
[<RequireQualifiedAccess>]
module SynField =
/// Get the useful information out of a SynField.
let extract (SynField (attrs, _, id, fieldType, _, _, _, _, _)) : SynFieldData<Ident option> =
{
Attrs = attrs |> List.collect (fun l -> l.Attributes)
Ident = id
Type = fieldType
}
/// Functorial `map`.
let mapIdent<'a, 'b> (f : 'a -> 'b) (x : SynFieldData<'a>) : SynFieldData<'b> =
let ident = f x.Ident
{
Attrs = x.Attrs
Ident = ident
Type = x.Type
}
/// Convert a `SynField` into our structured `SynFieldData` type. Throws if the field has no identifier.
let extractWithIdent (f : SynField) : SynFieldData<Ident> =
f
|> extract
|> mapIdent (fun ident ->
match ident with
| None -> failwith "expected field identifier to have a value, but it did not"
| Some i -> i
)
/// Convert our structured `SynFieldData` type into an AST `SynField`.
let make (data : SynFieldData<Ident option>) : SynField =
let attrs : SynAttributeList list =
data.Attrs
|> List.map (fun l ->
{
Attributes = [ l ]
Range = range0
}
)
SynField.SynField (
attrs,
false,
data.Ident,
data.Type,
false,
PreXmlDoc.Empty,
None,
range0,
SynFieldTrivia.Zero
)
/// Set the docstring of this `SynField`.
let withDocString (doc : PreXmlDoc) (f : SynField) : SynField =
match f with
| SynField (attributes, isStatic, idOpt, fieldType, isMutable, _, accessibility, range, trivia) ->
SynField (attributes, isStatic, idOpt, fieldType, isMutable, doc, accessibility, range, trivia)

View File

@@ -0,0 +1,14 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
/// Methods for manipulating the SynIdent AST type. This is basically an Ident, but specifically one which is appearing
/// in the AST at some position.
[<RequireQualifiedAccess>]
module SynIdent =
/// Create a SynIdent from an Ident.
let inline createI (i : Ident) : SynIdent = SynIdent.SynIdent (i, None)
/// Create a SynIdent from a string (which we'll convert into an Ident for you en route).
let inline createS (i : string) : SynIdent =
SynIdent.SynIdent (Ident.create i, None)

View File

@@ -0,0 +1,175 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Text.Range
open Fantomas.FCS.Syntax
/// Methods for manipulating the SynLongIdent type. This is a LongIdent, but specifically one which is appearing in the
/// AST somewhere.
[<RequireQualifiedAccess>]
module SynLongIdent =
/// The ">=" identifier.
let geq =
SynLongIdent.SynLongIdent (
[ Ident.create "op_GreaterThanOrEqual" ],
[],
[ Some (IdentTrivia.OriginalNotation ">=") ]
)
/// The "<=" identifier.
let leq =
SynLongIdent.SynLongIdent (
[ Ident.create "op_LessThanOrEqual" ],
[],
[ Some (IdentTrivia.OriginalNotation "<=") ]
)
/// The ">" identifier.
let gt =
SynLongIdent.SynLongIdent ([ Ident.create "op_GreaterThan" ], [], [ Some (IdentTrivia.OriginalNotation ">") ])
/// The "<" identifier.
let lt =
SynLongIdent.SynLongIdent ([ Ident.create "op_LessThan" ], [], [ Some (IdentTrivia.OriginalNotation "<") ])
/// The "-" identifier.
let sub =
SynLongIdent.SynLongIdent ([ Ident.create "op_Subtraction" ], [], [ Some (IdentTrivia.OriginalNotation "-") ])
/// The "=" identifier.
let eq =
SynLongIdent.SynLongIdent ([ Ident.create "op_Equality" ], [], [ Some (IdentTrivia.OriginalNotation "=") ])
/// The "&&" identifier.
let booleanAnd =
SynLongIdent.SynLongIdent ([ Ident.create "op_BooleanAnd" ], [], [ Some (IdentTrivia.OriginalNotation "&&") ])
/// The "||" identifier.
let booleanOr =
SynLongIdent.SynLongIdent ([ Ident.create "op_BooleanOr" ], [], [ Some (IdentTrivia.OriginalNotation "||") ])
/// The "+" identifier.
let plus =
SynLongIdent.SynLongIdent ([ Ident.create "op_Addition" ], [], [ Some (IdentTrivia.OriginalNotation "+") ])
/// The "*" identifier.
let times =
SynLongIdent.SynLongIdent ([ Ident.create "op_Multiply" ], [], [ Some (IdentTrivia.OriginalNotation "*") ])
/// The "|>" identifier.
let pipe =
SynLongIdent.SynLongIdent ([ Ident.create "op_PipeRight" ], [], [ Some (IdentTrivia.OriginalNotation "|>") ])
/// Convert this SynLongIdent into a human-readable string for display.
/// This is not quite round-trippable, but it should be round-trippable if your identifiers are not pathological
/// (e.g. you should not have a full stop in your identifiers; that's the job of LongIdent, not Ident).
let toString (sli : SynLongIdent) : string =
sli.LongIdent |> List.map _.idText |> String.concat "."
/// Build a SynLongIdent from a LongIdent (by attaching dummy location information to it).
let create (ident : LongIdent) : SynLongIdent =
let commas =
match ident with
| [] -> []
| _ :: commas -> commas |> List.map (fun _ -> range0)
SynLongIdent.SynLongIdent (ident, commas, List.replicate ident.Length None)
/// Build a SynLongIdent from an Ident. Please don't put full stops in the argument, I don't know what will happen;
/// use `create` if you have multiple components.
let inline createI (i : Ident) : SynLongIdent = create [ i ]
/// Build a SynLongIdent from a string which is expected to be "basically an Ident" - no full stops, for example.
/// Use `createS'` if you have multiple components.
let inline createS (s : string) : SynLongIdent = createI (Ident (s, range0))
/// Build a SynLongIdent from its components.
let inline createS' (s : string list) : SynLongIdent =
create (s |> List.map (fun i -> Ident (i, range0)))
/// Determine whether this ident is the identifier of the `unit` type.
let isUnit (ident : SynLongIdent) : bool =
match ident.LongIdent with
| [ i ] when System.String.Equals (i.idText, "unit", System.StringComparison.OrdinalIgnoreCase) -> true
| _ -> false
/// Determine whether this ident is the identifier of the `list` (F# list) type.
let isList (ident : SynLongIdent) : bool =
match ident.LongIdent with
| [ i ] when System.String.Equals (i.idText, "list", System.StringComparison.OrdinalIgnoreCase) -> true
// TODO: consider FSharpList or whatever it is
| _ -> false
/// Determine whether this ident is an identifier of the array type.
let isArray (ident : SynLongIdent) : bool =
match ident.LongIdent with
| [ i ] when
System.String.Equals (i.idText, "array", System.StringComparison.OrdinalIgnoreCase)
|| System.String.Equals (i.idText, "[]", System.StringComparison.Ordinal)
->
true
| _ -> false
/// Determine whether this ident is an identifier of the F# option type.
let isOption (ident : SynLongIdent) : bool =
match ident.LongIdent with
| [ i ] when System.String.Equals (i.idText, "option", System.StringComparison.OrdinalIgnoreCase) -> true
// TODO: consider Microsoft.FSharp.Option or whatever it is
| _ -> false
/// Determine whether this ident is an identifier of the F# Choice type.
let isChoice (ident : SynLongIdent) : bool =
match ident.LongIdent with
| [ i ] when System.String.Equals (i.idText, "Choice", System.StringComparison.Ordinal) -> true
// TODO: consider Microsoft.FSharp.Choice or whatever it is
| _ -> false
/// Determine whether this ident is an identifier of the System.Nullable type.
let isNullable (ident : SynLongIdent) : bool =
match ident.LongIdent |> List.map _.idText with
| [ "System" ; "Nullable" ]
| [ "Nullable" ] -> true
| _ -> false
/// Determine whether this ident is an identifier of the RestEase.Response type.
let isResponse (ident : SynLongIdent) : bool =
match ident.LongIdent |> List.map _.idText with
| [ "Response" ]
| [ "RestEase" ; "Response" ] -> true
| _ -> false
/// Determine whether this ident is an identifier of the F# Map type.
let isMap (ident : SynLongIdent) : bool =
match ident.LongIdent |> List.map _.idText with
| [ "Map" ] -> true
| _ -> false
/// Determine whether this ident is an identifier of the System.Collections.Generic.IReadOnlyDictionary type.
/// This is purely syntactic: it will not say that e.g. the Dictionary type is an IReadOnlyDictionary.
let isReadOnlyDictionary (ident : SynLongIdent) : bool =
match ident.LongIdent |> List.map _.idText with
| [ "IReadOnlyDictionary" ]
| [ "Generic" ; "IReadOnlyDictionary" ]
| [ "Collections" ; "Generic" ; "IReadOnlyDictionary" ]
| [ "System" ; "Collections" ; "Generic" ; "IReadOnlyDictionary" ] -> true
| _ -> false
/// Determine whether this ident is an identifier of the System.Collections.Generic.Dictionary type.
let isDictionary (ident : SynLongIdent) : bool =
match ident.LongIdent |> List.map _.idText with
| [ "Dictionary" ]
| [ "Generic" ; "Dictionary" ]
| [ "Collections" ; "Generic" ; "Dictionary" ]
| [ "System" ; "Collections" ; "Generic" ; "Dictionary" ] -> true
| _ -> false
/// Determine whether this ident is an identifier of the System.Collections.Generic.IDictionary type.
/// This is purely syntactic: it will not say that e.g. the Dictionary type is an IDictionary.
let isIDictionary (ident : SynLongIdent) : bool =
match ident.LongIdent |> List.map _.idText with
| [ "IDictionary" ]
| [ "Generic" ; "IDictionary" ]
| [ "Collections" ; "Generic" ; "IDictionary" ]
| [ "System" ; "Collections" ; "Generic" ; "IDictionary" ] -> true
| _ -> false

View File

@@ -0,0 +1,28 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
/// Methods for manipulating SynMatchClause, a type representing a single arm of a `match` pattern match.
/// For example, the entire line of code `| Foo (a, b) -> bar` is represented by one of these.
[<RequireQualifiedAccess>]
module SynMatchClause =
/// Represents the `match` arm `| {lhs} -> {rhs}`.
let create (lhs : SynPat) (rhs : SynExpr) : SynMatchClause =
SynMatchClause.SynMatchClause (
lhs,
None,
rhs,
range0,
DebugPointAtTarget.Yes,
{
ArrowRange = Some range0
BarRange = Some range0
}
)
/// Replace the `where` clause (or add a new one, if there isn't one already) in this `match` arm.
let withWhere (where : SynExpr) (m : SynMatchClause) : SynMatchClause =
match m with
| SynMatchClause (synPat, _, resultExpr, range, debugPointAtTarget, synMatchClauseTrivia) ->
SynMatchClause (synPat, Some where, resultExpr, range, debugPointAtTarget, synMatchClauseTrivia)

View File

@@ -0,0 +1,78 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Text.Range
open Fantomas.FCS.Xml
/// Methods for manipulating SynMemberDefn, which specifies interface members and other such fields in a type declaration.
[<RequireQualifiedAccess>]
module SynMemberDefn =
let private interfaceMemberSlotFlags =
{
SynMemberFlags.IsInstance = true
SynMemberFlags.IsDispatchSlot = true
SynMemberFlags.IsOverrideOrExplicitImpl = false
SynMemberFlags.IsFinal = false
SynMemberFlags.GetterOrSetterIsCompilerGenerated = false
SynMemberFlags.MemberKind = SynMemberKind.Member
}
/// An `abstract Foo : blah`.
/// You specify the shape of any arguments via the input `arity`.
let abstractMember
(attrs : SynAttribute list)
(ident : SynIdent)
(typars : SynTyparDecls option)
(arity : SynValInfo)
(xmlDoc : PreXmlDoc)
(returnType : SynType)
: SynMemberDefn
=
let slot =
SynValSig.SynValSig (
attrs
|> List.map (fun attr ->
{
Attributes = [ attr ]
Range = range0
}
),
ident,
SynValTyparDecls.SynValTyparDecls (typars, true),
returnType,
arity,
false,
false,
xmlDoc,
None,
None,
range0,
{
EqualsRange = None
WithKeyword = None
InlineKeyword = None
LeadingKeyword = SynLeadingKeyword.Abstract range0
}
)
SynMemberDefn.AbstractSlot (
slot,
interfaceMemberSlotFlags,
range0,
{
GetSetKeywords = None
}
)
/// `static member Foo = ...`
let staticMember (binding : SynBinding) : SynMemberDefn =
let binding = SynBinding.makeStaticMember binding
SynMemberDefn.Member (binding, range0)
/// `member this.Foo = ...`
///
/// You need to make sure the `this` is present in the name of the binding.
let memberImplementation (binding : SynBinding) : SynMemberDefn =
let binding = SynBinding.makeInstanceMember binding
SynMemberDefn.Member (binding, range0)

View File

@@ -0,0 +1,37 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Text.Range
/// Methods for manipulating `SynModuleDecl`, the type representing a single definition within a module.
/// For example, an `open` statement, a `let` binding, a type definition, etc.
[<RequireQualifiedAccess>]
module SynModuleDecl =
/// Open this target (e.g. `open MyModule` or `open MyNamespace`).
let inline openAny (ident : SynOpenDeclTarget) : SynModuleDecl = SynModuleDecl.Open (ident, range0)
/// Add consecutive `let`-bindings, non-recursive.
let inline createLets (bindings : SynBinding list) : SynModuleDecl =
SynModuleDecl.Let (false, bindings, range0)
/// Add a single `let`-binding. (Use `createLets` for *multiple* bindings.)
let inline createLet (binding : SynBinding) : SynModuleDecl = createLets [ binding ]
/// Add type definitions.
let inline createTypes (tys : SynTypeDefn list) : SynModuleDecl = SynModuleDecl.Types (tys, range0)
/// Add a nested module definition.
let nestedModule (info : SynComponentInfo) (decls : SynModuleDecl list) : SynModuleDecl =
SynModuleDecl.NestedModule (
info,
false,
decls,
false,
range0,
{
ModuleKeyword = Some range0
EqualsRange = Some range0
}
)

View File

@@ -0,0 +1,26 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Xml
open Fantomas.FCS.Text.Range
/// Methods for manipulating SynModuleOrNamespace, which defines a module or namespace definition.
[<RequireQualifiedAccess>]
module SynModuleOrNamespace =
/// Create a namespace with the given name and with the given declarations inside it.
let createNamespace (name : LongIdent) (decls : SynModuleDecl list) : SynModuleOrNamespace =
SynModuleOrNamespace.SynModuleOrNamespace (
name,
false,
SynModuleOrNamespaceKind.DeclaredNamespace,
decls,
PreXmlDoc.Empty,
[],
None,
range0,
{
LeadingKeyword = SynModuleOrNamespaceLeadingKeyword.Namespace range0
}
)

View File

@@ -0,0 +1,73 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
/// Methods for manipulating `SynPat`, which represents a pattern being matched on in any context.
[<RequireQualifiedAccess>]
module SynPat =
/// Wrap this pattern in parentheses.
let inline paren (pat : SynPat) : SynPat = SynPat.Paren (pat, range0)
/// The anonymous pattern, `_`.
let anon : SynPat = SynPat.Wild range0
/// `{pat} : {ty}`
let inline annotateTypeNoParen (ty : SynType) (pat : SynPat) = SynPat.Typed (pat, ty, range0)
/// `({pat} : {ty})`
let inline annotateType (ty : SynType) (pat : SynPat) = paren (annotateTypeNoParen ty pat)
/// The pattern that is just the given name, `x` (e.g. in `match "hi" with | x -> ...`)
let inline named (s : string) : SynPat =
SynPat.Named (SynIdent.SynIdent (Ident (s, range0), None), false, None, range0)
/// The pattern that is just the given name, `i` (e.g. in `match "hi" with | i -> ...`)
let inline namedI (i : Ident) : SynPat =
SynPat.Named (SynIdent.SynIdent (i, None), false, None, range0)
/// The pattern that is the given name applied to these arguments, e.g. in `match "hi" with | Foo (a, b) -> ...`
let inline identWithArgs (i : LongIdent) (args : SynArgPats) : SynPat =
SynPat.LongIdent (SynLongIdent.create i, None, None, args, None, range0)
/// The pattern that is the given name applied to these arguments, e.g. in `match "hi" with | Foo (a, b) -> ...`
let inline nameWithArgs (i : string) (args : SynPat list) : SynPat =
identWithArgs [ Ident.create i ] (SynArgPats.create args)
/// The tuple pattern, `{el1}, {el2}, ...`
let inline tupleNoParen (elements : SynPat list) : SynPat =
match elements with
| [] -> failwith "Can't tuple no elements in a pattern"
| [ p ] -> p
| elements -> SynPat.Tuple (false, elements, List.replicate (elements.Length - 1) range0, range0)
/// The tuple pattern, `({el1}, {el2}, ...)`
///
/// Consider `tupleNoParen` if you don't want parentheses.
let inline tuple (elements : SynPat list) : SynPat = tupleNoParen elements |> paren
/// A constant pattern, e.g. in `match foo with | "hi" -> ...`
let inline createConst (c : SynConst) = SynPat.Const (c, range0)
/// The unit pattern, as in e.g. `let foo () = ...`
let unit = createConst SynConst.Unit
/// The null pattern, as in e.g. `match foo with | null -> ...`
let createNull = SynPat.Null range0
/// The empty list pattern, as in e.g. `match foo with | [] -> ...`
let emptyList = SynPat.ArrayOrList (false, [], range0)
/// The list cons pattern, as in e.g. `match foo with | lhs :: rhs -> ...`
let listCons (lhs : SynPat) (rhs : SynPat) =
SynPat.ListCons (
lhs,
rhs,
range0,
{
ColonColonRange = range0
}
)
/// The empty array pattern, as in e.g. `match foo with | [||] -> ...`
let emptyArray = SynPat.ArrayOrList (true, [], range0)

View File

@@ -0,0 +1,13 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
/// Methods for manipulating the SynSimplePat AST type. This type represents the left-hand side of a pattern match,
/// e.g. the `x` in `fun x -> foo`.
[<RequireQualifiedAccess>]
module SynSimplePat =
/// Create a SynSimplePat that is a bare identifier, no type information, non-optional.
let createId (id : Ident) : SynSimplePat =
SynSimplePat.Id (id, None, false, false, false, range0)

View File

@@ -0,0 +1,15 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
/// Methods for manipulating the SynSimplePats AST type. This type represents a collection of SynSimplePat entries,
/// all tupled together (e.g. as in `fun (a, b : int) -> ...`).
[<RequireQualifiedAccess>]
module SynSimplePats =
/// Build a SynSimplePats by tupling together a bunch of individual patterns.
let create (pats : SynSimplePat list) : SynSimplePats =
match pats with
| [] -> SynSimplePats.SimplePats ([], [], range0)
| pats -> SynSimplePats.SimplePats (pats, List.replicate (pats.Length - 1) range0, range0)

View File

@@ -0,0 +1,624 @@
namespace WoofWare.Whippet.Fantomas
open System
open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
/// Patterns to let you match on a `SynType` to discover whether it's one of a well-known variety.
[<AutoOpen>]
module SynTypePatterns =
/// An `option` type. You get access to the type argument of `option`.
let (|OptionType|_|) (fieldType : SynType) =
match fieldType with
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isOption ident ->
Some innerType
| _ -> None
/// A `Choice` type. You get access to the type arguments; for example, a two-case `Choice<int, string>` would match
/// `ChoiceType [PrimitiveType "System.Int32" ; PrimitiveType "System.String"]`.
let (|ChoiceType|_|) (fieldType : SynType) =
match fieldType with
| SynType.App (SynType.LongIdent ident, _, inner, _, _, _, _) when SynLongIdent.isChoice ident -> Some inner
| _ -> None
/// A `System.Nullable` type. You get access to its type argument.
let (|NullableType|_|) (fieldType : SynType) =
match fieldType with
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isNullable ident ->
Some innerType
| _ -> None
/// An F# list type. You get access to its type argument.
let (|ListType|_|) (fieldType : SynType) =
match fieldType with
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isList ident ->
Some innerType
| _ -> None
/// An array type. You get access to its type argument.
let (|ArrayType|_|) (fieldType : SynType) =
match fieldType with
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isArray ident ->
Some innerType
| SynType.Array (1, innerType, _) -> Some innerType
| _ -> None
/// The `RestEase.Response` type.
let (|RestEaseResponseType|_|) (fieldType : SynType) =
match fieldType with
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when SynLongIdent.isResponse ident ->
Some innerType
| _ -> None
/// A System.Collections.Generic.Dictionary<_,_> type. You get access to its key and value argument types.
let (|DictionaryType|_|) (fieldType : SynType) =
match fieldType with
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when SynLongIdent.isDictionary ident ->
Some (key, value)
| _ -> None
/// A System.Collections.Generic.IDictionary<_,_> type. You get access to its key and value argument types.
/// Note that this is purely syntactic: a plain `Dictionary<_, _>` won't match this.
let (|IDictionaryType|_|) (fieldType : SynType) =
match fieldType with
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when SynLongIdent.isIDictionary ident ->
Some (key, value)
| _ -> None
/// A System.Collections.Generic.IReadOnlyDictionary<_,_> type. You get access to its key and value argument types.
/// Note that this is purely syntactic: a plain `Dictionary<_, _>` won't match this.
let (|IReadOnlyDictionaryType|_|) (fieldType : SynType) =
match fieldType with
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when
SynLongIdent.isReadOnlyDictionary ident
->
Some (key, value)
| _ -> None
/// An F# Map<_, _> type. You get access to its key and value argument types.
let (|MapType|_|) (fieldType : SynType) =
match fieldType with
| SynType.App (SynType.LongIdent ident, _, [ key ; value ], _, _, _, _) when SynLongIdent.isMap ident ->
Some (key, value)
| _ -> None
/// A System.Numerics.BigInteger type (which can be denoted `bigint`).
let (|BigInt|_|) (fieldType : SynType) : unit option =
match fieldType with
| SynType.LongIdent ident ->
match ident.LongIdent |> List.map _.idText with
| [ "bigint" ]
| [ "BigInteger" ]
| [ "Numerics" ; "BigInteger" ]
| [ "System" ; "Numerics" ; "BigInteger" ] -> Some ()
| _ -> None
| _ -> None
/// Returns the type, qualified as in e.g. `System.Boolean`.
let (|PrimitiveType|_|) (fieldType : SynType) : LongIdent option =
match fieldType with
| SynType.LongIdent ident ->
match ident.LongIdent with
| [ i ] -> Primitives.qualifyType i.idText
| _ -> None
| _ -> None
/// The `string` type.
let (|String|_|) (fieldType : SynType) : unit option =
match fieldType with
| SynType.LongIdent ident ->
match ident.LongIdent with
| [ i ] ->
[ "string" ]
|> List.tryFind (fun s -> s = i.idText)
|> Option.map ignore<string>
| _ -> None
| _ -> None
/// The `byte` type.
let (|Byte|_|) (fieldType : SynType) : unit option =
match fieldType with
| SynType.LongIdent ident ->
match ident.LongIdent with
| [ i ] -> [ "byte" ] |> List.tryFind (fun s -> s = i.idText) |> Option.map ignore<string>
| _ -> None
| _ -> None
/// The `System.Guid` type.
let (|Guid|_|) (fieldType : SynType) : unit option =
match fieldType with
| SynType.LongIdent ident ->
match ident.LongIdent |> List.map (fun i -> i.idText) with
| [ "System" ; "Guid" ]
| [ "Guid" ] -> Some ()
| _ -> None
| _ -> None
/// The `System.Net.Http.HttpResponseMessage` type.
let (|HttpResponseMessage|_|) (fieldType : SynType) : unit option =
match fieldType with
| SynType.LongIdent ident ->
match ident.LongIdent |> List.map (fun i -> i.idText) with
| [ "System" ; "Net" ; "Http" ; "HttpResponseMessage" ]
| [ "Net" ; "Http" ; "HttpResponseMessage" ]
| [ "Http" ; "HttpResponseMessage" ]
| [ "HttpResponseMessage" ] -> Some ()
| _ -> None
| _ -> None
/// The `System.Net.Http.HttpContent` type.
let (|HttpContent|_|) (fieldType : SynType) : unit option =
match fieldType with
| SynType.LongIdent ident ->
match ident.LongIdent |> List.map (fun i -> i.idText) with
| [ "System" ; "Net" ; "Http" ; "HttpContent" ]
| [ "Net" ; "Http" ; "HttpContent" ]
| [ "Http" ; "HttpContent" ]
| [ "HttpContent" ] -> Some ()
| _ -> None
| _ -> None
/// The `System.IO.Stream` type.
let (|Stream|_|) (fieldType : SynType) : unit option =
match fieldType with
| SynType.LongIdent ident ->
match ident.LongIdent |> List.map (fun i -> i.idText) with
| [ "System" ; "IO" ; "Stream" ]
| [ "IO" ; "Stream" ]
| [ "Stream" ] -> Some ()
| _ -> None
| _ -> None
/// A numeric primitive type, like `byte` or `float` but not `char`.
/// You get access to the fully-qualified type name, like `System.Int32`.
let (|NumberType|_|) (fieldType : SynType) =
match fieldType with
| SynType.LongIdent ident ->
match ident.LongIdent with
| [ i ] ->
// We won't bother with the case that the user has done e.g. `Single` (relying on `System` being open).
match Primitives.qualifyType i.idText with
| Some qualified ->
match i.idText with
| "char"
| "string" -> None
| _ -> Some qualified
| None -> None
| _ -> None
| _ -> None
/// A type with a unit of measure. Returns the name of the measure, and the outer type to which the measure was
/// applied.
let (|Measure|_|) (fieldType : SynType) : (Ident * LongIdent) option =
match fieldType with
| SynType.App (NumberType outer,
_,
[ SynType.LongIdent (SynLongIdent.SynLongIdent ([ ident ], _, _)) ],
_,
_,
_,
_) -> Some (ident, outer)
| _ -> None
/// The `System.Text.Json.Nodes.JsonNode` type.
let (|JsonNode|_|) (fieldType : SynType) : unit option =
match fieldType with
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
match ident |> List.map (fun i -> i.idText) with
| [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
| [ "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
| [ "Json" ; "Nodes" ; "JsonNode" ]
| [ "Nodes" ; "JsonNode" ]
| [ "JsonNode" ] -> Some ()
| _ -> None
| _ -> None
/// The `unit` type.
let (|UnitType|_|) (fieldType : SynType) : unit option =
match fieldType with
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
match ident |> List.map (fun i -> i.idText.ToLowerInvariant ()) with
| [ "microsoft" ; "fsharp" ; "core" ; "unit" ]
| [ "fsharp" ; "core" ; "unit" ]
| [ "core" ; "unit" ]
| [ "unit" ] -> Some ()
| _ -> None
| _ -> None
/// The `System.DateOnly` type.
let (|DateOnly|_|) (fieldType : SynType) =
match fieldType with
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
match ident |> List.map (fun i -> i.idText) with
| [ "System" ; "DateOnly" ]
| [ "DateOnly" ] -> Some ()
| _ -> None
| _ -> None
/// The `System.DateTime` type.
let (|DateTime|_|) (fieldType : SynType) =
match fieldType with
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
match ident |> List.map (fun i -> i.idText) with
| [ "System" ; "DateTime" ]
| [ "DateTime" ] -> Some ()
| _ -> None
| _ -> None
/// The `System.DateTimeOffset` type.
let (|DateTimeOffset|_|) (fieldType : SynType) =
match fieldType with
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
match ident |> List.map (fun i -> i.idText) with
| [ "System" ; "DateTimeOffset" ]
| [ "DateTimeOffset" ] -> Some ()
| _ -> None
| _ -> None
/// The `System.Uri` type.
let (|Uri|_|) (fieldType : SynType) =
match fieldType with
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
match ident |> List.map (fun i -> i.idText) with
| [ "System" ; "Uri" ]
| [ "Uri" ] -> Some ()
| _ -> None
| _ -> None
/// The `System.Threading.Tasks.Task<_>` type. You get access to the generic argument.
/// Due to a design error which I haven't yet fixed, this throws on the non-generic Task; please raise an issue
/// if you run into this.
let (|Task|_|) (fieldType : SynType) : SynType option =
match fieldType with
| SynType.App (SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)), _, args, _, _, _, _) ->
match ident |> List.map (fun i -> i.idText) with
| [ "Task" ]
| [ "Tasks" ; "Task" ]
| [ "Threading" ; "Tasks" ; "Task" ]
| [ "System" ; "Threading" ; "Tasks" ; "Task" ] ->
match args with
| [ arg ] -> Some arg
| _ -> failwithf "Expected Task to be applied to exactly one arg, but got: %+A" args
| _ -> None
| _ -> None
/// The `System.IO.DirectoryInfo` type.
let (|DirectoryInfo|_|) (fieldType : SynType) =
match fieldType with
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
match ident |> List.map (fun i -> i.idText) with
| [ "System" ; "IO" ; "DirectoryInfo" ]
| [ "IO" ; "DirectoryInfo" ]
| [ "DirectoryInfo" ] -> Some ()
| _ -> None
| _ -> None
/// The `System.IO.FieldInfo` type.
let (|FileInfo|_|) (fieldType : SynType) =
match fieldType with
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
match ident |> List.map (fun i -> i.idText) with
| [ "System" ; "IO" ; "FileInfo" ]
| [ "IO" ; "FileInfo" ]
| [ "FileInfo" ] -> Some ()
| _ -> None
| _ -> None
/// The `System.TimeSpan` type.
let (|TimeSpan|_|) (fieldType : SynType) =
match fieldType with
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
match ident |> List.map (fun i -> i.idText) with
| [ "System" ; "TimeSpan" ]
| [ "TimeSpan" ] -> Some ()
| _ -> None
| _ -> None
/// Methods for manipulating SynType, which represents a type as might appear e.g. in a type annotation.
[<RequireQualifiedAccess>]
module SynType =
/// Strip all outer parentheses from this SynType.
///
/// Most functions by default will not strip parentheses. Note, for example, that `let foo : (int) = 3` is fine.
/// Use `stripOptionalParen` to turn that `(int)` into `int`, so that e.g. you can match on it using the patterns
/// in `SynTypePatterns`.
let rec stripOptionalParen (ty : SynType) : SynType =
match ty with
| SynType.Paren (ty, _) -> stripOptionalParen ty
| ty -> ty
/// Wrap this type in parentheses.
let inline paren (ty : SynType) : SynType = SynType.Paren (ty, range0)
/// Define a SynType by just a name.
let inline createLongIdent (ident : LongIdent) : SynType =
SynType.LongIdent (SynLongIdent.create ident)
/// Define a SynType by just a name.
let inline createLongIdent' (ident : string list) : SynType =
SynType.LongIdent (SynLongIdent.createS' ident)
/// Define a SynType by just a name. Use `createLongIdent'` if you want more components in this name,
/// so e.g. don't pass `System.Collections.Generic.Dictionary` to `named`.
let inline named (name : string) = createLongIdent' [ name ]
/// {name}<{args}>
let inline app' (name : SynType) (args : SynType list) : SynType =
if args.IsEmpty then
failwith "Type cannot be applied to no arguments"
SynType.App (name, Some range0, args, List.replicate (args.Length - 1) range0, Some range0, false, range0)
/// {name}<{args}>
let inline app (name : string) (args : SynType list) : SynType = app' (named name) args
/// Returns None if the input list was empty.
let inline tupleNoParen (ty : SynType list) : SynType option =
match List.rev ty with
| [] -> None
| [ t ] -> Some t
| t :: rest ->
([ SynTupleTypeSegment.Type t ], rest)
||> List.fold (fun ty nextArg -> SynTupleTypeSegment.Type nextArg :: SynTupleTypeSegment.Star range0 :: ty)
|> fun segs -> SynType.Tuple (false, segs, range0)
|> Some
/// `{arg} {name}`, e.g. `int option`.
let inline appPostfix (name : string) (arg : SynType) : SynType =
SynType.App (named name, None, [ arg ], [], None, true, range0)
/// `{arg} {name1.name2.name3}`, e.g. `int System.Nullable`.
let inline appPostfix' (name : string list) (arg : SynType) : SynType =
SynType.App (createLongIdent' name, None, [ arg ], [], None, true, range0)
/// The type `{domain} -> {range}`.
let inline funFromDomain (domain : SynType) (range : SynType) : SynType =
SynType.Fun (
domain,
range,
range0,
{
ArrowRange = range0
}
)
/// In an abstract type definition like `type Foo = abstract Blah : x : int -> string`,
/// this represents one single `x : int` part.
let inline signatureParamOfType
(attrs : SynAttribute list)
(ty : SynType)
(optional : bool)
(name : Ident option)
: SynType
=
SynType.SignatureParameter (
attrs
|> List.map (fun attr ->
{
Attributes = [ attr ]
Range = range0
}
),
optional,
name,
ty,
range0
)
/// Create a type which refers to a generic type parameter. For example, `'a` (assuming there's already
/// some language construct causing the generic `'a` to be in scope).
let inline var (ty : SynTypar) : SynType = SynType.Var (ty, range0)
/// The `unit` type.
let unit : SynType = named "unit"
/// The `obj` type.
let obj : SynType = named "obj"
/// The `bool` type.
let bool : SynType = named "bool"
/// The `int` type.
let int : SynType = named "int"
/// The type `{elt} array`.
let array (elt : SynType) : SynType = SynType.Array (1, elt, range0)
/// The type `{elt} list` (i.e. an F# list).
let list (elt : SynType) : SynType =
SynType.App (named "list", None, [ elt ], [], None, true, range0)
/// The type `{elt} option`.
let option (elt : SynType) : SynType =
SynType.App (named "option", None, [ elt ], [], None, true, range0)
/// The anonymous type, i.e. the `_` in the type-annotated `x : _`.
let anon : SynType = SynType.Anon range0
/// The type `System.Threading.Tasks.Task<{elt}>`.
let task (elt : SynType) : SynType =
SynType.App (
createLongIdent' [ "System" ; "Threading" ; "Tasks" ; "Task" ],
None,
[ elt ],
[],
None,
true,
range0
)
/// The type `string`.
let string : SynType = named "string"
/// Given ['a1, 'a2] and 'ret, returns 'a1 -> 'a2 -> 'ret.
let toFun (inputs : SynType list) (ret : SynType) : SynType =
(ret, List.rev inputs) ||> List.fold (fun ty input -> funFromDomain input ty)
/// Convert a canonical form like `System.Int32` to a human-readable form like `int32`.
/// Throws on unrecognised inputs.
let primitiveToHumanReadableString (name : LongIdent) : string =
match name |> List.map _.idText with
| [ "System" ; "Single" ] -> "single"
| [ "System" ; "Double" ] -> "double"
| [ "System" ; "Byte" ] -> "byte"
| [ "System" ; "SByte" ] -> "signed byte"
| [ "System" ; "Int16" ] -> "int16"
| [ "System" ; "Int32" ] -> "int32"
| [ "System" ; "Int64" ] -> "int64"
| [ "System" ; "UInt16" ] -> "uint16"
| [ "System" ; "UInt32" ] -> "uint32"
| [ "System" ; "UInt64" ] -> "uint64"
| [ "System" ; "Char" ] -> "char"
| [ "System" ; "Decimal" ] -> "decimal"
| [ "System" ; "String" ] -> "string"
| [ "System" ; "Boolean" ] -> "bool"
| ty ->
ty
|> String.concat "."
|> failwithf "could not create human-readable string for primitive type %s"
/// Attempt to create a human-readable representation of this type, for use in error messages.
/// This function throws if we couldn't decide on a human-readable representation.
let rec toHumanReadableString (ty : SynType) : string =
match ty with
| PrimitiveType t1 -> primitiveToHumanReadableString t1
| OptionType t1 -> toHumanReadableString t1 + " option"
| NullableType t1 -> toHumanReadableString t1 + " Nullable"
| ChoiceType ts ->
ts
|> List.map toHumanReadableString
|> String.concat ", "
|> sprintf "Choice<%s>"
| MapType (k, v)
| DictionaryType (k, v)
| IDictionaryType (k, v)
| IReadOnlyDictionaryType (k, v) -> sprintf "map<%s, %s>" (toHumanReadableString k) (toHumanReadableString v)
| ListType t1 -> toHumanReadableString t1 + " list"
| ArrayType t1 -> toHumanReadableString t1 + " array"
| Task t1 -> toHumanReadableString t1 + " Task"
| UnitType -> "unit"
| FileInfo -> "FileInfo"
| DirectoryInfo -> "DirectoryInfo"
| Uri -> "URI"
| Stream -> "Stream"
| Guid -> "GUID"
| BigInt -> "bigint"
| DateTimeOffset -> "DateTimeOffset"
| DateOnly -> "DateOnly"
| TimeSpan -> "TimeSpan"
| SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) -> ident |> List.map _.idText |> String.concat "."
| ty -> failwithf "could not compute human-readable string for type: %O" ty
/// Guess whether the types are equal. We err on the side of saying "no, they're different".
let rec provablyEqual (ty1 : SynType) (ty2 : SynType) : bool =
if Object.ReferenceEquals (ty1, ty2) then
true
else
match ty1 with
| PrimitiveType t1 ->
match ty2 with
| PrimitiveType t2 -> (t1 |> List.map _.idText) = (t2 |> List.map _.idText)
| _ -> false
| OptionType t1 ->
match ty2 with
| OptionType t2 -> provablyEqual t1 t2
| _ -> false
| NullableType t1 ->
match ty2 with
| NullableType t2 -> provablyEqual t1 t2
| _ -> false
| ChoiceType t1 ->
match ty2 with
| ChoiceType t2 ->
t1.Length = t2.Length
&& List.forall (fun (a, b) -> provablyEqual a b) (List.zip t1 t2)
| _ -> false
| DictionaryType (k1, v1) ->
match ty2 with
| DictionaryType (k2, v2) -> provablyEqual k1 k2 && provablyEqual v1 v2
| _ -> false
| IDictionaryType (k1, v1) ->
match ty2 with
| IDictionaryType (k2, v2) -> provablyEqual k1 k2 && provablyEqual v1 v2
| _ -> false
| IReadOnlyDictionaryType (k1, v1) ->
match ty2 with
| IReadOnlyDictionaryType (k2, v2) -> provablyEqual k1 k2 && provablyEqual v1 v2
| _ -> false
| MapType (k1, v1) ->
match ty2 with
| MapType (k2, v2) -> provablyEqual k1 k2 && provablyEqual v1 v2
| _ -> false
| ListType t1 ->
match ty2 with
| ListType t2 -> provablyEqual t1 t2
| _ -> false
| ArrayType t1 ->
match ty2 with
| ArrayType t2 -> provablyEqual t1 t2
| _ -> false
| Task t1 ->
match ty2 with
| Task t2 -> provablyEqual t1 t2
| _ -> false
| UnitType ->
match ty2 with
| UnitType -> true
| _ -> false
| FileInfo ->
match ty2 with
| FileInfo -> true
| _ -> false
| DirectoryInfo ->
match ty2 with
| DirectoryInfo -> true
| _ -> false
| Uri ->
match ty2 with
| Uri -> true
| _ -> false
| Stream ->
match ty2 with
| Stream -> true
| _ -> false
| Guid ->
match ty2 with
| Guid -> true
| _ -> false
| BigInt ->
match ty2 with
| BigInt -> true
| _ -> false
| DateTimeOffset ->
match ty2 with
| DateTimeOffset -> true
| _ -> false
| DateOnly ->
match ty2 with
| DateOnly -> true
| _ -> false
| _ ->
match ty1, ty2 with
| SynType.LongIdent (SynLongIdent (ident1, _, _)), SynType.LongIdent (SynLongIdent (ident2, _, _)) ->
let ident1 = ident1 |> List.map _.idText
let ident2 = ident2 |> List.map _.idText
ident1 = ident2
| _, _ -> false
/// Returns the args (where these are tuple types if curried) in order, and the return type.
let rec getType (ty : SynType) : (SynType * bool) list * SynType =
match ty with
| SynType.Paren (ty, _) -> getType ty
| SynType.Fun (argType, returnType, _, _) ->
let args, ret = getType returnType
// TODO this code is clearly wrong
let (inputArgs, inputRet), hasParen =
match argType with
| SynType.Paren (argType, _) -> getType argType, true
| _ -> getType argType, false
((toFun (List.map fst inputArgs) inputRet), hasParen) :: args, ret
| _ -> [], ty

View File

@@ -0,0 +1,53 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Text.Range
/// Methods for manipulating `SynTypeDefn`, which represents any type definition like `type Foo = ...`.
[<RequireQualifiedAccess>]
module SynTypeDefn =
/// Build a `SynTypeDefn` from its components:
/// the "front matter" `SynComponentInfo`, and the "body" `SynTypeDefnRepr`.
let inline create (componentInfo : SynComponentInfo) (repr : SynTypeDefnRepr) : SynTypeDefn =
SynTypeDefn.SynTypeDefn (
componentInfo,
repr,
[],
None,
range0,
{
LeadingKeyword = SynTypeDefnLeadingKeyword.Type range0
EqualsRange = Some range0
WithKeyword = None
}
)
/// Add member definitions to this type: `type Foo = ... with member Blah = ...`
let inline withMemberDefns (members : SynMemberDefn list) (r : SynTypeDefn) : SynTypeDefn =
match r with
| SynTypeDefn (typeInfo, typeRepr, _, ctor, range, trivia) ->
SynTypeDefn.SynTypeDefn (typeInfo, typeRepr, members, ctor, range, trivia)
/// Get the name of this type as it appears in the source.
let getName (defn : SynTypeDefn) : LongIdent =
match defn with
| SynTypeDefn (SynComponentInfo.SynComponentInfo (_, _, _, id, _, _, _, _), _, _, _, _, _) -> id
/// Select from this type definition the first attribute with the given name: `[<Foo>] type Blah = ...`
let getAttribute (attrName : string) (defn : SynTypeDefn) : SynAttribute option =
match defn with
| SynTypeDefn (SynComponentInfo.SynComponentInfo (attrs, _, _, _, _, _, _, _), _, _, _, _, _) ->
attrs
|> List.collect (fun a -> a.Attributes)
|> List.tryFind (fun i ->
match i.TypeName with
| SynLongIdent.SynLongIdent (id, _, _) ->
let name = List.last(id).idText
name = attrName || name + "Attribute" = attrName
)
/// Determine whether this type definition has an attribute with the given name: `[<Foo>] type Blah = ...`
let hasAttribute (attrName : string) (defn : SynTypeDefn) : bool =
getAttribute attrName defn |> Option.isSome

View File

@@ -0,0 +1,32 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
/// Methods for manipulating SynTypeDefnRepr, which represents the "body" of a type definition: what actually makes up
/// the type, as opposed to e.g. its name.
[<RequireQualifiedAccess>]
module SynTypeDefnRepr =
/// A definition like `abstract Blah : int`, as you would use to define an interface type.
let inline interfaceType (mems : SynMemberDefns) : SynTypeDefnRepr =
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Unspecified, mems, range0)
/// Indicates the body of a `type Foo with {body}` extension type declaration.
let inline augmentation () : SynTypeDefnRepr =
SynTypeDefnRepr.ObjectModel (SynTypeDefnKind.Augmentation range0, [], range0)
/// An F# discriminated union with the given accessibility modifier on the implementation:
/// `type Foo = private | Blah`.
let inline unionWithAccess (implAccess : SynAccess option) (cases : SynUnionCase list) : SynTypeDefnRepr =
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (implAccess, cases, range0), range0)
/// An F# discriminated union.
let inline union (cases : SynUnionCase list) : SynTypeDefnRepr = unionWithAccess None cases
/// An F# record with the given accessibility modifier on the implementation: `type Foo = private { blah }`.
let inline recordWithAccess (implAccess : SynAccess option) (fields : SynField list) : SynTypeDefnRepr =
SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (implAccess, fields, range0), range0)
/// An F# record.
let inline record (fields : SynField list) : SynTypeDefnRepr = recordWithAccess None fields

View File

@@ -0,0 +1,57 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
open Fantomas.FCS.Xml
open Fantomas.FCS.SyntaxTrivia
/// Represents everything you need to know about a union case.
/// This is generic on whether each field of this case must be named.
type UnionCase<'ident> =
{
/// The name of the case: e.g. `| Foo of blah` has this being `Foo`.
Name : Ident
/// Any docstring associated with this case.
XmlDoc : PreXmlDoc option
/// Any accessibility modifier: e.g. `type Foo = private | Blah`.
Access : SynAccess option
/// Attributes on the case: for example, `| [<Attr>] Foo of blah`.
Attributes : SynAttribute list
/// The data contained within the case: for example, `[blah]` in `| Foo of blah`.
Fields : SynFieldData<'ident> list
}
/// Methods for manipulating `SynUnionCase`, which represents a single case of a discriminated union.
[<RequireQualifiedAccess>]
module SynUnionCase =
/// Build a SynUnionCase from our structured `UnionCase` type.
let create (case : UnionCase<Ident option>) : SynUnionCase =
let fields =
case.Fields
|> List.map (fun field ->
SynField.SynField (
SynAttributes.ofAttrs field.Attrs,
false,
field.Ident,
field.Type,
false,
PreXmlDoc.Empty,
None,
range0,
{
LeadingKeyword = None
}
)
)
SynUnionCase.SynUnionCase (
SynAttributes.ofAttrs case.Attributes,
SynIdent.createI case.Name,
SynUnionCaseKind.Fields fields,
case.XmlDoc |> Option.defaultValue PreXmlDoc.Empty,
case.Access,
range0,
{
BarRange = Some range0
}
)

View File

@@ -0,0 +1,9 @@
namespace WoofWare.Whippet.Fantomas
open Fantomas.FCS.Syntax
/// Module for manipulating the SynValInfo AST type (which represents the arguments and return type of a `let` binding).
[<RequireQualifiedAccess>]
module SynValInfo =
/// No arguments, no return info.
let empty = SynValInfo.SynValInfo ([], SynArgInfo.empty)

View File

@@ -0,0 +1,65 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Authors>Patrick Stevens</Authors>
<Copyright>Copyright (c) Patrick Stevens 2024</Copyright>
<Description>Helpers for accessing Fantomas syntax trees.</Description>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/Smaug123/WoofWare.Whippet</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>fsharp;fantomas</PackageTags>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarnOn>FS3559</WarnOn>
<PackageId>WoofWare.Whippet.Fantomas</PackageId>
</PropertyGroup>
<ItemGroup>
<Compile Include="Primitives.fs" />
<Compile Include="SynAttributes.fs" />
<Compile Include="SynConst.fs" />
<Compile Include="SynArgInfo.fs" />
<Compile Include="SynValInfo.fs" />
<Compile Include="PreXmlDoc.fs" />
<Compile Include="Ident.fs" />
<Compile Include="SynSimplePat.fs" />
<Compile Include="SynSimplePats.fs" />
<Compile Include="SynIdent.fs" />
<Compile Include="SynLongIdent.fs" />
<Compile Include="SynExprLetOrUseTrivia.fs" />
<Compile Include="SynArgPats.fs" />
<Compile Include="SynPat.fs" />
<Compile Include="SynBinding.fs" />
<Compile Include="SynType.fs" />
<Compile Include="SynMatchClause.fs" />
<Compile Include="CompExpr.fs" />
<Compile Include="SynExpr.fs" />
<Compile Include="SynField.fs" />
<Compile Include="SynUnionCase.fs" />
<Compile Include="SynTypeDefnRepr.fs" />
<Compile Include="SynTypeDefn.fs" />
<Compile Include="SynComponentInfo.fs" />
<Compile Include="SynMemberDefn.fs" />
<Compile Include="SynAttribute.fs" />
<Compile Include="SynModuleDecl.fs" />
<Compile Include="SynModuleOrNamespace.fs" />
<Compile Include="Ast.fs" />
<None Include="README.md">
<Pack>True</Pack>
<PackagePath>/</PackagePath>
<Link>README.md</Link>
</None>
<None Include="version.json" />
<EmbeddedResource Include="SurfaceBaseline.txt" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="6.0.1"/>
<!-- To match Myriad, right now, but once this is published we'll bump to latest -->
<PackageReference Include="Fantomas.FCS" Version="6.1.1"/>
<PackageReference Include="Fantomas.Core" Version="6.1.1"/>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,12 @@
{
"version": "0.1",
"publicReleaseRefSpec": [
"^refs/heads/main$"
],
"pathFilters": [
"./",
":/WoofWare.Whippet.Fantomas/",
":/global.json",
":/Directory.Build.props"
]
}

View File

@@ -16,7 +16,7 @@ module TestSurface =
[<Test>]
// https://github.com/nunit/nunit3-vs-adapter/issues/876
let CheckVersionAgainstRemote () =
MonotonicVersion.validate assembly "WoofWare.Myriad.Core"
MonotonicVersion.validate assembly "WoofWare.Whippet.Core"
*)
[<Test ; Explicit>]

View File

@@ -6,6 +6,10 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Whippet.Core", "Wo
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Whippet.Test", "WoofWare.Whippet.Test\WoofWare.Whippet.Test.fsproj", "{A2E2A639-D17D-426D-B424-0139B4DBCF8F}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Whippet.Fantomas", "WoofWare.Whippet.Fantomas\WoofWare.Whippet.Fantomas.fsproj", "{2D4FC000-94DC-4456-A7AA-A5776B91FB65}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "WoofWare.Whippet.Fantomas.Test", "WoofWare.Whippet.Fantomas.Test\WoofWare.Whippet.Fantomas.Test.fsproj", "{E220B17E-D608-43CB-B117-329BA240B13B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -24,5 +28,13 @@ Global
{A2E2A639-D17D-426D-B424-0139B4DBCF8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A2E2A639-D17D-426D-B424-0139B4DBCF8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A2E2A639-D17D-426D-B424-0139B4DBCF8F}.Release|Any CPU.Build.0 = Release|Any CPU
{2D4FC000-94DC-4456-A7AA-A5776B91FB65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D4FC000-94DC-4456-A7AA-A5776B91FB65}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D4FC000-94DC-4456-A7AA-A5776B91FB65}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D4FC000-94DC-4456-A7AA-A5776B91FB65}.Release|Any CPU.Build.0 = Release|Any CPU
{E220B17E-D608-43CB-B117-329BA240B13B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E220B17E-D608-43CB-B117-329BA240B13B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E220B17E-D608-43CB-B117-329BA240B13B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E220B17E-D608-43CB-B117-329BA240B13B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -61,7 +61,7 @@ module Program =
failwith
$"Expected GenerateRawFromRaw to take exactly one parameter: a RawSourceGenerationArgs. Got %i{pars.Length}"
if pars.[0].ParameterType <> typeof<RawSourceGenerationArgs> then
if pars.[0].ParameterType.FullName <> typeof<RawSourceGenerationArgs>.FullName then
failwith
$"Expected GenerateRawFromRaw to take exactly one parameter: a RawSourceGenerationArgs. Got %s{pars.[0].ParameterType.FullName}"
@@ -96,7 +96,7 @@ module Program =
)
let projectOptions =
defaultLoader.LoadProjects ([ args.InputFile.FullName ]) |> Seq.toArray
defaultLoader.LoadProjects [ args.InputFile.FullName ] |> Seq.toArray
let desiredProject =
projectOptions
@@ -104,7 +104,7 @@ module Program =
let toGenerate =
desiredProject.Items
|> List.choose (fun (ProjectItem.Compile (name, fullPath, metadata)) ->
|> List.choose (fun (ProjectItem.Compile (_name, fullPath, metadata)) ->
match metadata with
| None -> None
| Some metadata ->
@@ -122,7 +122,9 @@ module Program =
)
Console.Error.WriteLine $"Loading plugin: %s{args.PluginDll.FullName}"
let pluginAssembly = Assembly.LoadFrom args.PluginDll.FullName
// We will look up any member called GenerateRawFromRaw and/or GenerateFromRaw.
// It's your responsibility to decide whether to do anything with this call; you return null if you don't want
// to do anything.

View File

@@ -24,7 +24,6 @@
</None>
</ItemGroup>
<ItemGroup>
<!--<PackageReference Include="Fantomas.FCS" Version="6.3.15" />-->
<PackageReference Include="Ionide.ProjInfo" Version="0.67.0" />
<PackageReference Include="Microsoft.Build.Framework" Version="17.2.0" ExcludeAssets="runtime" PrivateAssets="all" />
<PackageReference Include="NuGet.Frameworks" Version="6.11.1" ExcludeAssets="runtime" PrivateAssets="all" />