mirror of
https://github.com/Smaug123/WoofWare.Myriad
synced 2025-10-26 22:29:01 +00:00
Compare commits
23 Commits
3ea1c7ab79
...
WoofWare.M
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61b07ad802 | ||
|
|
59369bcb94 | ||
|
|
072169e4e3 | ||
|
|
91136a25ab | ||
|
|
c51038448a | ||
|
|
09780efb07 | ||
|
|
f562271c12 | ||
|
|
e3081c3136 | ||
|
|
232d2ba5ec | ||
|
|
f7458f521e | ||
|
|
bfc25a672b | ||
|
|
af7fcb3028 | ||
|
|
91853b1fff | ||
|
|
1144e93c1c | ||
|
|
d899d77ae2 | ||
|
|
a2ad430b2f | ||
|
|
9e36986bc7 | ||
|
|
679c66885d | ||
|
|
246da41672 | ||
|
|
d07541c2c2 | ||
|
|
7b49505064 | ||
|
|
3209372b5b | ||
|
|
1bbbf4bd06 |
@@ -3,13 +3,13 @@
|
|||||||
"isRoot": true,
|
"isRoot": true,
|
||||||
"tools": {
|
"tools": {
|
||||||
"fantomas": {
|
"fantomas": {
|
||||||
"version": "6.3.0-alpha-007",
|
"version": "6.3.4",
|
||||||
"commands": [
|
"commands": [
|
||||||
"fantomas"
|
"fantomas"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"fsharp-analyzers": {
|
"fsharp-analyzers": {
|
||||||
"version": "0.24.0",
|
"version": "0.26.0",
|
||||||
"commands": [
|
"commands": [
|
||||||
"fsharp-analyzers"
|
"fsharp-analyzers"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ root=true
|
|||||||
|
|
||||||
[*]
|
[*]
|
||||||
charset=utf-8
|
charset=utf-8
|
||||||
end_of_line=crlf
|
|
||||||
trim_trailing_whitespace=true
|
trim_trailing_whitespace=true
|
||||||
insert_final_newline=true
|
insert_final_newline=true
|
||||||
indent_style=space
|
indent_style=space
|
||||||
|
|||||||
42
.github/workflows/dotnet.yaml
vendored
42
.github/workflows/dotnet.yaml
vendored
@@ -28,7 +28,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -58,7 +58,7 @@ jobs:
|
|||||||
- name: Build project
|
- name: Build project
|
||||||
run: nix develop --command dotnet build ./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj
|
run: nix develop --command dotnet build ./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj
|
||||||
- name: Run analyzers
|
- name: Run analyzers
|
||||||
run: nix run .#fsharp-analyzers -- --project ./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj --analyzers-path ./.analyzerpackages/g-research.fsharp.analyzers/0.8.0/ --verbosity detailed --report ./analysis.sarif --treat-as-error GRA-STRING-001 GRA-STRING-002 GRA-STRING-003 GRA-UNIONCASE-001 GRA-INTERPOLATED-001 GRA-TYPE-ANNOTATE-001 GRA-VIRTUALCALL-001 GRA-IMMUTABLECOLLECTIONEQUALITY-001 GRA-JSONOPTS-001 GRA-LOGARGFUNCFULLAPP-001 GRA-DISPBEFOREASYNC-001 --exclude-analyzers PartialAppAnalyzer
|
run: nix run .#fsharp-analyzers -- --project ./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj --analyzers-path ./.analyzerpackages/g-research.fsharp.analyzers/*/ --verbosity detailed --report ./analysis.sarif --treat-as-error GRA-STRING-001 GRA-STRING-002 GRA-STRING-003 GRA-UNIONCASE-001 GRA-INTERPOLATED-001 GRA-TYPE-ANNOTATE-001 GRA-VIRTUALCALL-001 GRA-IMMUTABLECOLLECTIONEQUALITY-001 GRA-JSONOPTS-001 GRA-LOGARGFUNCFULLAPP-001 GRA-DISPBEFOREASYNC-001 --exclude-analyzers PartialAppAnalyzer
|
||||||
|
|
||||||
build-nix:
|
build-nix:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -66,7 +66,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -79,7 +79,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -92,7 +92,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -105,7 +105,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -118,7 +118,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -132,7 +132,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -188,7 +188,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v25
|
uses: cachix/install-nix-action@V27
|
||||||
with:
|
with:
|
||||||
extra_nix_config: |
|
extra_nix_config: |
|
||||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -206,3 +206,25 @@ jobs:
|
|||||||
path: packed-attribute
|
path: packed-attribute
|
||||||
- name: Publish to NuGet (attribute)
|
- name: Publish to NuGet (attribute)
|
||||||
run: nix develop --command dotnet nuget push "packed-attribute/WoofWare.Myriad.Plugins.Attributes.*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
run: nix develop --command dotnet nuget push "packed-attribute/WoofWare.Myriad.Plugins.Attributes.*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
|
||||||
|
|
||||||
|
github-release-plugin:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ !github.event.repository.fork && github.ref == 'refs/heads/main' }}
|
||||||
|
needs: [all-required-checks-complete]
|
||||||
|
environment: main-deploy
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Download NuGet artifact (plugin)
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: nuget-package-plugin
|
||||||
|
- name: Download NuGet artifact (attribute)
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: nuget-package-attribute
|
||||||
|
- name: Tag and release plugin
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: sh .github/workflows/tag.sh
|
||||||
|
|||||||
17
.github/workflows/tag.sh
vendored
Normal file
17
.github/workflows/tag.sh
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
find . -maxdepth 1 -type f -name '*.nupkg' -exec sh -c 'tag=$(basename "$1" .nupkg); git tag "$tag"; git push origin "$tag"' shell {} \;
|
||||||
|
|
||||||
|
export TAG
|
||||||
|
TAG=$(find . -maxdepth 1 -type f -name 'WoofWare.Myriad.Plugins.*.nupkg' -exec sh -c 'basename "$1" .nupkg' shell {} \; | grep -v Attributes)
|
||||||
|
|
||||||
|
case "$TAG" in
|
||||||
|
*"
|
||||||
|
"*)
|
||||||
|
echo "Error: TAG contains a newline; multiple plugins found."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# target_commitish empty indicates the repo default branch
|
||||||
|
curl -L -X POST -H "Accept: application/vnd.github+json" -H "Authorization: Bearer $GITHUB_TOKEN" -H "X-GitHub-Api-Version: 2022-11-28" https://api.github.com/repos/Smaug123/WoofWare.Myriad/releases -d '{"tag_name":"'"$TAG"'","target_commitish":"","name":"'"$TAG"'","draft":false,"prerelease":false,"generate_release_notes":false}'
|
||||||
@@ -2,8 +2,8 @@ namespace ConsumePlugin
|
|||||||
|
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
type Const =
|
type Const<'a> =
|
||||||
| Int of int
|
| Verbatim of 'a
|
||||||
| String of string
|
| String of string
|
||||||
|
|
||||||
type PairOpKind =
|
type PairOpKind =
|
||||||
@@ -11,12 +11,12 @@ type PairOpKind =
|
|||||||
| ThenDoSeq
|
| ThenDoSeq
|
||||||
|
|
||||||
[<CreateCatamorphism "TreeCata">]
|
[<CreateCatamorphism "TreeCata">]
|
||||||
type Tree =
|
type Tree<'a, 'b> =
|
||||||
| Const of Const
|
| Const of Const<'a> * 'b
|
||||||
| Pair of Tree * Tree * PairOpKind
|
| Pair of Tree<'a, 'b> * Tree<'a, 'b> * PairOpKind
|
||||||
| Sequential of Tree list
|
| Sequential of Tree<'a, 'b> list
|
||||||
| Builder of Tree * TreeBuilder
|
| Builder of Tree<'a, 'b> * TreeBuilder<'b, 'a>
|
||||||
|
|
||||||
and TreeBuilder =
|
and TreeBuilder<'b, 'a> =
|
||||||
| Child of TreeBuilder
|
| Child of TreeBuilder<'b, 'a>
|
||||||
| Parent of Tree
|
| Parent of Tree<'a, 'b>
|
||||||
|
|||||||
@@ -47,6 +47,10 @@
|
|||||||
<Compile Include="GeneratedFileSystem.fs">
|
<Compile Include="GeneratedFileSystem.fs">
|
||||||
<MyriadFile>FSharpForFunAndProfitCata.fs</MyriadFile>
|
<MyriadFile>FSharpForFunAndProfitCata.fs</MyriadFile>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="List.fs" />
|
||||||
|
<Compile Include="ListCata.fs">
|
||||||
|
<MyriadFile>List.fs</MyriadFile>
|
||||||
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -12,16 +12,16 @@ namespace ConsumePlugin
|
|||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Description of how to combine cases during a fold
|
/// Description of how to combine cases during a fold
|
||||||
type TreeBuilderCataCase<'TreeBuilder, 'Tree> =
|
type TreeBuilderCataCase<'b, 'a, 'TreeBuilder, 'Tree> =
|
||||||
/// How to operate on the Child case
|
/// How to operate on the Child case
|
||||||
abstract Child : 'TreeBuilder -> 'TreeBuilder
|
abstract Child : 'TreeBuilder -> 'TreeBuilder
|
||||||
/// How to operate on the Parent case
|
/// How to operate on the Parent case
|
||||||
abstract Parent : 'Tree -> 'TreeBuilder
|
abstract Parent : 'Tree -> 'TreeBuilder
|
||||||
|
|
||||||
/// Description of how to combine cases during a fold
|
/// Description of how to combine cases during a fold
|
||||||
type TreeCataCase<'TreeBuilder, 'Tree> =
|
type TreeCataCase<'a, 'b, 'TreeBuilder, 'Tree> =
|
||||||
/// How to operate on the Const case
|
/// How to operate on the Const case
|
||||||
abstract Const : Const -> 'Tree
|
abstract Const : Const<'a> -> 'b -> 'Tree
|
||||||
/// How to operate on the Pair case
|
/// How to operate on the Pair case
|
||||||
abstract Pair : 'Tree -> 'Tree -> PairOpKind -> 'Tree
|
abstract Pair : 'Tree -> 'Tree -> PairOpKind -> 'Tree
|
||||||
/// How to operate on the Sequential case
|
/// How to operate on the Sequential case
|
||||||
@@ -30,30 +30,30 @@ type TreeCataCase<'TreeBuilder, 'Tree> =
|
|||||||
abstract Builder : 'Tree -> 'TreeBuilder -> 'Tree
|
abstract Builder : 'Tree -> 'TreeBuilder -> 'Tree
|
||||||
|
|
||||||
/// Specifies how to perform a fold (catamorphism) over the type Tree and its friends.
|
/// Specifies how to perform a fold (catamorphism) over the type Tree and its friends.
|
||||||
type TreeCata<'TreeBuilder, 'Tree> =
|
type TreeCata<'b, 'a, 'TreeBuilder, 'Tree> =
|
||||||
{
|
{
|
||||||
/// How to perform a fold (catamorphism) over the type TreeBuilder
|
/// How to perform a fold (catamorphism) over the type TreeBuilder
|
||||||
TreeBuilder : TreeBuilderCataCase<'TreeBuilder, 'Tree>
|
TreeBuilder : TreeBuilderCataCase<'b, 'a, 'TreeBuilder, 'Tree>
|
||||||
/// How to perform a fold (catamorphism) over the type Tree
|
/// How to perform a fold (catamorphism) over the type Tree
|
||||||
Tree : TreeCataCase<'TreeBuilder, 'Tree>
|
Tree : TreeCataCase<'a, 'b, 'TreeBuilder, 'Tree>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Methods to perform a catamorphism over the type Tree
|
/// Methods to perform a catamorphism over the type Tree
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module TreeCata =
|
module TreeCata =
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
type private Instruction =
|
type private Instruction<'b, 'a> =
|
||||||
| Process__TreeBuilder of TreeBuilder
|
| Process__TreeBuilder of TreeBuilder<'b, 'a>
|
||||||
| Process__Tree of Tree
|
| Process__Tree of Tree<'a, 'b>
|
||||||
| TreeBuilder_Child
|
| TreeBuilder_Child
|
||||||
| TreeBuilder_Parent
|
| TreeBuilder_Parent
|
||||||
| Tree_Pair of PairOpKind
|
| Tree_Pair of PairOpKind
|
||||||
| Tree_Sequential of int
|
| Tree_Sequential of int
|
||||||
| Tree_Builder
|
| Tree_Builder
|
||||||
|
|
||||||
let private loop (cata : TreeCata<_, _>) (instructions : ResizeArray<Instruction>) =
|
let private loop (cata : TreeCata<'b, 'a, 'TreeBuilder, 'Tree>) (instructions : ResizeArray<Instruction<'b, 'a>>) =
|
||||||
let treeStack = ResizeArray ()
|
let treeStack = ResizeArray<'Tree> ()
|
||||||
let treeBuilderStack = ResizeArray ()
|
let treeBuilderStack = ResizeArray<'TreeBuilder> ()
|
||||||
|
|
||||||
while instructions.Count > 0 do
|
while instructions.Count > 0 do
|
||||||
let currentInstruction = instructions.[instructions.Count - 1]
|
let currentInstruction = instructions.[instructions.Count - 1]
|
||||||
@@ -70,7 +70,7 @@ module TreeCata =
|
|||||||
instructions.Add (Instruction.Process__Tree arg0_0)
|
instructions.Add (Instruction.Process__Tree arg0_0)
|
||||||
| Instruction.Process__Tree x ->
|
| Instruction.Process__Tree x ->
|
||||||
match x with
|
match x with
|
||||||
| Tree.Const (arg0_0) -> cata.Tree.Const arg0_0 |> treeStack.Add
|
| Tree.Const (arg0_0, arg1_0) -> cata.Tree.Const arg0_0 arg1_0 |> treeStack.Add
|
||||||
| Tree.Pair (arg0_0, arg1_0, arg2_0) ->
|
| Tree.Pair (arg0_0, arg1_0, arg2_0) ->
|
||||||
instructions.Add (Instruction.Tree_Pair (arg2_0))
|
instructions.Add (Instruction.Tree_Pair (arg2_0))
|
||||||
instructions.Add (Instruction.Process__Tree arg0_0)
|
instructions.Add (Instruction.Process__Tree arg0_0)
|
||||||
@@ -120,14 +120,18 @@ module TreeCata =
|
|||||||
treeBuilderStack, treeStack
|
treeBuilderStack, treeStack
|
||||||
|
|
||||||
/// Execute the catamorphism.
|
/// Execute the catamorphism.
|
||||||
let runTreeBuilder (cata : TreeCata<'TreeBuilderRet, 'TreeRet>) (x : TreeBuilder) : 'TreeBuilderRet =
|
let runTreeBuilder
|
||||||
|
(cata : TreeCata<'b, 'a, 'TreeBuilderRet, 'TreeRet>)
|
||||||
|
(x : TreeBuilder<'b, 'a>)
|
||||||
|
: 'TreeBuilderRet
|
||||||
|
=
|
||||||
let instructions = ResizeArray ()
|
let instructions = ResizeArray ()
|
||||||
instructions.Add (Instruction.Process__TreeBuilder x)
|
instructions.Add (Instruction.Process__TreeBuilder x)
|
||||||
let treeBuilderRetStack, treeRetStack = loop cata instructions
|
let treeBuilderRetStack, treeRetStack = loop cata instructions
|
||||||
Seq.exactlyOne treeBuilderRetStack
|
Seq.exactlyOne treeBuilderRetStack
|
||||||
|
|
||||||
/// Execute the catamorphism.
|
/// Execute the catamorphism.
|
||||||
let runTree (cata : TreeCata<'TreeBuilderRet, 'TreeRet>) (x : Tree) : 'TreeRet =
|
let runTree (cata : TreeCata<'b, 'a, 'TreeBuilderRet, 'TreeRet>) (x : Tree<'a, 'b>) : 'TreeRet =
|
||||||
let instructions = ResizeArray ()
|
let instructions = ResizeArray ()
|
||||||
instructions.Add (Instruction.Process__Tree x)
|
instructions.Add (Instruction.Process__Tree x)
|
||||||
let treeBuilderRetStack, treeRetStack = loop cata instructions
|
let treeBuilderRetStack, treeRetStack = loop cata instructions
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ module FileSystemItemCata =
|
|||||||
| Process__FileSystemItem of FileSystemItem
|
| Process__FileSystemItem of FileSystemItem
|
||||||
| FileSystemItem_Directory of string * int * int
|
| FileSystemItem_Directory of string * int * int
|
||||||
|
|
||||||
let private loop (cata : FileSystemCata<_>) (instructions : ResizeArray<Instruction>) =
|
let private loop (cata : FileSystemCata<'FileSystemItem>) (instructions : ResizeArray<Instruction>) =
|
||||||
let fileSystemItemStack = ResizeArray ()
|
let fileSystemItemStack = ResizeArray<'FileSystemItem> ()
|
||||||
|
|
||||||
while instructions.Count > 0 do
|
while instructions.Count > 0 do
|
||||||
let currentInstruction = instructions.[instructions.Count - 1]
|
let currentInstruction = instructions.[instructions.Count - 1]
|
||||||
@@ -108,8 +108,8 @@ module GiftCata =
|
|||||||
| Gift_Boxed
|
| Gift_Boxed
|
||||||
| Gift_WithACard of string
|
| Gift_WithACard of string
|
||||||
|
|
||||||
let private loop (cata : GiftCata<_>) (instructions : ResizeArray<Instruction>) =
|
let private loop (cata : GiftCata<'Gift>) (instructions : ResizeArray<Instruction>) =
|
||||||
let giftStack = ResizeArray ()
|
let giftStack = ResizeArray<'Gift> ()
|
||||||
|
|
||||||
while instructions.Count > 0 do
|
while instructions.Count > 0 do
|
||||||
let currentInstruction = instructions.[instructions.Count - 1]
|
let currentInstruction = instructions.[instructions.Count - 1]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -25,10 +26,11 @@ type internal PublicTypeMock =
|
|||||||
|
|
||||||
interface IPublicType with
|
interface IPublicType with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||||
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -49,10 +51,11 @@ type public PublicTypeInternalFalseMock =
|
|||||||
|
|
||||||
interface IPublicTypeInternalFalse with
|
interface IPublicTypeInternalFalse with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||||
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
member this.Mem3 (arg_0_0, arg_0_1) = this.Mem3 (arg_0_0, arg_0_1)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -71,9 +74,10 @@ type internal InternalTypeMock =
|
|||||||
|
|
||||||
interface InternalType with
|
interface InternalType with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -92,9 +96,10 @@ type private PrivateTypeMock =
|
|||||||
|
|
||||||
interface PrivateType with
|
interface PrivateType with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -113,9 +118,10 @@ type private PrivateTypeInternalFalseMock =
|
|||||||
|
|
||||||
interface PrivateTypeInternalFalse with
|
interface PrivateTypeInternalFalse with
|
||||||
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
member this.Mem1 (arg_0_0, arg_0_1) = this.Mem1 (arg_0_0, arg_0_1)
|
||||||
member this.Mem2 (arg_0_0) = this.Mem2 (arg_0_0)
|
member this.Mem2 arg_0_0 = this.Mem2 (arg_0_0)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -131,9 +137,10 @@ type internal VeryPublicTypeMock<'a, 'b> =
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface VeryPublicType<'a, 'b> with
|
interface VeryPublicType<'a, 'b> with
|
||||||
member this.Mem1 (arg_0_0) = this.Mem1 (arg_0_0)
|
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
|
||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
/// Mock record type for an interface
|
/// Mock record type for an interface
|
||||||
@@ -159,9 +166,9 @@ type internal CurriedMock<'a> =
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Curried<'a> with
|
interface Curried<'a> with
|
||||||
member this.Mem1 (arg_0_0) (arg_1_0) = this.Mem1 (arg_0_0) (arg_1_0)
|
member this.Mem1 arg_0_0 arg_1_0 = this.Mem1 (arg_0_0) (arg_1_0)
|
||||||
member this.Mem2 (arg_0_0, arg_0_1) (arg_1_0) = this.Mem2 (arg_0_0, arg_0_1) (arg_1_0)
|
member this.Mem2 (arg_0_0, arg_0_1) arg_1_0 = this.Mem2 (arg_0_0, arg_0_1) (arg_1_0)
|
||||||
member this.Mem3 ((arg_0_0, arg_0_1)) (arg_1_0) = this.Mem3 (arg_0_0, arg_0_1) (arg_1_0)
|
member this.Mem3 ((arg_0_0, arg_0_1)) arg_1_0 = this.Mem3 (arg_0_0, arg_0_1) (arg_1_0)
|
||||||
|
|
||||||
member this.Mem4 ((arg_0_0, arg_0_1)) ((arg_1_0, arg_1_1)) =
|
member this.Mem4 ((arg_0_0, arg_0_1)) ((arg_1_0, arg_1_1)) =
|
||||||
this.Mem4 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
this.Mem4 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
||||||
@@ -171,3 +178,31 @@ type internal CurriedMock<'a> =
|
|||||||
|
|
||||||
member this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1) =
|
member this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1) =
|
||||||
this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
this.Mem6 (arg_0_0, arg_0_1) (arg_1_0, arg_1_1)
|
||||||
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
/// Mock record type for an interface
|
||||||
|
type internal TypeWithInterfaceMock =
|
||||||
|
{
|
||||||
|
/// Implementation of IDisposable.Dispose
|
||||||
|
Dispose : unit -> unit
|
||||||
|
Mem1 : string option -> string[] Async
|
||||||
|
Mem2 : unit -> string[] Async
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An implementation where every method throws.
|
||||||
|
static member Empty : TypeWithInterfaceMock =
|
||||||
|
{
|
||||||
|
Dispose = (fun _ -> ())
|
||||||
|
Mem1 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
|
Mem2 = (fun x -> raise (System.NotImplementedException "Unimplemented mock function"))
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TypeWithInterface with
|
||||||
|
member this.Mem1 arg_0_0 = this.Mem1 (arg_0_0)
|
||||||
|
member this.Mem2 () = this.Mem2 (())
|
||||||
|
|
||||||
|
interface System.IDisposable with
|
||||||
|
member this.Dispose () : unit = this.Dispose ()
|
||||||
|
|||||||
@@ -288,7 +288,52 @@ module PureGymApi =
|
|||||||
| v -> v),
|
| v -> v),
|
||||||
System.Uri (
|
System.Uri (
|
||||||
("/v2/gymSessions/member"
|
("/v2/gymSessions/member"
|
||||||
+ "?fromDate="
|
+ (if "/v2/gymSessions/member".IndexOf (char 63) > 0 then
|
||||||
|
"&"
|
||||||
|
else
|
||||||
|
"?")
|
||||||
|
+ "fromDate="
|
||||||
|
+ ((fromDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)
|
||||||
|
+ "&toDate="
|
||||||
|
+ ((toDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)),
|
||||||
|
System.UriKind.Relative
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
let httpMessage =
|
||||||
|
new System.Net.Http.HttpRequestMessage (
|
||||||
|
Method = System.Net.Http.HttpMethod.Get,
|
||||||
|
RequestUri = uri
|
||||||
|
)
|
||||||
|
|
||||||
|
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
|
||||||
|
let response = response.EnsureSuccessStatusCode ()
|
||||||
|
let! responseStream = response.Content.ReadAsStreamAsync ct |> Async.AwaitTask
|
||||||
|
|
||||||
|
let! jsonNode =
|
||||||
|
System.Text.Json.Nodes.JsonNode.ParseAsync (responseStream, cancellationToken = ct)
|
||||||
|
|> Async.AwaitTask
|
||||||
|
|
||||||
|
return Sessions.jsonParse jsonNode
|
||||||
|
}
|
||||||
|
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
||||||
|
|
||||||
|
member _.GetSessionsWithQuery (fromDate : DateOnly, toDate : DateOnly, ct : CancellationToken option) =
|
||||||
|
async {
|
||||||
|
let! ct = Async.CancellationToken
|
||||||
|
|
||||||
|
let uri =
|
||||||
|
System.Uri (
|
||||||
|
(match client.BaseAddress with
|
||||||
|
| null -> System.Uri "https://whatnot.com"
|
||||||
|
| v -> v),
|
||||||
|
System.Uri (
|
||||||
|
("/v2/gymSessions/member?foo=1"
|
||||||
|
+ (if "/v2/gymSessions/member?foo=1".IndexOf (char 63) > 0 then
|
||||||
|
"&"
|
||||||
|
else
|
||||||
|
"?")
|
||||||
|
+ "fromDate="
|
||||||
+ ((fromDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)
|
+ ((fromDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)
|
||||||
+ "&toDate="
|
+ "&toDate="
|
||||||
+ ((toDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)),
|
+ ((toDate.ToString "yyyy-MM-dd") |> System.Web.HttpUtility.UrlEncode)),
|
||||||
@@ -1140,6 +1185,69 @@ module ApiWithHeaders =
|
|||||||
member _.SomeHeader : string = someHeader ()
|
member _.SomeHeader : string = someHeader ()
|
||||||
member _.SomeOtherHeader : int = someOtherHeader ()
|
member _.SomeOtherHeader : int = someOtherHeader ()
|
||||||
|
|
||||||
|
member this.GetPathParam (parameter : string, ct : CancellationToken option) =
|
||||||
|
async {
|
||||||
|
let! ct = Async.CancellationToken
|
||||||
|
|
||||||
|
let uri =
|
||||||
|
System.Uri (
|
||||||
|
(match client.BaseAddress with
|
||||||
|
| null ->
|
||||||
|
raise (
|
||||||
|
System.ArgumentNullException (
|
||||||
|
nameof (client.BaseAddress),
|
||||||
|
"No base address was supplied on the type, and no BaseAddress was on the HttpClient."
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| v -> v),
|
||||||
|
System.Uri (
|
||||||
|
"endpoint/{param}"
|
||||||
|
.Replace ("{param}", parameter.ToString () |> System.Web.HttpUtility.UrlEncode),
|
||||||
|
System.UriKind.Relative
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
let httpMessage =
|
||||||
|
new System.Net.Http.HttpRequestMessage (
|
||||||
|
Method = System.Net.Http.HttpMethod.Get,
|
||||||
|
RequestUri = uri
|
||||||
|
)
|
||||||
|
|
||||||
|
do httpMessage.Headers.Add ("X-Foo", this.SomeHeader.ToString ())
|
||||||
|
do httpMessage.Headers.Add ("Authorization", this.SomeOtherHeader.ToString ())
|
||||||
|
do httpMessage.Headers.Add ("Header-Name", "Header-Value")
|
||||||
|
let! response = client.SendAsync (httpMessage, ct) |> Async.AwaitTask
|
||||||
|
let response = response.EnsureSuccessStatusCode ()
|
||||||
|
let! responseString = response.Content.ReadAsStringAsync ct |> Async.AwaitTask
|
||||||
|
return responseString
|
||||||
|
}
|
||||||
|
|> (fun a -> Async.StartAsTask (a, ?cancellationToken = ct))
|
||||||
|
}
|
||||||
|
namespace PureGym
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Threading
|
||||||
|
open System.Threading.Tasks
|
||||||
|
open System.IO
|
||||||
|
open System.Net
|
||||||
|
open System.Net.Http
|
||||||
|
open RestEase
|
||||||
|
|
||||||
|
/// Module for constructing a REST client.
|
||||||
|
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module ApiWithHeaders2 =
|
||||||
|
/// Create a REST client. The input functions will be re-evaluated on every HTTP request to obtain the required values for the corresponding header properties.
|
||||||
|
let make
|
||||||
|
(someHeader : unit -> string)
|
||||||
|
(someOtherHeader : unit -> int)
|
||||||
|
(client : System.Net.Http.HttpClient)
|
||||||
|
: IApiWithHeaders2
|
||||||
|
=
|
||||||
|
{ new IApiWithHeaders2 with
|
||||||
|
member _.SomeHeader : string = someHeader ()
|
||||||
|
member _.SomeOtherHeader : int = someOtherHeader ()
|
||||||
|
|
||||||
member this.GetPathParam (parameter : string, ct : CancellationToken option) =
|
member this.GetPathParam (parameter : string, ct : CancellationToken option) =
|
||||||
async {
|
async {
|
||||||
let! ct = Async.CancellationToken
|
let! ct = Async.CancellationToken
|
||||||
|
|||||||
19
ConsumePlugin/List.fs
Normal file
19
ConsumePlugin/List.fs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
namespace ConsumePlugin
|
||||||
|
|
||||||
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
[<CreateCatamorphism "MyListCata">]
|
||||||
|
type MyList<'a> =
|
||||||
|
| Nil
|
||||||
|
| Cons of ConsCase<'a>
|
||||||
|
|
||||||
|
and ConsCase<'a> =
|
||||||
|
{
|
||||||
|
Head : 'a
|
||||||
|
Tail : MyList<'a>
|
||||||
|
}
|
||||||
|
|
||||||
|
[<CreateCatamorphism "MyList2Cata">]
|
||||||
|
type MyList2<'a> =
|
||||||
|
| Nil
|
||||||
|
| Cons of 'a * MyList2<'a>
|
||||||
118
ConsumePlugin/ListCata.fs
Normal file
118
ConsumePlugin/ListCata.fs
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// This code was generated by myriad.
|
||||||
|
// Changes to this file will be lost when the code is regenerated.
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace ConsumePlugin
|
||||||
|
|
||||||
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
/// Description of how to combine cases during a fold
|
||||||
|
type MyListCataCase<'a, 'MyList> =
|
||||||
|
/// How to operate on the Nil case
|
||||||
|
abstract Nil : 'MyList
|
||||||
|
/// How to operate on the Cons case
|
||||||
|
abstract Cons : head : 'a -> tail : 'MyList -> 'MyList
|
||||||
|
|
||||||
|
/// Specifies how to perform a fold (catamorphism) over the type MyList and its friends.
|
||||||
|
type MyListCata<'a, 'MyList> =
|
||||||
|
{
|
||||||
|
/// How to perform a fold (catamorphism) over the type MyList
|
||||||
|
MyList : MyListCataCase<'a, 'MyList>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Methods to perform a catamorphism over the type MyList
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module MyListCata =
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
type private Instruction<'a> =
|
||||||
|
| Process__MyList of MyList<'a>
|
||||||
|
| MyList_Cons of 'a
|
||||||
|
|
||||||
|
let private loop (cata : MyListCata<'a, 'MyList>) (instructions : ResizeArray<Instruction<'a>>) =
|
||||||
|
let myListStack = ResizeArray<'MyList> ()
|
||||||
|
|
||||||
|
while instructions.Count > 0 do
|
||||||
|
let currentInstruction = instructions.[instructions.Count - 1]
|
||||||
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
|
match currentInstruction with
|
||||||
|
| Instruction.Process__MyList x ->
|
||||||
|
match x with
|
||||||
|
| MyList.Nil -> cata.MyList.Nil |> myListStack.Add
|
||||||
|
| MyList.Cons ({
|
||||||
|
Head = head
|
||||||
|
Tail = tail
|
||||||
|
}) ->
|
||||||
|
instructions.Add (Instruction.MyList_Cons (head))
|
||||||
|
instructions.Add (Instruction.Process__MyList tail)
|
||||||
|
| Instruction.MyList_Cons (head) ->
|
||||||
|
let tail = myListStack.[myListStack.Count - 1]
|
||||||
|
myListStack.RemoveAt (myListStack.Count - 1)
|
||||||
|
cata.MyList.Cons head tail |> myListStack.Add
|
||||||
|
|
||||||
|
myListStack
|
||||||
|
|
||||||
|
/// Execute the catamorphism.
|
||||||
|
let runMyList (cata : MyListCata<'a, 'MyListRet>) (x : MyList<'a>) : 'MyListRet =
|
||||||
|
let instructions = ResizeArray ()
|
||||||
|
instructions.Add (Instruction.Process__MyList x)
|
||||||
|
let myListRetStack = loop cata instructions
|
||||||
|
Seq.exactlyOne myListRetStack
|
||||||
|
namespace ConsumePlugin
|
||||||
|
|
||||||
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
/// Description of how to combine cases during a fold
|
||||||
|
type MyList2CataCase<'a, 'MyList2> =
|
||||||
|
/// How to operate on the Nil case
|
||||||
|
abstract Nil : 'MyList2
|
||||||
|
/// How to operate on the Cons case
|
||||||
|
abstract Cons : 'a -> 'MyList2 -> 'MyList2
|
||||||
|
|
||||||
|
/// Specifies how to perform a fold (catamorphism) over the type MyList2 and its friends.
|
||||||
|
type MyList2Cata<'a, 'MyList2> =
|
||||||
|
{
|
||||||
|
/// How to perform a fold (catamorphism) over the type MyList2
|
||||||
|
MyList2 : MyList2CataCase<'a, 'MyList2>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Methods to perform a catamorphism over the type MyList2
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module MyList2Cata =
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
type private Instruction<'a> =
|
||||||
|
| Process__MyList2 of MyList2<'a>
|
||||||
|
| MyList2_Cons of 'a
|
||||||
|
|
||||||
|
let private loop (cata : MyList2Cata<'a, 'MyList2>) (instructions : ResizeArray<Instruction<'a>>) =
|
||||||
|
let myList2Stack = ResizeArray<'MyList2> ()
|
||||||
|
|
||||||
|
while instructions.Count > 0 do
|
||||||
|
let currentInstruction = instructions.[instructions.Count - 1]
|
||||||
|
instructions.RemoveAt (instructions.Count - 1)
|
||||||
|
|
||||||
|
match currentInstruction with
|
||||||
|
| Instruction.Process__MyList2 x ->
|
||||||
|
match x with
|
||||||
|
| MyList2.Nil -> cata.MyList2.Nil |> myList2Stack.Add
|
||||||
|
| MyList2.Cons (arg0_0, arg1_0) ->
|
||||||
|
instructions.Add (Instruction.MyList2_Cons (arg0_0))
|
||||||
|
instructions.Add (Instruction.Process__MyList2 arg1_0)
|
||||||
|
| Instruction.MyList2_Cons (arg0_0) ->
|
||||||
|
let arg1_0 = myList2Stack.[myList2Stack.Count - 1]
|
||||||
|
myList2Stack.RemoveAt (myList2Stack.Count - 1)
|
||||||
|
cata.MyList2.Cons arg0_0 arg1_0 |> myList2Stack.Add
|
||||||
|
|
||||||
|
myList2Stack
|
||||||
|
|
||||||
|
/// Execute the catamorphism.
|
||||||
|
let runMyList2 (cata : MyList2Cata<'a, 'MyList2Ret>) (x : MyList2<'a>) : 'MyList2Ret =
|
||||||
|
let instructions = ResizeArray ()
|
||||||
|
instructions.Add (Instruction.Process__MyList2 x)
|
||||||
|
let myList2RetStack = loop cata instructions
|
||||||
|
Seq.exactlyOne myList2RetStack
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
namespace SomeNamespace
|
namespace SomeNamespace
|
||||||
|
|
||||||
|
open System
|
||||||
open WoofWare.Myriad.Plugins
|
open WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
[<GenerateMock>]
|
[<GenerateMock>]
|
||||||
@@ -41,3 +42,9 @@ type Curried<'a> =
|
|||||||
abstract Mem4 : (int * string) -> ('a * int) -> string
|
abstract Mem4 : (int * string) -> ('a * int) -> string
|
||||||
abstract Mem5 : x : int * string -> ('a * int) -> string
|
abstract Mem5 : x : int * string -> ('a * int) -> string
|
||||||
abstract Mem6 : int * string -> y : 'a * int -> string
|
abstract Mem6 : int * string -> y : 'a * int -> string
|
||||||
|
|
||||||
|
[<GenerateMock>]
|
||||||
|
type TypeWithInterface =
|
||||||
|
inherit IDisposable
|
||||||
|
abstract Mem1 : string option -> string[] Async
|
||||||
|
abstract Mem2 : unit -> string[] Async
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ type IPureGymApi =
|
|||||||
abstract GetSessions :
|
abstract GetSessions :
|
||||||
[<Query>] fromDate : DateOnly * [<Query>] toDate : DateOnly * ?ct : CancellationToken -> Task<Sessions>
|
[<Query>] fromDate : DateOnly * [<Query>] toDate : DateOnly * ?ct : CancellationToken -> Task<Sessions>
|
||||||
|
|
||||||
|
[<Get "/v2/gymSessions/member?foo=1">]
|
||||||
|
abstract GetSessionsWithQuery :
|
||||||
|
[<Query>] fromDate : DateOnly * [<Query>] toDate : DateOnly * ?ct : CancellationToken -> Task<Sessions>
|
||||||
|
|
||||||
// An example from RestEase's own docs
|
// An example from RestEase's own docs
|
||||||
[<Post "users/new">]
|
[<Post "users/new">]
|
||||||
abstract CreateUserString : [<Body>] user : string * ?ct : CancellationToken -> Task<string>
|
abstract CreateUserString : [<Body>] user : string * ?ct : CancellationToken -> Task<string>
|
||||||
@@ -120,7 +124,8 @@ type internal IApiWithoutBaseAddress =
|
|||||||
[<WoofWare.Myriad.Plugins.HttpClient>]
|
[<WoofWare.Myriad.Plugins.HttpClient>]
|
||||||
[<BasePath "foo">]
|
[<BasePath "foo">]
|
||||||
type IApiWithBasePath =
|
type IApiWithBasePath =
|
||||||
[<Get "endpoint/{param}">]
|
// Example where we use the bundled attributes rather than RestEase's
|
||||||
|
[<WoofWare.Myriad.Plugins.RestEase.Get "endpoint/{param}">]
|
||||||
abstract GetPathParam : [<Path "param">] parameter : string * ?cancellationToken : CancellationToken -> Task<string>
|
abstract GetPathParam : [<Path "param">] parameter : string * ?cancellationToken : CancellationToken -> Task<string>
|
||||||
|
|
||||||
[<WoofWare.Myriad.Plugins.HttpClient>]
|
[<WoofWare.Myriad.Plugins.HttpClient>]
|
||||||
@@ -141,3 +146,16 @@ type IApiWithHeaders =
|
|||||||
|
|
||||||
[<Get "endpoint/{param}">]
|
[<Get "endpoint/{param}">]
|
||||||
abstract GetPathParam : [<Path "param">] parameter : string * ?ct : CancellationToken -> Task<string>
|
abstract GetPathParam : [<Path "param">] parameter : string * ?ct : CancellationToken -> Task<string>
|
||||||
|
|
||||||
|
[<WoofWare.Myriad.Plugins.HttpClient>]
|
||||||
|
[<WoofWare.Myriad.Plugins.RestEase.Header("Header-Name", "Header-Value")>]
|
||||||
|
type IApiWithHeaders2 =
|
||||||
|
[<WoofWare.Myriad.Plugins.RestEase.Header "X-Foo">]
|
||||||
|
abstract SomeHeader : string
|
||||||
|
|
||||||
|
[<WoofWare.Myriad.Plugins.RestEase.Header "Authorization">]
|
||||||
|
abstract SomeOtherHeader : int
|
||||||
|
|
||||||
|
[<Get "endpoint/{param}">]
|
||||||
|
abstract GetPathParam :
|
||||||
|
[<WoofWare.Myriad.Plugins.RestEase.Path "param">] parameter : string * ?ct : CancellationToken -> Task<string>
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -332,7 +332,7 @@ thereby allowing the programmer to use F#'s record-update syntax.
|
|||||||
Takes a collection of mutually recursive discriminated unions:
|
Takes a collection of mutually recursive discriminated unions:
|
||||||
|
|
||||||
```fsharp
|
```fsharp
|
||||||
[<CreateCatamorphism>]
|
[<CreateCatamorphism "MyCata">]
|
||||||
type Expr =
|
type Expr =
|
||||||
| Const of Const
|
| Const of Const
|
||||||
| Pair of Expr * Expr * PairOpKind
|
| Pair of Expr * Expr * PairOpKind
|
||||||
@@ -356,7 +356,7 @@ type ExprBuilderCata<'Expr, 'ExprBuilder> =
|
|||||||
abstract Child : 'ExprBuilder -> 'ExprBuilder
|
abstract Child : 'ExprBuilder -> 'ExprBuilder
|
||||||
abstract Parent : 'Expr -> 'ExprBuilder
|
abstract Parent : 'Expr -> 'ExprBuilder
|
||||||
|
|
||||||
type Cata<'Expr, 'ExprBuilder> =
|
type MyCata<'Expr, 'ExprBuilder> =
|
||||||
{
|
{
|
||||||
Expr : ExprCata<'Expr, 'ExprBuilder>
|
Expr : ExprCata<'Expr, 'ExprBuilder>
|
||||||
ExprBuilder : ExprBuilderCata<'Expr, 'ExprBuilder>
|
ExprBuilder : ExprBuilderCata<'Expr, 'ExprBuilder>
|
||||||
@@ -364,10 +364,10 @@ type Cata<'Expr, 'ExprBuilder> =
|
|||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module ExprCata =
|
module ExprCata =
|
||||||
let runExpr (cata : Cata<'ExprRet, 'ExprBuilderRet>) (x : Expr) : 'ExprRet =
|
let runExpr (cata : MyCata<'ExprRet, 'ExprBuilderRet>) (x : Expr) : 'ExprRet =
|
||||||
failwith "this is implemented"
|
failwith "this is implemented"
|
||||||
|
|
||||||
let runExprBuilder (cata : Cata<'ExprRet, 'ExprBuilderRet>) (x : ExprBuilder) : 'ExprBuilderRet =
|
let runExprBuilder (cata : MyCata<'ExprRet, 'ExprBuilderRet>) (x : ExprBuilder) : 'ExprBuilderRet =
|
||||||
failwith "this is implemented"
|
failwith "this is implemented"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -381,6 +381,10 @@ and then each time you only plug in what you want to do.
|
|||||||
* Mutually recursive DUs are supported (as in the example above).
|
* Mutually recursive DUs are supported (as in the example above).
|
||||||
Every DU in a recursive `type Foo... and Bar...` knot will be given an appropriate cata, as long as any one of those DUs has the `[<CreateCatamorphism>]` attribute.
|
Every DU in a recursive `type Foo... and Bar...` knot will be given an appropriate cata, as long as any one of those DUs has the `[<CreateCatamorphism>]` attribute.
|
||||||
* There is *limited* support for records and for lists.
|
* There is *limited* support for records and for lists.
|
||||||
|
* There is *extremely brittle* support for generics in the DUs you are cata'ing over.
|
||||||
|
It is based on the names of the generic parameters, so you must ensure that generic parameters with the same name have the same meaning across the various cases in your recursive knot of DUs.
|
||||||
|
(If you overstep the bounds of what this generator can do, you will get compile-time errors, e.g. with generics being constrained to each other's values.)
|
||||||
|
See the [List tests](./WoofWare.Myriad.Plugins.Test/TestCataGenerator/TestMyList2.fs) for an example, where we re-implement `FSharpList<'a>`.
|
||||||
|
|
||||||
### Limitations
|
### Limitations
|
||||||
|
|
||||||
|
|||||||
63
WoofWare.Myriad.Plugins.Attributes/RestEase.fs
Normal file
63
WoofWare.Myriad.Plugins.Attributes/RestEase.fs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
|
open System
|
||||||
|
|
||||||
|
/// Module containing duplicates of the supported RestEase attributes, in case you don't want
|
||||||
|
/// to take a dependency on RestEase.
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module RestEase =
|
||||||
|
/// Indicates that a method represents an HTTP Get query to the specified endpoint.
|
||||||
|
type GetAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Post query to the specified endpoint.
|
||||||
|
type PostAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Delete query to the specified endpoint.
|
||||||
|
type DeleteAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Head query to the specified endpoint.
|
||||||
|
type HeadAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Options query to the specified endpoint.
|
||||||
|
type OptionsAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Put query to the specified endpoint.
|
||||||
|
type PutAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Patch query to the specified endpoint.
|
||||||
|
type PatchAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that a method represents an HTTP Trace query to the specified endpoint.
|
||||||
|
type TraceAttribute (path : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that this argument to a method is interpolated into the HTTP request at runtime
|
||||||
|
/// by setting a query parameter (with the given name) to the value of the annotated argument.
|
||||||
|
type QueryAttribute (paramName : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that this interface represents a REST client which accesses an API whose paths are
|
||||||
|
/// all relative to the given address.
|
||||||
|
type BaseAddressAttribute (addr : string) =
|
||||||
|
inherit Attribute ()
|
||||||
|
|
||||||
|
/// Indicates that this interface member causes the interface to set a header with the given name,
|
||||||
|
/// whose value is obtained whenever required by a fresh call to the interface member.
|
||||||
|
type HeaderAttribute (header : string, value : string option) =
|
||||||
|
inherit Attribute ()
|
||||||
|
new (header : string) = HeaderAttribute (header, None)
|
||||||
|
new (header : string, value : string) = HeaderAttribute (header, Some value)
|
||||||
|
|
||||||
|
/// Indicates that this argument to a method is interpolated into the request path at runtime
|
||||||
|
/// by writing it into the templated string that specifies the HTTP query e.g. in the `[<Get "/foo/{template}">]`.
|
||||||
|
type PathAttribute (path : string option) =
|
||||||
|
inherit Attribute ()
|
||||||
|
new (path : string) = PathAttribute (Some path)
|
||||||
|
new () = PathAttribute None
|
||||||
@@ -19,3 +19,32 @@ WoofWare.Myriad.Plugins.JsonSerializeAttribute.DefaultIsExtensionMethod [static
|
|||||||
WoofWare.Myriad.Plugins.JsonSerializeAttribute.get_DefaultIsExtensionMethod [static method]: unit -> bool
|
WoofWare.Myriad.Plugins.JsonSerializeAttribute.get_DefaultIsExtensionMethod [static method]: unit -> bool
|
||||||
WoofWare.Myriad.Plugins.RemoveOptionsAttribute inherit System.Attribute
|
WoofWare.Myriad.Plugins.RemoveOptionsAttribute inherit System.Attribute
|
||||||
WoofWare.Myriad.Plugins.RemoveOptionsAttribute..ctor [constructor]: unit
|
WoofWare.Myriad.Plugins.RemoveOptionsAttribute..ctor [constructor]: unit
|
||||||
|
WoofWare.Myriad.Plugins.RestEase inherit obj
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+BaseAddressAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+BaseAddressAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+DeleteAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+DeleteAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+GetAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+GetAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+HeadAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+HeadAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+HeaderAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+HeaderAttribute..ctor [constructor]: (string, string option)
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+HeaderAttribute..ctor [constructor]: (string, string)
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+HeaderAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+OptionsAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+OptionsAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PatchAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PatchAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PathAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PathAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PathAttribute..ctor [constructor]: string option
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PathAttribute..ctor [constructor]: unit
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PostAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PostAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PutAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+PutAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+QueryAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+QueryAttribute..ctor [constructor]: string
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+TraceAttribute inherit System.Attribute
|
||||||
|
WoofWare.Myriad.Plugins.RestEase+TraceAttribute..ctor [constructor]: string
|
||||||
@@ -11,11 +11,9 @@ module TestSurface =
|
|||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical assembly
|
let ``Ensure API surface has not been modified`` () = ApiSurface.assertIdentical assembly
|
||||||
|
|
||||||
(*
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Check version against remote`` () =
|
let ``Check version against remote`` () =
|
||||||
MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins.Attributes"
|
MonotonicVersion.validate assembly "WoofWare.Myriad.Plugins.Attributes"
|
||||||
*)
|
|
||||||
|
|
||||||
[<Test ; Explicit>]
|
[<Test ; Explicit>]
|
||||||
let ``Update API surface`` () =
|
let ``Update API surface`` () =
|
||||||
|
|||||||
@@ -12,9 +12,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ApiSurface" Version="4.0.28" />
|
<PackageReference Include="ApiSurface" Version="4.0.39" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0"/>
|
||||||
<PackageReference Include="NUnit" Version="3.13.3"/>
|
<PackageReference Include="NUnit" Version="4.1.0"/>
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Attributes.fs"/>
|
<Compile Include="Attributes.fs"/>
|
||||||
|
<Compile Include="RestEase.fs" />
|
||||||
<EmbeddedResource Include="version.json"/>
|
<EmbeddedResource Include="version.json"/>
|
||||||
<EmbeddedResource Include="SurfaceBaseline.txt"/>
|
<EmbeddedResource Include="SurfaceBaseline.txt"/>
|
||||||
<None Include="..\README.md">
|
<None Include="..\README.md">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"version": "2.2",
|
"version": "3.0",
|
||||||
"publicReleaseRefSpec": [
|
"publicReleaseRefSpec": [
|
||||||
"^refs/heads/main$"
|
"^refs/heads/main$"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -8,17 +8,17 @@ open FsCheck
|
|||||||
|
|
||||||
[<TestFixture>]
|
[<TestFixture>]
|
||||||
module TestCataGenerator =
|
module TestCataGenerator =
|
||||||
let idCata : TreeCata<_, _> =
|
let idCata<'a, 'b> : TreeCata<'a, 'b, _, _> =
|
||||||
{
|
{
|
||||||
Tree =
|
Tree =
|
||||||
{ new TreeCataCase<_, _> with
|
{ new TreeCataCase<_, _, _, _> with
|
||||||
member _.Const x = Const x
|
member _.Const x y = Const (x, y)
|
||||||
member _.Pair x y z = Pair (x, y, z)
|
member _.Pair x y z = Pair (x, y, z)
|
||||||
member _.Sequential xs = Sequential xs
|
member _.Sequential xs = Sequential xs
|
||||||
member _.Builder x b = Builder (x, b)
|
member _.Builder x b = Builder (x, b)
|
||||||
}
|
}
|
||||||
TreeBuilder =
|
TreeBuilder =
|
||||||
{ new TreeBuilderCataCase<_, _> with
|
{ new TreeBuilderCataCase<_, _, _, _> with
|
||||||
member _.Child x = Child x
|
member _.Child x = Child x
|
||||||
member _.Parent x = Parent x
|
member _.Parent x = Parent x
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ module TestCataGenerator =
|
|||||||
[<Test>]
|
[<Test>]
|
||||||
let ``Example`` () =
|
let ``Example`` () =
|
||||||
let x =
|
let x =
|
||||||
Tree.Pair (Tree.Const (Const.Int 0), Tree.Const (Const.String ""), PairOpKind.ThenDoSeq)
|
Tree.Pair (Tree.Const (Const.Verbatim 0, "hi"), Tree.Const (Const.String "", "bye"), PairOpKind.ThenDoSeq)
|
||||||
|
|
||||||
TreeCata.runTree idCata x |> shouldEqual x
|
TreeCata.runTree idCata x |> shouldEqual x
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ module TestCataGenerator =
|
|||||||
let ``Cata works`` () =
|
let ``Cata works`` () =
|
||||||
let builderCases = ref 0
|
let builderCases = ref 0
|
||||||
|
|
||||||
let property (x : Tree) =
|
let property (x : Tree<int, string>) =
|
||||||
match x with
|
match x with
|
||||||
| Tree.Builder _ -> Interlocked.Increment builderCases |> ignore
|
| Tree.Builder _ -> Interlocked.Increment builderCases |> ignore
|
||||||
| _ -> ()
|
| _ -> ()
|
||||||
|
|||||||
77
WoofWare.Myriad.Plugins.Test/TestCataGenerator/TestMyList.fs
Normal file
77
WoofWare.Myriad.Plugins.Test/TestCataGenerator/TestMyList.fs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
namespace WoofWare.Myriad.Plugins.Test
|
||||||
|
|
||||||
|
open NUnit.Framework
|
||||||
|
open FsCheck
|
||||||
|
open FsUnitTyped
|
||||||
|
open ConsumePlugin
|
||||||
|
|
||||||
|
[<TestFixture>]
|
||||||
|
module TestMyList =
|
||||||
|
|
||||||
|
let idCata<'a> : MyListCata<'a, _> =
|
||||||
|
{
|
||||||
|
MyList =
|
||||||
|
{ new MyListCataCase<'a, _> with
|
||||||
|
member _.Nil = MyList.Nil
|
||||||
|
|
||||||
|
member _.Cons head tail =
|
||||||
|
MyList.Cons
|
||||||
|
{
|
||||||
|
Head = head
|
||||||
|
Tail = tail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``Cata works`` () =
|
||||||
|
let property (x : MyList<int>) = MyListCata.runMyList idCata x = x
|
||||||
|
|
||||||
|
Check.QuickThrowOnFailure property
|
||||||
|
|
||||||
|
let toListCata<'a> =
|
||||||
|
{
|
||||||
|
MyList =
|
||||||
|
{ new MyListCataCase<'a, 'a list> with
|
||||||
|
member _.Nil = []
|
||||||
|
member _.Cons (head : 'a) (tail : 'a list) = head :: tail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let toListViaCata<'a> (l : MyList<'a>) : 'a list = MyListCata.runMyList toListCata l
|
||||||
|
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``Example of a fold converting to a new data structure`` () =
|
||||||
|
let rec toListNaive (l : MyList<int>) : int list =
|
||||||
|
match l with
|
||||||
|
| MyList.Nil -> []
|
||||||
|
| MyList.Cons consCell -> consCell.Head :: toListNaive consCell.Tail
|
||||||
|
|
||||||
|
Check.QuickThrowOnFailure (fun l -> toListNaive l = toListViaCata l)
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``Example of equivalence with FoldBack`` () =
|
||||||
|
let baseCase = 0L
|
||||||
|
let atLeaf (head : int) (tail : int64) : int64 = int64 head + tail
|
||||||
|
|
||||||
|
let sumCata =
|
||||||
|
{
|
||||||
|
MyList =
|
||||||
|
{ new MyListCataCase<int, int64> with
|
||||||
|
member _.Nil = baseCase
|
||||||
|
member _.Cons (head : int) (tail : int64) = atLeaf head tail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let viaCata (l : MyList<int>) : int64 = MyListCata.runMyList sumCata l
|
||||||
|
|
||||||
|
let viaFold (l : MyList<int>) : int64 =
|
||||||
|
// choose your favourite "to list" method - here I use the cata
|
||||||
|
// but that could have been done naively
|
||||||
|
(toListViaCata l, baseCase)
|
||||||
|
||> List.foldBack (fun elt state -> atLeaf elt state)
|
||||||
|
|
||||||
|
let property (l : MyList<int>) = viaCata l = viaFold l
|
||||||
|
|
||||||
|
Check.QuickThrowOnFailure property
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
namespace WoofWare.Myriad.Plugins.Test
|
||||||
|
|
||||||
|
open NUnit.Framework
|
||||||
|
open FsCheck
|
||||||
|
open FsUnitTyped
|
||||||
|
open ConsumePlugin
|
||||||
|
|
||||||
|
[<TestFixture>]
|
||||||
|
module TestMyList2 =
|
||||||
|
|
||||||
|
let idCata<'a> : MyList2Cata<'a, _> =
|
||||||
|
{
|
||||||
|
MyList2 =
|
||||||
|
{ new MyList2CataCase<'a, _> with
|
||||||
|
member _.Nil = MyList2.Nil
|
||||||
|
|
||||||
|
member _.Cons (head : 'a) (tail : MyList2<'a>) = MyList2.Cons (head, tail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``Cata works`` () =
|
||||||
|
let property (x : MyList2<int>) = MyList2Cata.runMyList2 idCata x = x
|
||||||
|
|
||||||
|
Check.QuickThrowOnFailure property
|
||||||
@@ -234,6 +234,33 @@ module TestPureGymRestApi =
|
|||||||
|
|
||||||
api.GetSessions(startDate, endDate).Result |> shouldEqual expected
|
api.GetSessions(startDate, endDate).Result |> shouldEqual expected
|
||||||
|
|
||||||
|
[<TestCaseSource(nameof sessionsCases)>]
|
||||||
|
let ``Test GetSessionsWithQuery``
|
||||||
|
(baseUri : Uri, (startDate : DateOnly, (endDate : DateOnly, (json : string, expected : Sessions))))
|
||||||
|
=
|
||||||
|
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
||||||
|
async {
|
||||||
|
message.Method |> shouldEqual HttpMethod.Get
|
||||||
|
|
||||||
|
// This one is specified as being absolute, in its attribute on the IPureGymApi type
|
||||||
|
let expectedUri =
|
||||||
|
let fromDate = dateOnlyToString startDate
|
||||||
|
let toDate = dateOnlyToString endDate
|
||||||
|
$"https://example.com/v2/gymSessions/member?foo=1&fromDate=%s{fromDate}&toDate=%s{toDate}"
|
||||||
|
|
||||||
|
message.RequestUri.ToString () |> shouldEqual expectedUri
|
||||||
|
|
||||||
|
let content = new StringContent (json)
|
||||||
|
let resp = new HttpResponseMessage (HttpStatusCode.OK)
|
||||||
|
resp.Content <- content
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
use client = HttpClientMock.make baseUri proc
|
||||||
|
let api = PureGymApi.make client
|
||||||
|
|
||||||
|
api.GetSessionsWithQuery(startDate, endDate).Result |> shouldEqual expected
|
||||||
|
|
||||||
[<Test>]
|
[<Test>]
|
||||||
let ``URI example`` () =
|
let ``URI example`` () =
|
||||||
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
let proc (message : HttpRequestMessage) : HttpResponseMessage Async =
|
||||||
|
|||||||
@@ -25,19 +25,20 @@
|
|||||||
<Compile Include="TestCataGenerator\TestCataGenerator.fs" />
|
<Compile Include="TestCataGenerator\TestCataGenerator.fs" />
|
||||||
<Compile Include="TestCataGenerator\TestDirectory.fs" />
|
<Compile Include="TestCataGenerator\TestDirectory.fs" />
|
||||||
<Compile Include="TestCataGenerator\TestGift.fs" />
|
<Compile Include="TestCataGenerator\TestGift.fs" />
|
||||||
|
<Compile Include="TestCataGenerator\TestMyList.fs" />
|
||||||
|
<Compile Include="TestCataGenerator\TestMyList2.fs" />
|
||||||
<Compile Include="TestRemoveOptions.fs"/>
|
<Compile Include="TestRemoveOptions.fs"/>
|
||||||
<Compile Include="TestSurface.fs"/>
|
<Compile Include="TestSurface.fs"/>
|
||||||
<None Include="../.github/workflows/dotnet.yaml" />
|
<None Include="../.github/workflows/dotnet.yaml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ApiSurface" Version="4.0.28"/>
|
<PackageReference Include="ApiSurface" Version="4.0.39"/>
|
||||||
<PackageReference Include="FsCheck" Version="2.16.6"/>
|
<PackageReference Include="FsCheck" Version="2.16.6"/>
|
||||||
<PackageReference Include="FsUnit" Version="6.0.0"/>
|
<PackageReference Include="FsUnit" Version="6.0.0"/>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0"/>
|
||||||
<PackageReference Include="NUnit" Version="4.0.1"/>
|
<PackageReference Include="NUnit" Version="4.1.0"/>
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0"/>
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ type internal InterfaceType =
|
|||||||
{
|
{
|
||||||
Attributes : SynAttribute list
|
Attributes : SynAttribute list
|
||||||
Name : LongIdent
|
Name : LongIdent
|
||||||
|
Inherits : SynType list
|
||||||
Members : MemberInfo list
|
Members : MemberInfo list
|
||||||
Properties : PropertyInfo list
|
Properties : PropertyInfo list
|
||||||
Generics : SynTyparDecls option
|
Generics : SynTyparDecls option
|
||||||
@@ -76,6 +77,9 @@ type internal AdtNode =
|
|||||||
{
|
{
|
||||||
Type : SynType
|
Type : SynType
|
||||||
Name : Ident option
|
Name : Ident option
|
||||||
|
/// An ordered list, so you can look up any given generic within `this.Type`
|
||||||
|
/// to discover what its index is in the parent DU which defined it.
|
||||||
|
GenericsOfParent : SynTyparDecl list
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A DU is a sum of products (e.g. `type Thing = Foo of a * b`);
|
/// A DU is a sum of products (e.g. `type Thing = Foo of a * b`);
|
||||||
@@ -85,6 +89,10 @@ type internal AdtProduct =
|
|||||||
{
|
{
|
||||||
Name : SynIdent
|
Name : SynIdent
|
||||||
Fields : AdtNode list
|
Fields : AdtNode list
|
||||||
|
/// This AdtProduct represents a product in which there might be
|
||||||
|
/// some bound type parameters. This field lists the bound
|
||||||
|
/// type parameters in the order they appeared on the parent type.
|
||||||
|
Generics : SynTyparDecl list
|
||||||
}
|
}
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
@@ -124,6 +132,11 @@ module internal AstHelper =
|
|||||||
// TODO: consider Microsoft.FSharp.Option or whatever it is
|
// TODO: consider Microsoft.FSharp.Option or whatever it is
|
||||||
| _ -> false
|
| _ -> false
|
||||||
|
|
||||||
|
let isUnitIdent (ident : SynLongIdent) : bool =
|
||||||
|
match ident.LongIdent with
|
||||||
|
| [ i ] when System.String.Equals (i.idText, "unit", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
let isListIdent (ident : SynLongIdent) : bool =
|
let isListIdent (ident : SynLongIdent) : bool =
|
||||||
match ident.LongIdent with
|
match ident.LongIdent with
|
||||||
| [ i ] when System.String.Equals (i.idText, "list", System.StringComparison.OrdinalIgnoreCase) -> true
|
| [ i ] when System.String.Equals (i.idText, "list", System.StringComparison.OrdinalIgnoreCase) -> true
|
||||||
@@ -335,7 +348,18 @@ module internal AstHelper =
|
|||||||
}
|
}
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
}
|
}
|
||||||
| _ -> failwith $"Unrecognised args in interface method declaration: %+A{args}"
|
| arg ->
|
||||||
|
{
|
||||||
|
HasParen = false
|
||||||
|
Args =
|
||||||
|
{
|
||||||
|
Attributes = []
|
||||||
|
IsOptional = false
|
||||||
|
Id = None
|
||||||
|
Type = arg
|
||||||
|
}
|
||||||
|
|> List.singleton
|
||||||
|
}
|
||||||
|> fun ty ->
|
|> fun ty ->
|
||||||
{ ty with
|
{ ty with
|
||||||
HasParen = ty.HasParen || hasParen
|
HasParen = ty.HasParen || hasParen
|
||||||
@@ -379,30 +403,53 @@ module internal AstHelper =
|
|||||||
|
|
||||||
let attrs = attrs |> List.collect (fun s -> s.Attributes)
|
let attrs = attrs |> List.collect (fun s -> s.Attributes)
|
||||||
|
|
||||||
let members, properties =
|
let members, inherits =
|
||||||
match synTypeDefnRepr with
|
match synTypeDefnRepr with
|
||||||
| SynTypeDefnRepr.ObjectModel (_kind, members, _) ->
|
| SynTypeDefnRepr.ObjectModel (_kind, members, _) ->
|
||||||
members
|
members
|
||||||
|> List.map (fun defn ->
|
|> List.map (fun defn ->
|
||||||
match defn with
|
match defn with
|
||||||
| SynMemberDefn.AbstractSlot (slotSig, flags, _, _) -> parseMember slotSig flags
|
| SynMemberDefn.AbstractSlot (slotSig, flags, _, _) -> Choice1Of2 (parseMember slotSig flags)
|
||||||
|
| SynMemberDefn.Inherit (baseType, _asIdent, _) -> Choice2Of2 baseType
|
||||||
| _ -> failwith $"Unrecognised member definition: %+A{defn}"
|
| _ -> failwith $"Unrecognised member definition: %+A{defn}"
|
||||||
)
|
)
|
||||||
| _ -> failwith $"Unrecognised SynTypeDefnRepr for an interface type: %+A{synTypeDefnRepr}"
|
| _ -> failwith $"Unrecognised SynTypeDefnRepr for an interface type: %+A{synTypeDefnRepr}"
|
||||||
|> List.partitionChoice
|
|> List.partitionChoice
|
||||||
|
|
||||||
|
let members, properties = members |> List.partitionChoice
|
||||||
|
|
||||||
{
|
{
|
||||||
Members = members
|
Members = members
|
||||||
Properties = properties
|
Properties = properties
|
||||||
Name = interfaceName
|
Name = interfaceName
|
||||||
|
Inherits = inherits
|
||||||
Attributes = attrs
|
Attributes = attrs
|
||||||
Generics = typars
|
Generics = typars
|
||||||
Accessibility = accessibility
|
Accessibility = accessibility
|
||||||
}
|
}
|
||||||
|
|
||||||
let getUnionCases (SynTypeDefn.SynTypeDefn (_, repr, _, _, _, _)) : AdtProduct list =
|
let getUnionCases
|
||||||
|
(SynTypeDefn.SynTypeDefn (info, repr, _, _, _, _))
|
||||||
|
: AdtProduct list * SynTyparDecl list * SynAccess option
|
||||||
|
=
|
||||||
|
let typars, access =
|
||||||
|
match info with
|
||||||
|
| SynComponentInfo (_, typars, _, _, _, _, access, _) -> typars, access
|
||||||
|
|
||||||
|
let typars =
|
||||||
|
match typars with
|
||||||
|
| None -> []
|
||||||
|
| Some (SynTyparDecls.PrefixList (decls, _)) -> decls
|
||||||
|
| Some (SynTyparDecls.SinglePrefix (l, _)) -> [ l ]
|
||||||
|
| Some (SynTyparDecls.PostfixList (decls, constraints, _)) ->
|
||||||
|
if not constraints.IsEmpty then
|
||||||
|
failwith "Constrained type parameters not currently supported"
|
||||||
|
|
||||||
|
decls
|
||||||
|
|
||||||
match repr with
|
match repr with
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_, cases, _), _) ->
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_, cases, _), _) ->
|
||||||
|
let cases =
|
||||||
cases
|
cases
|
||||||
|> List.map (fun (SynUnionCase.SynUnionCase (_, ident, kind, _, _, _, _)) ->
|
|> List.map (fun (SynUnionCase.SynUnionCase (_, ident, kind, _, _, _, _)) ->
|
||||||
match kind with
|
match kind with
|
||||||
@@ -416,13 +463,30 @@ module internal AstHelper =
|
|||||||
{
|
{
|
||||||
Type = ty
|
Type = ty
|
||||||
Name = id
|
Name = id
|
||||||
|
GenericsOfParent = typars
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
Generics = typars
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cases, typars, access
|
||||||
| _ -> failwithf "Failed to get union cases for type that was: %+A" repr
|
| _ -> failwithf "Failed to get union cases for type that was: %+A" repr
|
||||||
|
|
||||||
let getRecordFields (SynTypeDefn.SynTypeDefn (_, repr, _, _, _, _)) : AdtNode list =
|
let getRecordFields (SynTypeDefn.SynTypeDefn (typeInfo, repr, _, _, _, _)) : AdtNode list =
|
||||||
|
let (SynComponentInfo.SynComponentInfo (typeParams = typars)) = typeInfo
|
||||||
|
|
||||||
|
let typars =
|
||||||
|
match typars with
|
||||||
|
| None -> []
|
||||||
|
| Some (SynTyparDecls.PrefixList (decls, _)) -> decls
|
||||||
|
| Some (SynTyparDecls.SinglePrefix (l, _)) -> [ l ]
|
||||||
|
| Some (SynTyparDecls.PostfixList (decls, constraints, _)) ->
|
||||||
|
if not constraints.IsEmpty then
|
||||||
|
failwith "Constrained type parameters not currently supported"
|
||||||
|
|
||||||
|
decls
|
||||||
|
|
||||||
match repr with
|
match repr with
|
||||||
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_, fields, _), _) ->
|
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_, fields, _), _) ->
|
||||||
fields
|
fields
|
||||||
@@ -430,6 +494,7 @@ module internal AstHelper =
|
|||||||
{
|
{
|
||||||
Name = ident
|
Name = ident
|
||||||
Type = ty
|
Type = ty
|
||||||
|
GenericsOfParent = typars
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
| _ -> failwithf "Failed to get record elements for type that was: %+A" repr
|
| _ -> failwithf "Failed to get record elements for type that was: %+A" repr
|
||||||
@@ -442,6 +507,11 @@ module internal SynTypePatterns =
|
|||||||
Some innerType
|
Some innerType
|
||||||
| _ -> None
|
| _ -> None
|
||||||
|
|
||||||
|
let (|UnitType|_|) (fieldType : SynType) : unit option =
|
||||||
|
match fieldType with
|
||||||
|
| SynType.LongIdent ident when AstHelper.isUnitIdent ident -> Some ()
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
let (|ListType|_|) (fieldType : SynType) =
|
let (|ListType|_|) (fieldType : SynType) =
|
||||||
match fieldType with
|
match fieldType with
|
||||||
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isListIdent ident ->
|
| SynType.App (SynType.LongIdent ident, _, [ innerType ], _, _, _, _) when AstHelper.isListIdent ident ->
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ module internal CataGenerator =
|
|||||||
/// The relationship this field has with the parent type (or the
|
/// The relationship this field has with the parent type (or the
|
||||||
/// recursive knot of parent types)
|
/// recursive knot of parent types)
|
||||||
Description : FieldDescription
|
Description : FieldDescription
|
||||||
|
/// Any generic parameters this field consumes.
|
||||||
|
/// This only makes sense in the context of a UnionAnalysis:
|
||||||
|
/// it is an index into the parent Union's collection of generic parameters.
|
||||||
|
RequiredGenerics : int list option
|
||||||
}
|
}
|
||||||
|
|
||||||
type CataUnionRecordField = (Ident * CataUnionBasicField) list
|
type CataUnionRecordField = (Ident * CataUnionBasicField) list
|
||||||
@@ -81,6 +85,8 @@ module internal CataGenerator =
|
|||||||
/// recursive knot), this is everything we need to know about it for the cata.
|
/// recursive knot), this is everything we need to know about it for the cata.
|
||||||
type UnionAnalysis =
|
type UnionAnalysis =
|
||||||
{
|
{
|
||||||
|
Accessibility : SynAccess option
|
||||||
|
Typars : SynTyparDecl list
|
||||||
/// The name of the stack we'll use for the results
|
/// The name of the stack we'll use for the results
|
||||||
/// of returning from a descent into this union type,
|
/// of returning from a descent into this union type,
|
||||||
/// when performing the cata
|
/// when performing the cata
|
||||||
@@ -112,28 +118,70 @@ module internal CataGenerator =
|
|||||||
/// Seq.exactlyOne {relevantTypar}Stack
|
/// Seq.exactlyOne {relevantTypar}Stack
|
||||||
let createRunFunction
|
let createRunFunction
|
||||||
(cataName : Ident)
|
(cataName : Ident)
|
||||||
(allTypars : SynType list)
|
(userProvidedTypars : SynTyparDecl list)
|
||||||
|
(allArtificialTypars : SynType list)
|
||||||
(relevantTypar : SynType)
|
(relevantTypar : SynType)
|
||||||
(unionType : SynTypeDefn)
|
(analysis : UnionAnalysis)
|
||||||
: SynBinding
|
: SynBinding
|
||||||
=
|
=
|
||||||
let relevantTypeName =
|
let relevantTypeName = analysis.ParentTypeName
|
||||||
match unionType with
|
|
||||||
| SynTypeDefn.SynTypeDefn (SynComponentInfo.SynComponentInfo (longId = id), _, _, _, _, _) -> List.last id
|
|
||||||
|
|
||||||
let allTyparNames =
|
let allArtificialTyparNames =
|
||||||
allTypars
|
allArtificialTypars
|
||||||
|> List.map (fun ty ->
|
|> List.map (fun ty ->
|
||||||
match ty with
|
match ty with
|
||||||
| SynType.Var (SynTypar.SynTypar (ident = ident), _) -> ident
|
| SynType.Var (SynTypar.SynTypar (ident = ident), _) -> ident
|
||||||
| _ -> failwith "logic error in generator"
|
| _ -> failwith "logic error in generator"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let userProvidedTyparsForCase =
|
||||||
|
analysis.Typars
|
||||||
|
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, ty)) -> SynType.Var (ty, range0))
|
||||||
|
|
||||||
|
let userProvidedTyparsForCata =
|
||||||
|
userProvidedTypars
|
||||||
|
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, ty)) -> SynType.Var (ty, range0))
|
||||||
|
|
||||||
let relevantTyparName =
|
let relevantTyparName =
|
||||||
match relevantTypar with
|
match relevantTypar with
|
||||||
| SynType.Var (SynTypar.SynTypar (ident = ident), _) -> ident
|
| SynType.Var (SynTypar.SynTypar (ident = ident), _) -> ident
|
||||||
| _ -> failwith "logic error in generator"
|
| _ -> failwith "logic error in generator"
|
||||||
|
|
||||||
|
let inputObjectType =
|
||||||
|
let baseType =
|
||||||
|
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent relevantTypeName)
|
||||||
|
|
||||||
|
if userProvidedTypars.Length = 0 then
|
||||||
|
baseType
|
||||||
|
else
|
||||||
|
SynType.App (
|
||||||
|
baseType,
|
||||||
|
Some range0,
|
||||||
|
userProvidedTyparsForCase,
|
||||||
|
List.replicate (userProvidedTypars.Length - 1) range0,
|
||||||
|
Some range0,
|
||||||
|
false,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
|
// The object on which we'll run the cata
|
||||||
|
let inputObject =
|
||||||
|
SynPat.CreateTyped (SynPat.CreateNamed (Ident.Create "x"), inputObjectType)
|
||||||
|
|
||||||
|
let cataObject =
|
||||||
|
SynPat.CreateTyped (
|
||||||
|
SynPat.CreateNamed (Ident.Create "cata"),
|
||||||
|
SynType.App (
|
||||||
|
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ cataName ]),
|
||||||
|
Some range0,
|
||||||
|
userProvidedTyparsForCata @ allArtificialTypars,
|
||||||
|
List.replicate (userProvidedTypars.Length + allArtificialTypars.Length - 1) range0,
|
||||||
|
Some range0,
|
||||||
|
false,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
SynBinding.SynBinding (
|
SynBinding.SynBinding (
|
||||||
None,
|
None,
|
||||||
SynBindingKind.Normal,
|
SynBindingKind.Normal,
|
||||||
@@ -150,29 +198,8 @@ module internal CataGenerator =
|
|||||||
None
|
None
|
||||||
),
|
),
|
||||||
SynPat.CreateLongIdent (
|
SynPat.CreateLongIdent (
|
||||||
SynLongIdent.CreateString ("run" + relevantTypeName.idText),
|
SynLongIdent.CreateString ("run" + List.last(relevantTypeName).idText),
|
||||||
[
|
[ SynPat.CreateParen cataObject ; SynPat.CreateParen inputObject ]
|
||||||
SynPat.CreateParen (
|
|
||||||
SynPat.CreateTyped (
|
|
||||||
SynPat.CreateNamed (Ident.Create "cata"),
|
|
||||||
SynType.App (
|
|
||||||
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ cataName ]),
|
|
||||||
Some range0,
|
|
||||||
allTypars,
|
|
||||||
List.replicate (allTypars.Length - 1) range0,
|
|
||||||
Some range0,
|
|
||||||
false,
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
SynPat.CreateParen (
|
|
||||||
SynPat.CreateTyped (
|
|
||||||
SynPat.CreateNamed (Ident.Create "x"),
|
|
||||||
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ relevantTypeName ])
|
|
||||||
)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
),
|
),
|
||||||
Some (SynBindingReturnInfo.Create relevantTypar),
|
Some (SynBindingReturnInfo.Create relevantTypar),
|
||||||
SynExpr.CreateTyped (
|
SynExpr.CreateTyped (
|
||||||
@@ -196,10 +223,7 @@ module internal CataGenerator =
|
|||||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "instructions" ; "Add" ]),
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "instructions" ; "Add" ]),
|
||||||
SynExpr.CreateParen (
|
SynExpr.CreateParen (
|
||||||
SynExpr.CreateApp (
|
SynExpr.CreateApp (
|
||||||
SynExpr.CreateLongIdent (
|
SynExpr.CreateLongIdent analysis.AssociatedProcessInstruction,
|
||||||
SynLongIdent.Create
|
|
||||||
[ "Instruction" ; "Process__" + relevantTypeName.idText ]
|
|
||||||
),
|
|
||||||
SynExpr.CreateLongIdent (SynLongIdent.CreateString "x")
|
SynExpr.CreateLongIdent (SynLongIdent.CreateString "x")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -219,8 +243,8 @@ module internal CataGenerator =
|
|||||||
Ident.Create (t.idText + "Stack") |> Ident.lowerFirstLetter
|
Ident.Create (t.idText + "Stack") |> Ident.lowerFirstLetter
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
allTyparNames,
|
allArtificialTyparNames,
|
||||||
List.replicate (allTypars.Length - 1) range0,
|
List.replicate (allArtificialTyparNames.Length - 1) range0,
|
||||||
range0
|
range0
|
||||||
),
|
),
|
||||||
expr =
|
expr =
|
||||||
@@ -262,9 +286,10 @@ module internal CataGenerator =
|
|||||||
match ty with
|
match ty with
|
||||||
| SynTypeDefn.SynTypeDefn (SynComponentInfo.SynComponentInfo (_, _, _, id, _, _, _, _), _, _, _, _, _) -> id
|
| SynTypeDefn.SynTypeDefn (SynComponentInfo.SynComponentInfo (_, _, _, id, _, _, _, _), _, _, _, _, _) -> id
|
||||||
|
|
||||||
let getNameUnion (unionType : SynType) : LongIdent option =
|
let rec getNameUnion (unionType : SynType) : LongIdent option =
|
||||||
match unionType with
|
match unionType with
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (name, _, _)) -> Some name
|
| SynType.LongIdent (SynLongIdent.SynLongIdent (name, _, _)) -> Some name
|
||||||
|
| SynType.App (ty, _, _, _, _, _, _) -> getNameUnion ty
|
||||||
| _ -> None
|
| _ -> None
|
||||||
|
|
||||||
let getNameKey (ty : SynTypeDefn) : string =
|
let getNameKey (ty : SynTypeDefn) : string =
|
||||||
@@ -279,51 +304,20 @@ module internal CataGenerator =
|
|||||||
/// Get the fields of this particular union case, and describe their relation to the
|
/// Get the fields of this particular union case, and describe their relation to the
|
||||||
/// recursive knot of user-provided DUs for which we are creating a cata.
|
/// recursive knot of user-provided DUs for which we are creating a cata.
|
||||||
let analyse
|
let analyse
|
||||||
|
(availableGenerics : SynTyparDecl list)
|
||||||
(allRecordTypes : SynTypeDefn list)
|
(allRecordTypes : SynTypeDefn list)
|
||||||
(allUnionTypes : SynTypeDefn list)
|
(allUnionTypes : SynTypeDefn list)
|
||||||
(argIndex : int)
|
(argIndex : int)
|
||||||
(fields : AdtNode list)
|
(fields : AdtNode list)
|
||||||
: CataUnionBasicField list
|
: CataUnionBasicField list
|
||||||
=
|
=
|
||||||
let rec go (prefix : string) (name : Ident option) (ty : SynType) =
|
let availableGenerics =
|
||||||
let stripped = SynType.stripOptionalParen ty
|
availableGenerics
|
||||||
|
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident)
|
||||||
|
|
||||||
match stripped with
|
let rec go (prefix : string) (name : Ident option) (ty : SynType) : CataUnionBasicField =
|
||||||
| ListType child ->
|
let dealWithPrimitive (typeArgs : int list option) (ty : SynType) (typeName : LongIdent) =
|
||||||
let gone = go (prefix + "_") None child
|
let key = typeName |> List.map _.idText |> String.concat "/"
|
||||||
|
|
||||||
match gone.Description with
|
|
||||||
| FieldDescription.NonRecursive ty ->
|
|
||||||
// Great, no recursion, just treat it as atomic
|
|
||||||
{
|
|
||||||
FieldName = name
|
|
||||||
ArgName =
|
|
||||||
match name with
|
|
||||||
| Some n -> Ident.lowerFirstLetter n
|
|
||||||
| None -> Ident.Create $"arg%s{prefix}"
|
|
||||||
Description = FieldDescription.NonRecursive stripped
|
|
||||||
}
|
|
||||||
| FieldDescription.Self ty ->
|
|
||||||
{
|
|
||||||
FieldName = name
|
|
||||||
ArgName =
|
|
||||||
match name with
|
|
||||||
| Some n -> Ident.lowerFirstLetter n
|
|
||||||
| None -> Ident.Create $"arg%s{prefix}"
|
|
||||||
Description = FieldDescription.ListSelf ty
|
|
||||||
}
|
|
||||||
| FieldDescription.ListSelf _ -> failwith "Deeply nested lists not currently supported"
|
|
||||||
| PrimitiveType _ ->
|
|
||||||
{
|
|
||||||
FieldName = name
|
|
||||||
ArgName =
|
|
||||||
match name with
|
|
||||||
| Some n -> Ident.lowerFirstLetter n
|
|
||||||
| None -> Ident.Create $"arg%s{prefix}"
|
|
||||||
Description = FieldDescription.NonRecursive stripped
|
|
||||||
}
|
|
||||||
| SynType.LongIdent (SynLongIdent.SynLongIdent (ty, _, _)) ->
|
|
||||||
let key = ty |> List.map _.idText |> String.concat "/"
|
|
||||||
|
|
||||||
let isKnownUnion =
|
let isKnownUnion =
|
||||||
allUnionTypes |> List.exists (fun unionTy -> getNameKey unionTy = key)
|
allUnionTypes |> List.exists (fun unionTy -> getNameKey unionTy = key)
|
||||||
@@ -339,9 +333,28 @@ module internal CataGenerator =
|
|||||||
match name with
|
match name with
|
||||||
| Some n -> Ident.lowerFirstLetter n
|
| Some n -> Ident.lowerFirstLetter n
|
||||||
| None -> Ident.Create $"arg%s{prefix}"
|
| None -> Ident.Create $"arg%s{prefix}"
|
||||||
Description = FieldDescription.Self stripped
|
Description = FieldDescription.Self ty
|
||||||
|
RequiredGenerics = typeArgs
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
FieldName = name
|
||||||
|
ArgName =
|
||||||
|
match name with
|
||||||
|
| Some n -> Ident.lowerFirstLetter n
|
||||||
|
| None -> Ident.Create $"arg%s{prefix}"
|
||||||
|
Description = FieldDescription.NonRecursive ty
|
||||||
|
RequiredGenerics = typeArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
let rec dealWithType (typeArgs : int list option) (stripped : SynType) =
|
||||||
|
match stripped with
|
||||||
|
| ListType child ->
|
||||||
|
let gone = go (prefix + "_") None child
|
||||||
|
|
||||||
|
match gone.Description with
|
||||||
|
| FieldDescription.NonRecursive ty ->
|
||||||
|
// Great, no recursion, just treat it as atomic
|
||||||
{
|
{
|
||||||
FieldName = name
|
FieldName = name
|
||||||
ArgName =
|
ArgName =
|
||||||
@@ -349,10 +362,63 @@ module internal CataGenerator =
|
|||||||
| Some n -> Ident.lowerFirstLetter n
|
| Some n -> Ident.lowerFirstLetter n
|
||||||
| None -> Ident.Create $"arg%s{prefix}"
|
| None -> Ident.Create $"arg%s{prefix}"
|
||||||
Description = FieldDescription.NonRecursive stripped
|
Description = FieldDescription.NonRecursive stripped
|
||||||
|
RequiredGenerics = typeArgs
|
||||||
|
}
|
||||||
|
| FieldDescription.Self ty ->
|
||||||
|
{
|
||||||
|
FieldName = name
|
||||||
|
ArgName =
|
||||||
|
match name with
|
||||||
|
| Some n -> Ident.lowerFirstLetter n
|
||||||
|
| None -> Ident.Create $"arg%s{prefix}"
|
||||||
|
Description = FieldDescription.ListSelf ty
|
||||||
|
RequiredGenerics = typeArgs
|
||||||
|
}
|
||||||
|
| FieldDescription.ListSelf _ -> failwith "Deeply nested lists not currently supported"
|
||||||
|
| PrimitiveType _ ->
|
||||||
|
{
|
||||||
|
FieldName = name
|
||||||
|
ArgName =
|
||||||
|
match name with
|
||||||
|
| Some n -> Ident.lowerFirstLetter n
|
||||||
|
| None -> Ident.Create $"arg%s{prefix}"
|
||||||
|
Description = FieldDescription.NonRecursive stripped
|
||||||
|
RequiredGenerics = typeArgs
|
||||||
|
}
|
||||||
|
| SynType.App (ty, _, childTypeArgs, _, _, _, _) ->
|
||||||
|
match typeArgs with
|
||||||
|
| Some _ -> failwithf "Nested applications of types not supported in %+A" ty
|
||||||
|
| None ->
|
||||||
|
let childTypeArgs =
|
||||||
|
childTypeArgs
|
||||||
|
|> List.map (fun generic ->
|
||||||
|
let generic =
|
||||||
|
match generic with
|
||||||
|
| SynType.Var (SynTypar.SynTypar (name, _, _), _) -> name
|
||||||
|
| _ -> failwithf "Unrecognised generic arg: %+A" generic
|
||||||
|
|
||||||
|
availableGenerics
|
||||||
|
|> List.findIndex (fun knownGeneric -> knownGeneric.idText = generic.idText)
|
||||||
|
)
|
||||||
|
|
||||||
|
dealWithType (Some childTypeArgs) (SynType.stripOptionalParen ty)
|
||||||
|
| SynType.LongIdent (SynLongIdent.SynLongIdent (ty, _, _)) -> dealWithPrimitive typeArgs stripped ty
|
||||||
|
| SynType.Var (typar, _) ->
|
||||||
|
{
|
||||||
|
FieldName = name
|
||||||
|
ArgName =
|
||||||
|
match name with
|
||||||
|
| Some n -> Ident.lowerFirstLetter n
|
||||||
|
| None -> Ident.Create $"arg%s{prefix}"
|
||||||
|
Description = FieldDescription.NonRecursive ty
|
||||||
|
RequiredGenerics = typeArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
| _ -> failwithf "Unrecognised type: %+A" stripped
|
| _ -> failwithf "Unrecognised type: %+A" stripped
|
||||||
|
|
||||||
|
let stripped = SynType.stripOptionalParen ty
|
||||||
|
dealWithType None stripped
|
||||||
|
|
||||||
fields |> List.mapi (fun i x -> go $"%i{argIndex}_%i{i}" x.Name x.Type)
|
fields |> List.mapi (fun i x -> go $"%i{argIndex}_%i{i}" x.Name x.Type)
|
||||||
|
|
||||||
/// Returns whether this type recursively contains a Self, and the type which
|
/// Returns whether this type recursively contains a Self, and the type which
|
||||||
@@ -410,6 +476,8 @@ module internal CataGenerator =
|
|||||||
{
|
{
|
||||||
Name = name |> Option.map Ident.lowerFirstLetter
|
Name = name |> Option.map Ident.lowerFirstLetter
|
||||||
Type = ty
|
Type = ty
|
||||||
|
// TODO this is definitely wrong
|
||||||
|
GenericsOfParent = []
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -432,7 +500,27 @@ module internal CataGenerator =
|
|||||||
Fields =
|
Fields =
|
||||||
{
|
{
|
||||||
Name = None
|
Name = None
|
||||||
Type = SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent union.ParentTypeName)
|
Type =
|
||||||
|
let name =
|
||||||
|
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent union.ParentTypeName)
|
||||||
|
|
||||||
|
match union.Typars with
|
||||||
|
| [] -> name
|
||||||
|
| typars ->
|
||||||
|
let typars =
|
||||||
|
typars
|
||||||
|
|> List.map (fun (SynTyparDecl (_, typar)) -> SynType.Var (typar, range0))
|
||||||
|
|
||||||
|
SynType.App (
|
||||||
|
name,
|
||||||
|
Some range0,
|
||||||
|
typars,
|
||||||
|
List.replicate (typars.Length - 1) range0,
|
||||||
|
Some range0,
|
||||||
|
false,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
GenericsOfParent = union.Typars
|
||||||
}
|
}
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
}
|
}
|
||||||
@@ -445,12 +533,28 @@ module internal CataGenerator =
|
|||||||
|
|
||||||
/// Build the DU which defines the states our state machine can be in.
|
/// Build the DU which defines the states our state machine can be in.
|
||||||
let createInstructionType (analysis : UnionAnalysis list) : SynTypeDefn =
|
let createInstructionType (analysis : UnionAnalysis list) : SynTypeDefn =
|
||||||
|
let parentGenerics =
|
||||||
|
analysis
|
||||||
|
|> List.collect _.Typars
|
||||||
|
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|
||||||
|
|> List.distinct
|
||||||
|
|> List.map (fun i ->
|
||||||
|
SynTyparDecl.SynTyparDecl ([], SynTypar.SynTypar (Ident.Create i, TyparStaticReq.None, false))
|
||||||
|
)
|
||||||
|
|
||||||
// One union case for each union type, and then
|
// One union case for each union type, and then
|
||||||
// a union case for each union case which contains a recursive reference.
|
// a union case for each union case which contains a recursive reference.
|
||||||
let casesFromProcess : SynUnionCase list =
|
let casesFromProcess : SynUnionCase list =
|
||||||
baseCases analysis
|
baseCases analysis
|
||||||
|> List.map (fun unionCase ->
|
|> List.map (fun unionCase ->
|
||||||
SynUnionCase.Create (unionCase.Name, unionCase.Fields |> List.map (fun f -> SynField.Create f.Type))
|
let fields =
|
||||||
|
unionCase.Fields
|
||||||
|
|> List.map (fun field ->
|
||||||
|
// TODO: adjust type parameters
|
||||||
|
SynField.Create field.Type
|
||||||
|
)
|
||||||
|
|
||||||
|
SynUnionCase.Create (unionCase.Name, fields)
|
||||||
)
|
)
|
||||||
|
|
||||||
let casesFromCases =
|
let casesFromCases =
|
||||||
@@ -461,10 +565,28 @@ module internal CataGenerator =
|
|||||||
|
|
||||||
let cases = casesFromProcess @ casesFromCases
|
let cases = casesFromProcess @ casesFromCases
|
||||||
|
|
||||||
|
let typars =
|
||||||
|
let count = analysis |> List.map (fun x -> List.length x.Typars) |> List.max
|
||||||
|
|
||||||
|
if analysis |> List.forall (fun x -> x.Typars.IsEmpty) then
|
||||||
|
None
|
||||||
|
else
|
||||||
|
|
||||||
|
let typars =
|
||||||
|
analysis
|
||||||
|
|> List.collect _.Typars
|
||||||
|
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|
||||||
|
|> List.distinct
|
||||||
|
|> List.map (fun i ->
|
||||||
|
SynTyparDecl.SynTyparDecl ([], SynTypar.SynTypar (Ident.Create i, TyparStaticReq.None, false))
|
||||||
|
)
|
||||||
|
|
||||||
|
Some (SynTyparDecls.PostfixList (typars, [], range0))
|
||||||
|
|
||||||
SynTypeDefn.SynTypeDefn (
|
SynTypeDefn.SynTypeDefn (
|
||||||
SynComponentInfo.SynComponentInfo (
|
SynComponentInfo.SynComponentInfo (
|
||||||
[ SynAttributeList.Create [ SynAttribute.RequireQualifiedAccess () ] ],
|
[ SynAttributeList.Create [ SynAttribute.RequireQualifiedAccess () ] ],
|
||||||
None,
|
typars,
|
||||||
[],
|
[],
|
||||||
[ Ident.Create "Instruction" ],
|
[ Ident.Create "Instruction" ],
|
||||||
PreXmlDoc.Empty,
|
PreXmlDoc.Empty,
|
||||||
@@ -514,7 +636,7 @@ module internal CataGenerator =
|
|||||||
let componentInfo =
|
let componentInfo =
|
||||||
SynComponentInfo.SynComponentInfo (
|
SynComponentInfo.SynComponentInfo (
|
||||||
[],
|
[],
|
||||||
Some (SynTyparDecls.PostfixList (orderedGenerics, [], range0)),
|
Some (SynTyparDecls.PostfixList (analysis.Typars @ orderedGenerics, [], range0)),
|
||||||
[],
|
[],
|
||||||
[ analysis.CataTypeName ],
|
[ analysis.CataTypeName ],
|
||||||
// TODO: better docstring
|
// TODO: better docstring
|
||||||
@@ -557,7 +679,26 @@ module internal CataGenerator =
|
|||||||
[ SynType.Var (generics.[getNameKeyUnion ty], range0) ],
|
[ SynType.Var (generics.[getNameKeyUnion ty], range0) ],
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
| FieldDescription.NonRecursive ty -> ty
|
| FieldDescription.NonRecursive ty ->
|
||||||
|
match field.RequiredGenerics with
|
||||||
|
| None -> ty
|
||||||
|
| Some generics ->
|
||||||
|
let generics =
|
||||||
|
generics
|
||||||
|
|> List.map (fun i ->
|
||||||
|
let (SynTyparDecl.SynTyparDecl (_, typar)) = analysis.Typars.[i]
|
||||||
|
SynType.Var (typar, range0)
|
||||||
|
)
|
||||||
|
|
||||||
|
SynType.App (
|
||||||
|
ty,
|
||||||
|
Some range0,
|
||||||
|
generics,
|
||||||
|
List.replicate (generics.Length - 1) range0,
|
||||||
|
Some range0,
|
||||||
|
false,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
SynType.Fun (
|
SynType.Fun (
|
||||||
SynType.SignatureParameter (
|
SynType.SignatureParameter (
|
||||||
@@ -625,30 +766,36 @@ module internal CataGenerator =
|
|||||||
/// Build a record which contains one of every cata type.
|
/// Build a record which contains one of every cata type.
|
||||||
/// That is, define a type Cata<{'ret<U> for U in T}>
|
/// That is, define a type Cata<{'ret<U> for U in T}>
|
||||||
/// with one member for each U, namely of type [U]Cata<{'ret<U> for U in T}>.
|
/// with one member for each U, namely of type [U]Cata<{'ret<U> for U in T}>.
|
||||||
// TODO: this should take an analysis instead
|
let createCataRecord (cataName : Ident) (doc : PreXmlDoc) (analysis : UnionAnalysis list) : SynTypeDefn =
|
||||||
let createCataRecord (cataName : Ident) (doc : PreXmlDoc) (allUnionTypes : SynTypeDefn list) : SynTypeDefn =
|
// An artificial generic for each union type
|
||||||
let generics =
|
let generics =
|
||||||
allUnionTypes
|
analysis
|
||||||
|> List.map (fun defn ->
|
|> List.map (fun analysis -> SynTypar.SynTypar (analysis.GenericName, TyparStaticReq.None, false))
|
||||||
let name = getName defn |> List.map _.idText |> String.concat "" |> Ident.Create
|
|
||||||
SynTypar.SynTypar (name, TyparStaticReq.None, false)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
// A field for each cata
|
||||||
let fields =
|
let fields =
|
||||||
allUnionTypes
|
analysis
|
||||||
|> List.map (fun unionType ->
|
|> List.map (fun analysis ->
|
||||||
let nameForDoc = List.last (getName unionType) |> _.idText
|
let nameForDoc = List.last(analysis.ParentTypeName).idText
|
||||||
|
|
||||||
let doc =
|
let doc =
|
||||||
PreXmlDoc.Create $" How to perform a fold (catamorphism) over the type %s{nameForDoc}"
|
PreXmlDoc.Create $" How to perform a fold (catamorphism) over the type %s{nameForDoc}"
|
||||||
|
|
||||||
let name = getName unionType
|
let artificialGenerics = generics |> List.map (fun v -> SynType.Var (v, range0))
|
||||||
|
|
||||||
|
let userInputGenerics =
|
||||||
|
analysis.Typars
|
||||||
|
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|
||||||
|
|> List.distinct
|
||||||
|
|> List.map (fun i ->
|
||||||
|
SynType.Var (SynTypar.SynTypar (Ident.Create i, TyparStaticReq.None, false), range0)
|
||||||
|
)
|
||||||
|
|
||||||
let ty =
|
let ty =
|
||||||
SynType.App (
|
SynType.App (
|
||||||
SynType.CreateLongIdent (SynLongIdent.CreateString (List.last(name).idText + "CataCase")),
|
SynType.LongIdent (SynLongIdent.CreateFromLongIdent [ analysis.CataTypeName ]),
|
||||||
Some range0,
|
Some range0,
|
||||||
generics |> List.map (fun v -> SynType.Var (v, range0)),
|
userInputGenerics @ artificialGenerics,
|
||||||
List.replicate (generics.Length - 1) range0,
|
List.replicate (generics.Length - 1) range0,
|
||||||
Some range0,
|
Some range0,
|
||||||
false,
|
false,
|
||||||
@@ -658,7 +805,7 @@ module internal CataGenerator =
|
|||||||
SynField.SynField (
|
SynField.SynField (
|
||||||
[],
|
[],
|
||||||
false,
|
false,
|
||||||
Some (List.last name),
|
Some (List.last analysis.ParentTypeName),
|
||||||
ty,
|
ty,
|
||||||
false,
|
false,
|
||||||
doc,
|
doc,
|
||||||
@@ -670,16 +817,23 @@ module internal CataGenerator =
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// A "real" generic for each generic in the user-provided type
|
||||||
|
let genericsFromUserInput =
|
||||||
|
analysis
|
||||||
|
|> List.collect _.Typars
|
||||||
|
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|
||||||
|
|> List.distinct
|
||||||
|
|> List.map (fun i ->
|
||||||
|
SynTyparDecl.SynTyparDecl ([], SynTypar.SynTypar (Ident.Create i, TyparStaticReq.None, false))
|
||||||
|
)
|
||||||
|
|
||||||
|
let genericsFromCata =
|
||||||
|
generics |> List.map (fun ty -> SynTyparDecl.SynTyparDecl ([], ty))
|
||||||
|
|
||||||
let componentInfo =
|
let componentInfo =
|
||||||
SynComponentInfo.SynComponentInfo (
|
SynComponentInfo.SynComponentInfo (
|
||||||
[],
|
[],
|
||||||
Some (
|
Some (SynTyparDecls.PostfixList (genericsFromUserInput @ genericsFromCata, [], range0)),
|
||||||
SynTyparDecls.PostfixList (
|
|
||||||
generics |> List.map (fun ty -> SynTyparDecl.SynTyparDecl ([], ty)),
|
|
||||||
[],
|
|
||||||
range0
|
|
||||||
)
|
|
||||||
),
|
|
||||||
[],
|
[],
|
||||||
[ cataName ],
|
[ cataName ],
|
||||||
doc,
|
doc,
|
||||||
@@ -714,8 +868,10 @@ module internal CataGenerator =
|
|||||||
|
|
||||||
allUnionTypes
|
allUnionTypes
|
||||||
|> List.map (fun unionType ->
|
|> List.map (fun unionType ->
|
||||||
|
let cases, typars, access = AstHelper.getUnionCases unionType
|
||||||
|
|
||||||
let cases =
|
let cases =
|
||||||
AstHelper.getUnionCases unionType
|
cases
|
||||||
|> List.map (fun prod ->
|
|> List.map (fun prod ->
|
||||||
let fields =
|
let fields =
|
||||||
prod.Fields
|
prod.Fields
|
||||||
@@ -723,14 +879,16 @@ module internal CataGenerator =
|
|||||||
|> List.collect (fun (i, node) ->
|
|> List.collect (fun (i, node) ->
|
||||||
match getNameUnion node.Type with
|
match getNameUnion node.Type with
|
||||||
| None ->
|
| None ->
|
||||||
analyse allRecordTypes allUnionTypes i [ node ] |> List.map CataUnionField.Basic
|
analyse typars allRecordTypes allUnionTypes i [ node ]
|
||||||
|
|> List.map CataUnionField.Basic
|
||||||
| Some name ->
|
| Some name ->
|
||||||
|
|
||||||
match Map.tryFind (List.last(name).idText) recordTypes with
|
match Map.tryFind (List.last(name).idText) recordTypes with
|
||||||
| None ->
|
| None ->
|
||||||
analyse allRecordTypes allUnionTypes i [ node ] |> List.map CataUnionField.Basic
|
analyse typars allRecordTypes allUnionTypes i [ node ]
|
||||||
|
|> List.map CataUnionField.Basic
|
||||||
| Some fields ->
|
| Some fields ->
|
||||||
List.zip fields (analyse allRecordTypes allUnionTypes i fields)
|
List.zip fields (analyse typars allRecordTypes allUnionTypes i fields)
|
||||||
|> List.map (fun (field, analysis) -> Option.get field.Name, analysis)
|
|> List.map (fun (field, analysis) -> Option.get field.Name, analysis)
|
||||||
|> CataUnionField.Record
|
|> CataUnionField.Record
|
||||||
|> List.singleton
|
|> List.singleton
|
||||||
@@ -742,6 +900,8 @@ module internal CataGenerator =
|
|||||||
let unionTypeName = getName unionType
|
let unionTypeName = getName unionType
|
||||||
|
|
||||||
{
|
{
|
||||||
|
Typars = typars
|
||||||
|
Accessibility = access
|
||||||
StackName =
|
StackName =
|
||||||
List.last(getName unionType).idText + "Stack"
|
List.last(getName unionType).idText + "Stack"
|
||||||
|> Ident.Create
|
|> Ident.Create
|
||||||
@@ -810,7 +970,7 @@ module internal CataGenerator =
|
|||||||
)
|
)
|
||||||
|
|
||||||
let matchBody =
|
let matchBody =
|
||||||
if nonRecursiveArgs.Length = unionCase.Fields.Length then
|
if nonRecursiveArgs.Length = unionCase.FlattenedFields.Length then
|
||||||
// directly call the cata
|
// directly call the cata
|
||||||
callCataAndPushResult analysis.StackName unionCase
|
callCataAndPushResult analysis.StackName unionCase
|
||||||
else
|
else
|
||||||
@@ -821,7 +981,7 @@ module internal CataGenerator =
|
|||||||
let reprocessCommand =
|
let reprocessCommand =
|
||||||
SynExpr.CreateApp (
|
SynExpr.CreateApp (
|
||||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "instructions" ; "Add" ]),
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "instructions" ; "Add" ]),
|
||||||
if selfArgs.Length = unionCase.Fields.Length then
|
if selfArgs.Length = unionCase.FlattenedFields.Length then
|
||||||
SynExpr.CreateLongIdent unionCase.AssociatedInstruction
|
SynExpr.CreateLongIdent unionCase.AssociatedInstruction
|
||||||
else
|
else
|
||||||
// We need to tell ourselves each non-rec arg, and the length of each input list.
|
// We need to tell ourselves each non-rec arg, and the length of each input list.
|
||||||
@@ -906,10 +1066,8 @@ module internal CataGenerator =
|
|||||||
]
|
]
|
||||||
|> SynExpr.CreateSequential
|
|> SynExpr.CreateSequential
|
||||||
|
|
||||||
SynMatchClause.SynMatchClause (
|
let matchLhs =
|
||||||
SynPat.CreateLongIdent (
|
if unionCase.Fields.Length > 0 then
|
||||||
unionCase.Match,
|
|
||||||
[
|
|
||||||
SynPat.CreateParen (
|
SynPat.CreateParen (
|
||||||
SynPat.Tuple (
|
SynPat.Tuple (
|
||||||
false,
|
false,
|
||||||
@@ -922,9 +1080,7 @@ module internal CataGenerator =
|
|||||||
let fields =
|
let fields =
|
||||||
fields
|
fields
|
||||||
|> List.map (fun (name, field) ->
|
|> List.map (fun (name, field) ->
|
||||||
([], name),
|
([], name), range0, SynPat.CreateNamed (Ident.lowerFirstLetter name)
|
||||||
range0,
|
|
||||||
SynPat.CreateNamed (Ident.lowerFirstLetter name)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
SynPat.Record (fields, range0)
|
SynPat.Record (fields, range0)
|
||||||
@@ -933,8 +1089,12 @@ module internal CataGenerator =
|
|||||||
range0
|
range0
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
]
|
|> List.singleton
|
||||||
),
|
else
|
||||||
|
[]
|
||||||
|
|
||||||
|
SynMatchClause.SynMatchClause (
|
||||||
|
SynPat.CreateLongIdent (unionCase.Match, matchLhs),
|
||||||
None,
|
None,
|
||||||
matchBody,
|
matchBody,
|
||||||
range0,
|
range0,
|
||||||
@@ -1218,6 +1378,35 @@ module internal CataGenerator =
|
|||||||
None
|
None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let userSuppliedGenerics =
|
||||||
|
analysis
|
||||||
|
|> List.collect _.Typars
|
||||||
|
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|
||||||
|
|> List.distinct
|
||||||
|
|> List.map (fun i -> SynTypar.SynTypar (Ident.Create i, TyparStaticReq.None, false))
|
||||||
|
|
||||||
|
let instructionsArrType =
|
||||||
|
if not userSuppliedGenerics.IsEmpty then
|
||||||
|
SynType.App (
|
||||||
|
SynType.CreateLongIdent "Instruction",
|
||||||
|
Some range0,
|
||||||
|
userSuppliedGenerics |> List.map (fun x -> SynType.Var (x, range0)),
|
||||||
|
List.replicate (userSuppliedGenerics.Length - 1) range0,
|
||||||
|
Some range0,
|
||||||
|
false,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
else
|
||||||
|
SynType.CreateLongIdent "Instruction"
|
||||||
|
|
||||||
|
let cataGenerics =
|
||||||
|
[
|
||||||
|
for generic in userSuppliedGenerics do
|
||||||
|
yield SynType.Var (generic, range0)
|
||||||
|
for case in analysis do
|
||||||
|
yield SynType.Var (SynTypar.SynTypar (case.GenericName, TyparStaticReq.None, false), range0)
|
||||||
|
]
|
||||||
|
|
||||||
let headPat =
|
let headPat =
|
||||||
SynPat.LongIdent (
|
SynPat.LongIdent (
|
||||||
SynLongIdent.CreateString "loop",
|
SynLongIdent.CreateString "loop",
|
||||||
@@ -1231,8 +1420,8 @@ module internal CataGenerator =
|
|||||||
SynType.App (
|
SynType.App (
|
||||||
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ cataTypeName ]),
|
SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent [ cataTypeName ]),
|
||||||
Some range0,
|
Some range0,
|
||||||
List.replicate analysis.Length (SynType.Anon range0),
|
cataGenerics,
|
||||||
List.replicate (analysis.Length - 1) range0,
|
List.replicate (cataGenerics.Length - 1) range0,
|
||||||
Some range0,
|
Some range0,
|
||||||
false,
|
false,
|
||||||
range0
|
range0
|
||||||
@@ -1245,7 +1434,7 @@ module internal CataGenerator =
|
|||||||
SynType.App (
|
SynType.App (
|
||||||
SynType.CreateLongIdent "ResizeArray",
|
SynType.CreateLongIdent "ResizeArray",
|
||||||
Some range0,
|
Some range0,
|
||||||
[ SynType.CreateLongIdent "Instruction" ],
|
[ instructionsArrType ],
|
||||||
[],
|
[],
|
||||||
Some range0,
|
Some range0,
|
||||||
false,
|
false,
|
||||||
@@ -1347,7 +1536,20 @@ module internal CataGenerator =
|
|||||||
SynPat.Named (SynIdent.SynIdent (unionCase.StackName, None), false, None, range0),
|
SynPat.Named (SynIdent.SynIdent (unionCase.StackName, None), false, None, range0),
|
||||||
None,
|
None,
|
||||||
SynExpr.CreateApp (
|
SynExpr.CreateApp (
|
||||||
SynExpr.CreateLongIdent (SynLongIdent.CreateString "ResizeArray"),
|
SynExpr.TypeApp (
|
||||||
|
SynExpr.CreateIdent (Ident.Create "ResizeArray"),
|
||||||
|
range0,
|
||||||
|
[
|
||||||
|
SynType.Var (
|
||||||
|
SynTypar.SynTypar (unionCase.GenericName, TyparStaticReq.None, false),
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
Some range0,
|
||||||
|
range0,
|
||||||
|
range0
|
||||||
|
),
|
||||||
SynExpr.CreateConst SynConst.Unit
|
SynExpr.CreateConst SynConst.Unit
|
||||||
),
|
),
|
||||||
range0,
|
range0,
|
||||||
@@ -1404,6 +1606,9 @@ module internal CataGenerator =
|
|||||||
xmldoc = PreXmlDoc.Create $" Methods to perform a catamorphism over the type %s{parentName}"
|
xmldoc = PreXmlDoc.Create $" Methods to perform a catamorphism over the type %s{parentName}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let cataVarName = Ident.Create "cata"
|
||||||
|
let analysis = makeUnionAnalyses cataVarName allRecordTypes allUnionTypes
|
||||||
|
|
||||||
let allTypars =
|
let allTypars =
|
||||||
allUnionTypes
|
allUnionTypes
|
||||||
|> List.map (fun unionType ->
|
|> List.map (fun unionType ->
|
||||||
@@ -1414,12 +1619,20 @@ module internal CataGenerator =
|
|||||||
|> fun x -> SynType.Var (x, range0)
|
|> fun x -> SynType.Var (x, range0)
|
||||||
)
|
)
|
||||||
|
|
||||||
let runFunctions =
|
let userProvidedGenerics =
|
||||||
List.zip allUnionTypes allTypars
|
analysis
|
||||||
|> List.map (fun (unionType, relevantTypar) -> createRunFunction cataName allTypars relevantTypar unionType)
|
|> List.collect _.Typars
|
||||||
|
|> List.map (fun (SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|
||||||
|
|> List.distinct
|
||||||
|
|> List.map (fun x ->
|
||||||
|
SynTyparDecl.SynTyparDecl ([], SynTypar.SynTypar (Ident.Create x, TyparStaticReq.None, false))
|
||||||
|
)
|
||||||
|
|
||||||
let cataVarName = Ident.Create "cata"
|
let runFunctions =
|
||||||
let analysis = makeUnionAnalyses cataVarName allRecordTypes allUnionTypes
|
List.zip analysis allTypars
|
||||||
|
|> List.map (fun (analysis, relevantTypar) ->
|
||||||
|
createRunFunction cataName userProvidedGenerics allTypars relevantTypar analysis
|
||||||
|
)
|
||||||
|
|
||||||
let cataStructures =
|
let cataStructures =
|
||||||
createCataStructure analysis
|
createCataStructure analysis
|
||||||
@@ -1432,7 +1645,7 @@ module internal CataGenerator =
|
|||||||
$" Specifies how to perform a fold (catamorphism) over the type %s{parentName} and its friends."
|
$" Specifies how to perform a fold (catamorphism) over the type %s{parentName} and its friends."
|
||||||
|
|
||||||
let cataRecord =
|
let cataRecord =
|
||||||
SynModuleDecl.Types ([ createCataRecord cataName recordDoc allUnionTypes ], range0)
|
SynModuleDecl.Types ([ createCataRecord cataName recordDoc analysis ], range0)
|
||||||
|
|
||||||
SynModuleOrNamespace.CreateNamespace (
|
SynModuleOrNamespace.CreateNamespace (
|
||||||
ns,
|
ns,
|
||||||
@@ -1453,14 +1666,7 @@ module internal CataGenerator =
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
/// Myriad generator that provides a catamorphism for an algebraic data type.
|
let generate (context : GeneratorContext) : Output =
|
||||||
[<MyriadGenerator("create-catamorphism")>]
|
|
||||||
type CreateCatamorphismGenerator () =
|
|
||||||
|
|
||||||
interface IMyriadGenerator with
|
|
||||||
member _.ValidInputExtensions = [ ".fs" ]
|
|
||||||
|
|
||||||
member _.Generate (context : GeneratorContext) =
|
|
||||||
let ast, _ =
|
let ast, _ =
|
||||||
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
Ast.fromFilename context.InputFilename |> Async.RunSynchronously |> Array.head
|
||||||
|
|
||||||
@@ -1504,8 +1710,15 @@ type CreateCatamorphismGenerator () =
|
|||||||
|
|
||||||
let modules =
|
let modules =
|
||||||
namespaceAndTypes
|
namespaceAndTypes
|
||||||
|> List.map (fun (ns, taggedType, unions, records) ->
|
|> List.map (fun (ns, taggedType, unions, records) -> createModule opens ns taggedType unions records)
|
||||||
CataGenerator.createModule opens ns taggedType unions records
|
|
||||||
)
|
|
||||||
|
|
||||||
Output.Ast modules
|
Output.Ast modules
|
||||||
|
|
||||||
|
/// Myriad generator that provides a catamorphism for an algebraic data type.
|
||||||
|
[<MyriadGenerator("create-catamorphism")>]
|
||||||
|
type CreateCatamorphismGenerator () =
|
||||||
|
|
||||||
|
interface IMyriadGenerator with
|
||||||
|
member _.ValidInputExtensions = [ ".fs" ]
|
||||||
|
|
||||||
|
member _.Generate (context : GeneratorContext) = CataGenerator.generate context
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
namespace WoofWare.Myriad.Plugins
|
namespace WoofWare.Myriad.Plugins
|
||||||
|
|
||||||
open System
|
|
||||||
open System.Net.Http
|
open System.Net.Http
|
||||||
open System.Text
|
|
||||||
open Fantomas.FCS.Syntax
|
open Fantomas.FCS.Syntax
|
||||||
open Fantomas.FCS.SyntaxTrivia
|
open Fantomas.FCS.SyntaxTrivia
|
||||||
open Fantomas.FCS.Xml
|
open Fantomas.FCS.Xml
|
||||||
@@ -82,34 +80,50 @@ module internal HttpClientGenerator =
|
|||||||
match attr.TypeName.AsString with
|
match attr.TypeName.AsString with
|
||||||
| "Get"
|
| "Get"
|
||||||
| "GetAttribute"
|
| "GetAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Get"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.GetAttribute"
|
||||||
| "RestEase.Get"
|
| "RestEase.Get"
|
||||||
| "RestEase.GetAttribute" -> Some (HttpMethod.Get, attr.ArgExpr)
|
| "RestEase.GetAttribute" -> Some (HttpMethod.Get, attr.ArgExpr)
|
||||||
| "Post"
|
| "Post"
|
||||||
| "PostAttribute"
|
| "PostAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Post"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.PostAttribute"
|
||||||
| "RestEase.Post"
|
| "RestEase.Post"
|
||||||
| "RestEase.PostAttribute" -> Some (HttpMethod.Post, attr.ArgExpr)
|
| "RestEase.PostAttribute" -> Some (HttpMethod.Post, attr.ArgExpr)
|
||||||
| "Put"
|
| "Put"
|
||||||
| "PutAttribute"
|
| "PutAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Put"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.PutAttribute"
|
||||||
| "RestEase.Put"
|
| "RestEase.Put"
|
||||||
| "RestEase.PutAttribute" -> Some (HttpMethod.Put, attr.ArgExpr)
|
| "RestEase.PutAttribute" -> Some (HttpMethod.Put, attr.ArgExpr)
|
||||||
| "Delete"
|
| "Delete"
|
||||||
| "DeleteAttribute"
|
| "DeleteAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Delete"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.DeleteAttribute"
|
||||||
| "RestEase.Delete"
|
| "RestEase.Delete"
|
||||||
| "RestEase.DeleteAttribute" -> Some (HttpMethod.Delete, attr.ArgExpr)
|
| "RestEase.DeleteAttribute" -> Some (HttpMethod.Delete, attr.ArgExpr)
|
||||||
| "Head"
|
| "Head"
|
||||||
| "HeadAttribute"
|
| "HeadAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Head"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.HeadAttribute"
|
||||||
| "RestEase.Head"
|
| "RestEase.Head"
|
||||||
| "RestEase.HeadAttribute" -> Some (HttpMethod.Head, attr.ArgExpr)
|
| "RestEase.HeadAttribute" -> Some (HttpMethod.Head, attr.ArgExpr)
|
||||||
| "Options"
|
| "Options"
|
||||||
| "OptionsAttribute"
|
| "OptionsAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Options"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.OptionsAttribute"
|
||||||
| "RestEase.Options"
|
| "RestEase.Options"
|
||||||
| "RestEase.OptionsAttribute" -> Some (HttpMethod.Options, attr.ArgExpr)
|
| "RestEase.OptionsAttribute" -> Some (HttpMethod.Options, attr.ArgExpr)
|
||||||
| "Patch"
|
| "Patch"
|
||||||
| "PatchAttribute"
|
| "PatchAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Patch"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.PatchAttribute"
|
||||||
| "RestEase.Patch"
|
| "RestEase.Patch"
|
||||||
| "RestEase.PatchAttribute" -> Some (HttpMethod.Patch, attr.ArgExpr)
|
| "RestEase.PatchAttribute" -> Some (HttpMethod.Patch, attr.ArgExpr)
|
||||||
| "Trace"
|
| "Trace"
|
||||||
| "TraceAttribute"
|
| "TraceAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Trace"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.TraceAttribute"
|
||||||
| "RestEase.Trace"
|
| "RestEase.Trace"
|
||||||
| "RestEase.TraceAttribute" -> Some (HttpMethod.Trace, attr.ArgExpr)
|
| "RestEase.TraceAttribute" -> Some (HttpMethod.Trace, attr.ArgExpr)
|
||||||
| _ -> None
|
| _ -> None
|
||||||
@@ -127,7 +141,8 @@ module internal HttpClientGenerator =
|
|||||||
|> List.choose (fun attr ->
|
|> List.choose (fun attr ->
|
||||||
match attr.TypeName.AsString with
|
match attr.TypeName.AsString with
|
||||||
| "Header"
|
| "Header"
|
||||||
| "RestEase.Header" ->
|
| "RestEase.Header"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Header" ->
|
||||||
match attr.ArgExpr with
|
match attr.ArgExpr with
|
||||||
| SynExpr.Paren (SynExpr.Tuple (_, [ v1 ; v2 ], _, _), _, _, _) ->
|
| SynExpr.Paren (SynExpr.Tuple (_, [ v1 ; v2 ], _, _), _, _, _) ->
|
||||||
Some [ SynExpr.stripOptionalParen v1 ; SynExpr.stripOptionalParen v2 ]
|
Some [ SynExpr.stripOptionalParen v1 ; SynExpr.stripOptionalParen v2 ]
|
||||||
@@ -293,6 +308,27 @@ module internal HttpClientGenerator =
|
|||||||
| None -> failwith "Unable to get parameter variable name from anonymous parameter"
|
| None -> failwith "Unable to get parameter variable name from anonymous parameter"
|
||||||
| Some id -> id
|
| Some id -> id
|
||||||
|
|
||||||
|
let urlSeparator =
|
||||||
|
// apparent Myriad bug: `IndexOf '?'` gets formatted as `IndexOf ?` which is clearly wrong
|
||||||
|
let questionMark =
|
||||||
|
SynExpr.CreateParen (
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateIdentString "char",
|
||||||
|
SynExpr.CreateConst (SynConst.Int32 63)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
let containsQuestion =
|
||||||
|
info.UrlTemplate
|
||||||
|
|> SynExpr.callMethodArg "IndexOf" questionMark
|
||||||
|
|> SynExpr.greaterThanOrEqual (SynExpr.CreateConst (SynConst.Int32 0))
|
||||||
|
|
||||||
|
SynExpr.ifThenElse
|
||||||
|
containsQuestion
|
||||||
|
(SynExpr.CreateConst (SynConst.CreateString "?"))
|
||||||
|
(SynExpr.CreateConst (SynConst.CreateString "&"))
|
||||||
|
|> SynExpr.CreateParen
|
||||||
|
|
||||||
let prefix =
|
let prefix =
|
||||||
SynExpr.CreateIdent firstValueId
|
SynExpr.CreateIdent firstValueId
|
||||||
|> SynExpr.toString firstValue.Type
|
|> SynExpr.toString firstValue.Type
|
||||||
@@ -301,7 +337,7 @@ module internal HttpClientGenerator =
|
|||||||
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ])
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ])
|
||||||
)
|
)
|
||||||
|> SynExpr.CreateParen
|
|> SynExpr.CreateParen
|
||||||
|> SynExpr.plus (SynExpr.CreateConstString ("?" + firstKey + "="))
|
|> SynExpr.plus (SynExpr.plus urlSeparator (SynExpr.CreateConstString (firstKey + "=")))
|
||||||
|
|
||||||
(prefix, queryParams)
|
(prefix, queryParams)
|
||||||
||> List.fold (fun uri (paramKey, paramValue) ->
|
||> List.fold (fun uri (paramKey, paramValue) ->
|
||||||
@@ -709,6 +745,10 @@ module internal HttpClientGenerator =
|
|||||||
attrs
|
attrs
|
||||||
|> List.choose (fun attr ->
|
|> List.choose (fun attr ->
|
||||||
match attr.TypeName.AsString with
|
match attr.TypeName.AsString with
|
||||||
|
| "RestEase.Query"
|
||||||
|
| "RestEase.QueryAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Query"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.QueryAttribute"
|
||||||
| "Query"
|
| "Query"
|
||||||
| "QueryAttribute" ->
|
| "QueryAttribute" ->
|
||||||
match attr.ArgExpr with
|
match attr.ArgExpr with
|
||||||
@@ -717,6 +757,10 @@ module internal HttpClientGenerator =
|
|||||||
Some (HttpAttribute.Query (Some s))
|
Some (HttpAttribute.Query (Some s))
|
||||||
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Query attribute: %+A{a}"
|
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Query attribute: %+A{a}"
|
||||||
| _ -> None
|
| _ -> None
|
||||||
|
| "RestEase.Path"
|
||||||
|
| "RestEase.PathAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Path"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.PathAttribute"
|
||||||
| "Path"
|
| "Path"
|
||||||
| "PathAttribute" ->
|
| "PathAttribute" ->
|
||||||
match attr.ArgExpr with
|
match attr.ArgExpr with
|
||||||
@@ -725,6 +769,10 @@ module internal HttpClientGenerator =
|
|||||||
| SynExpr.Const (SynConst.Unit, _) -> Some (HttpAttribute.Path PathSpec.MatchArgName)
|
| SynExpr.Const (SynConst.Unit, _) -> Some (HttpAttribute.Path PathSpec.MatchArgName)
|
||||||
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Path attribute: %+A{a}"
|
| SynExpr.Const (a, _) -> failwith $"unrecognised constant arg to the Path attribute: %+A{a}"
|
||||||
| _ -> None
|
| _ -> None
|
||||||
|
| "RestEase.Body"
|
||||||
|
| "RestEase.BodyAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.Body"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.BodyAttribute"
|
||||||
| "Body"
|
| "Body"
|
||||||
| "BodyAttribute" ->
|
| "BodyAttribute" ->
|
||||||
match attr.ArgExpr with
|
match attr.ArgExpr with
|
||||||
@@ -740,8 +788,10 @@ module internal HttpClientGenerator =
|
|||||||
match attr.TypeName.AsString with
|
match attr.TypeName.AsString with
|
||||||
| "BasePath"
|
| "BasePath"
|
||||||
| "RestEase.BasePath"
|
| "RestEase.BasePath"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.BasePath"
|
||||||
| "BasePathAttribute"
|
| "BasePathAttribute"
|
||||||
| "RestEase.BasePathAttribute" -> Some attr.ArgExpr
|
| "RestEase.BasePathAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.BasePathAttribute" -> Some attr.ArgExpr
|
||||||
| _ -> None
|
| _ -> None
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -751,8 +801,10 @@ module internal HttpClientGenerator =
|
|||||||
match attr.TypeName.AsString with
|
match attr.TypeName.AsString with
|
||||||
| "BaseAddress"
|
| "BaseAddress"
|
||||||
| "RestEase.BaseAddress"
|
| "RestEase.BaseAddress"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.BaseAddress"
|
||||||
| "BaseAddressAttribute"
|
| "BaseAddressAttribute"
|
||||||
| "RestEase.BaseAddressAttribute" -> Some attr.ArgExpr
|
| "RestEase.BaseAddressAttribute"
|
||||||
|
| "WoofWare.Myriad.Plugins.RestEase.BaseAddressAttribute" -> Some attr.ArgExpr
|
||||||
| _ -> None
|
| _ -> None
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -764,6 +816,10 @@ module internal HttpClientGenerator =
|
|||||||
=
|
=
|
||||||
let interfaceType = AstHelper.parseInterface interfaceType
|
let interfaceType = AstHelper.parseInterface interfaceType
|
||||||
|
|
||||||
|
if not (List.isEmpty interfaceType.Inherits) then
|
||||||
|
failwith
|
||||||
|
"HttpClientGenerator does not support inheritance. Remove the `inherit` keyword if you want to use this generator."
|
||||||
|
|
||||||
let constantHeaders =
|
let constantHeaders =
|
||||||
interfaceType.Attributes
|
interfaceType.Attributes
|
||||||
|> extractHeaderInformation
|
|> extractHeaderInformation
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ module internal InterfaceMockGenerator =
|
|||||||
| None -> failwith "Expected record field to have a name, but it was somehow anonymous"
|
| None -> failwith "Expected record field to have a name, but it was somehow anonymous"
|
||||||
| Some id -> id
|
| Some id -> id
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
type private KnownInheritance = | IDisposable
|
||||||
|
|
||||||
let createType
|
let createType
|
||||||
(spec : GenerateMockOutputSpec)
|
(spec : GenerateMockOutputSpec)
|
||||||
(name : string)
|
(name : string)
|
||||||
@@ -29,6 +32,20 @@ module internal InterfaceMockGenerator =
|
|||||||
(fields : SynField list)
|
(fields : SynField list)
|
||||||
: SynModuleDecl
|
: SynModuleDecl
|
||||||
=
|
=
|
||||||
|
let inherits =
|
||||||
|
interfaceType.Inherits
|
||||||
|
|> Seq.map (fun ty ->
|
||||||
|
match ty with
|
||||||
|
| SynType.LongIdent (SynLongIdent.SynLongIdent (name, _, _)) ->
|
||||||
|
match name |> List.map _.idText with
|
||||||
|
| [] -> failwith "Unexpected empty identifier in inheritance declaration"
|
||||||
|
| [ "IDisposable" ]
|
||||||
|
| [ "System" ; "IDisposable" ] -> KnownInheritance.IDisposable
|
||||||
|
| _ -> failwithf "Unrecognised inheritance identifier: %+A" name
|
||||||
|
| x -> failwithf "Unrecognised type in inheritance: %+A" x
|
||||||
|
)
|
||||||
|
|> Set.ofSeq
|
||||||
|
|
||||||
let synValData =
|
let synValData =
|
||||||
{
|
{
|
||||||
SynMemberFlags.IsInstance = false
|
SynMemberFlags.IsInstance = false
|
||||||
@@ -90,6 +107,23 @@ module internal InterfaceMockGenerator =
|
|||||||
)
|
)
|
||||||
|> SynBindingReturnInfo.Create
|
|> SynBindingReturnInfo.Create
|
||||||
|
|
||||||
|
let constructorFields =
|
||||||
|
let extras =
|
||||||
|
if inherits.Contains KnownInheritance.IDisposable then
|
||||||
|
let unitFun = SynExpr.createLambda "_" SynExpr.CreateUnit
|
||||||
|
|
||||||
|
[
|
||||||
|
(SynLongIdent.CreateFromLongIdent [ Ident.Create "Dispose" ], true), Some unitFun
|
||||||
|
]
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
|
||||||
|
let nonExtras =
|
||||||
|
fields
|
||||||
|
|> List.map (fun field -> (SynLongIdent.CreateFromLongIdent [ getName field ], true), Some failwithFun)
|
||||||
|
|
||||||
|
extras @ nonExtras
|
||||||
|
|
||||||
let constructor =
|
let constructor =
|
||||||
SynMemberDefn.Member (
|
SynMemberDefn.Member (
|
||||||
SynBinding.SynBinding (
|
SynBinding.SynBinding (
|
||||||
@@ -102,12 +136,7 @@ module internal InterfaceMockGenerator =
|
|||||||
SynValData.SynValData (Some synValData, SynValInfo.Empty, None),
|
SynValData.SynValData (Some synValData, SynValInfo.Empty, None),
|
||||||
constructorIdent,
|
constructorIdent,
|
||||||
Some constructorReturnType,
|
Some constructorReturnType,
|
||||||
AstHelper.instantiateRecord (
|
AstHelper.instantiateRecord constructorFields,
|
||||||
fields
|
|
||||||
|> List.map (fun field ->
|
|
||||||
((SynLongIdent.CreateFromLongIdent [ getName field ], true), Some failwithFun)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
range0,
|
range0,
|
||||||
DebugPointAtBinding.Yes range0,
|
DebugPointAtBinding.Yes range0,
|
||||||
{ SynExpr.synBindingTriviaZero true with
|
{ SynExpr.synBindingTriviaZero true with
|
||||||
@@ -117,6 +146,21 @@ module internal InterfaceMockGenerator =
|
|||||||
range0
|
range0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let fields =
|
||||||
|
let extras =
|
||||||
|
if inherits.Contains KnownInheritance.IDisposable then
|
||||||
|
[
|
||||||
|
SynField.Create (
|
||||||
|
SynType.CreateFun (SynType.CreateUnit, SynType.CreateUnit),
|
||||||
|
Ident.Create "Dispose",
|
||||||
|
xmldoc = PreXmlDoc.Create " Implementation of IDisposable.Dispose"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
|
||||||
|
extras @ fields
|
||||||
|
|
||||||
let interfaceMembers =
|
let interfaceMembers =
|
||||||
let members =
|
let members =
|
||||||
interfaceType.Members
|
interfaceType.Members
|
||||||
@@ -150,7 +194,9 @@ module internal InterfaceMockGenerator =
|
|||||||
|> List.mapi (fun i arg ->
|
|> List.mapi (fun i arg ->
|
||||||
arg.Args
|
arg.Args
|
||||||
|> List.mapi (fun j arg ->
|
|> List.mapi (fun j arg ->
|
||||||
SynArgInfo.CreateIdString $"arg_%i{i}_%i{j}"
|
match arg.Type with
|
||||||
|
| UnitType -> SynArgInfo.SynArgInfo ([], false, None)
|
||||||
|
| _ -> SynArgInfo.CreateIdString $"arg_%i{i}_%i{j}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@@ -165,8 +211,16 @@ module internal InterfaceMockGenerator =
|
|||||||
|> List.mapi (fun i tupledArgs ->
|
|> List.mapi (fun i tupledArgs ->
|
||||||
let args =
|
let args =
|
||||||
tupledArgs.Args
|
tupledArgs.Args
|
||||||
|> List.mapi (fun j _ -> SynPat.CreateNamed (Ident.Create $"arg_%i{i}_%i{j}"))
|
|> List.mapi (fun j ty ->
|
||||||
|
match ty.Type with
|
||||||
|
| UnitType -> SynPat.Const (SynConst.Unit, range0)
|
||||||
|
| _ -> SynPat.CreateNamed (Ident.Create $"arg_%i{i}_%i{j}")
|
||||||
|
)
|
||||||
|
|
||||||
|
match args with
|
||||||
|
| [] -> failwith "somehow got no args at all"
|
||||||
|
| [ arg ] -> arg
|
||||||
|
| args ->
|
||||||
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|
||||||
|> SynPat.CreateParen
|
|> SynPat.CreateParen
|
||||||
|> fun i -> if tupledArgs.HasParen then SynPat.Paren (i, range0) else i
|
|> fun i -> if tupledArgs.HasParen then SynPat.Paren (i, range0) else i
|
||||||
@@ -187,7 +241,11 @@ module internal InterfaceMockGenerator =
|
|||||||
memberInfo.Args
|
memberInfo.Args
|
||||||
|> List.mapi (fun i args ->
|
|> List.mapi (fun i args ->
|
||||||
args.Args
|
args.Args
|
||||||
|> List.mapi (fun j args -> SynExpr.CreateIdentString $"arg_%i{i}_%i{j}")
|
|> List.mapi (fun j arg ->
|
||||||
|
match arg.Type with
|
||||||
|
| UnitType -> SynExpr.CreateConst SynConst.Unit
|
||||||
|
| _ -> SynExpr.CreateIdentString $"arg_%i{i}_%i{j}"
|
||||||
|
)
|
||||||
|> SynExpr.CreateParenedTuple
|
|> SynExpr.CreateParenedTuple
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -264,11 +322,100 @@ module internal InterfaceMockGenerator =
|
|||||||
| Some (SynAccess.Internal _), _ -> SynAccess.Internal range0
|
| Some (SynAccess.Internal _), _ -> SynAccess.Internal range0
|
||||||
| Some (SynAccess.Private _), _ -> SynAccess.Private range0
|
| Some (SynAccess.Private _), _ -> SynAccess.Private range0
|
||||||
|
|
||||||
|
let extraInterfaces =
|
||||||
|
inherits
|
||||||
|
|> Seq.map (fun inheritance ->
|
||||||
|
match inheritance with
|
||||||
|
| KnownInheritance.IDisposable ->
|
||||||
|
let valData =
|
||||||
|
SynValData.SynValData (
|
||||||
|
Some
|
||||||
|
{
|
||||||
|
IsInstance = true
|
||||||
|
IsDispatchSlot = false
|
||||||
|
IsOverrideOrExplicitImpl = true
|
||||||
|
IsFinal = false
|
||||||
|
GetterOrSetterIsCompilerGenerated = false
|
||||||
|
MemberKind = SynMemberKind.Member
|
||||||
|
},
|
||||||
|
valInfo =
|
||||||
|
SynValInfo.SynValInfo (
|
||||||
|
curriedArgInfos =
|
||||||
|
[
|
||||||
|
yield
|
||||||
|
[
|
||||||
|
SynArgInfo.SynArgInfo (
|
||||||
|
attributes = [],
|
||||||
|
optional = false,
|
||||||
|
ident = None
|
||||||
|
)
|
||||||
|
]
|
||||||
|
],
|
||||||
|
returnInfo =
|
||||||
|
SynArgInfo.SynArgInfo (attributes = [], optional = false, ident = None)
|
||||||
|
),
|
||||||
|
thisIdOpt = None
|
||||||
|
)
|
||||||
|
|
||||||
|
let headArgs = [ SynPat.Const (SynConst.Unit, range0) ]
|
||||||
|
|
||||||
|
let headPat =
|
||||||
|
SynPat.LongIdent (
|
||||||
|
SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; Ident.Create "Dispose" ],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
SynArgPats.Pats headArgs,
|
||||||
|
None,
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
|
||||||
|
let binding =
|
||||||
|
SynBinding.SynBinding (
|
||||||
|
None,
|
||||||
|
SynBindingKind.Normal,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
[],
|
||||||
|
PreXmlDoc.Empty,
|
||||||
|
valData,
|
||||||
|
headPat,
|
||||||
|
Some (
|
||||||
|
SynBindingReturnInfo.SynBindingReturnInfo (
|
||||||
|
SynType.Unit (),
|
||||||
|
range0,
|
||||||
|
[],
|
||||||
|
SynBindingReturnInfoTrivia.Zero
|
||||||
|
)
|
||||||
|
),
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateLongIdent (SynLongIdent.Create [ "this" ; "Dispose" ]),
|
||||||
|
SynExpr.CreateUnit
|
||||||
|
),
|
||||||
|
range0,
|
||||||
|
DebugPointAtBinding.Yes range0,
|
||||||
|
{
|
||||||
|
LeadingKeyword = SynLeadingKeyword.Member range0
|
||||||
|
InlineKeyword = None
|
||||||
|
EqualsRange = Some range0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
let mem = SynMemberDefn.Member (binding, range0)
|
||||||
|
|
||||||
|
SynMemberDefn.Interface (
|
||||||
|
SynType.CreateLongIdent (SynLongIdent.Create [ "System" ; "IDisposable" ]),
|
||||||
|
Some range0,
|
||||||
|
Some [ mem ],
|
||||||
|
range0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|> Seq.toList
|
||||||
|
|
||||||
let record =
|
let record =
|
||||||
{
|
{
|
||||||
Name = Ident.Create name
|
Name = Ident.Create name
|
||||||
Fields = fields
|
Fields = fields
|
||||||
Members = Some [ constructor ; interfaceMembers ]
|
Members = Some ([ constructor ; interfaceMembers ] @ extraInterfaces)
|
||||||
XmlDoc = Some xmlDoc
|
XmlDoc = Some xmlDoc
|
||||||
Generics = interfaceType.Generics
|
Generics = interfaceType.Generics
|
||||||
Accessibility = Some access
|
Accessibility = Some access
|
||||||
@@ -333,7 +480,6 @@ module internal InterfaceMockGenerator =
|
|||||||
|
|
||||||
let typeDecl = createType spec name interfaceType docString fields
|
let typeDecl = createType spec name interfaceType docString fields
|
||||||
|
|
||||||
|
|
||||||
SynModuleOrNamespace.CreateNamespace (
|
SynModuleOrNamespace.CreateNamespace (
|
||||||
namespaceId,
|
namespaceId,
|
||||||
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ typeDecl ]
|
decls = (opens |> List.map SynModuleDecl.CreateOpen) @ [ typeDecl ]
|
||||||
|
|||||||
@@ -311,3 +311,19 @@ module internal SynExpr =
|
|||||||
),
|
),
|
||||||
x
|
x
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/// {y} >= {x}
|
||||||
|
let greaterThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr =
|
||||||
|
SynExpr.CreateApp (
|
||||||
|
SynExpr.CreateAppInfix (
|
||||||
|
SynExpr.CreateLongIdent (
|
||||||
|
SynLongIdent.SynLongIdent (
|
||||||
|
[ Ident.Create "op_GreaterThanOrEqual" ],
|
||||||
|
[],
|
||||||
|
[ Some (IdentTrivia.OriginalNotation ">=") ]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
y
|
||||||
|
),
|
||||||
|
x
|
||||||
|
)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.8.0]" />
|
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.10.0]" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
outputs = {
|
outputs = {
|
||||||
self,
|
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
flake-utils,
|
flake-utils,
|
||||||
...
|
...
|
||||||
|
|||||||
76
nix/deps.nix
76
nix/deps.nix
@@ -3,23 +3,18 @@
|
|||||||
{fetchNuGet}: [
|
{fetchNuGet}: [
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "fsharp-analyzers";
|
pname = "fsharp-analyzers";
|
||||||
version = "0.24.0";
|
version = "0.26.0";
|
||||||
sha256 = "sha256-cNaM/yHI28sHDGamKMrU237ltOyrR+8vPNUImB5RxjU=";
|
sha256 = "sha256-60Bl36LOb/zVNdH2SBSuQ5O41lP9dKTNZbs5vvYs+3U=";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "fantomas";
|
pname = "fantomas";
|
||||||
version = "6.3.0-alpha-007";
|
version = "6.3.4";
|
||||||
sha256 = "sha256-uZw6h6k/DS4BcYtK9cv8TLS0H8MZDO3WBaPPTdtTgu0=";
|
sha256 = "sha256-1aWqZynBkQoznenGoP0sbf1PcUXAbcHiWyECuv89xa0=";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "ApiSurface";
|
pname = "ApiSurface";
|
||||||
version = "4.0.28";
|
version = "4.0.39";
|
||||||
sha256 = "1gg0dqbgbb8aqn2lxi5gf2wq969kgskby5wph6m2b3hdkz7265ak";
|
sha256 = "sha256-I4K5nJbltsfL/1r+KPTIo2wUd30zsCC2pkrnIRnsRHM=";
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "coverlet.collector";
|
|
||||||
version = "6.0.0";
|
|
||||||
sha256 = "12j34vrkmph8lspbafnqmfnj2qvysz1jcrks2khw798s6dwv0j90";
|
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Fantomas.Core";
|
pname = "Fantomas.Core";
|
||||||
@@ -121,21 +116,11 @@
|
|||||||
version = "8.0.0";
|
version = "8.0.0";
|
||||||
sha256 = "0055f69q3hbagqp8gl3nk0vfn4qyqyxsxyy7pd0g7wm3z28byzmx";
|
sha256 = "0055f69q3hbagqp8gl3nk0vfn4qyqyxsxyy7pd0g7wm3z28byzmx";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.CodeCoverage";
|
|
||||||
version = "17.8.0";
|
|
||||||
sha256 = "173wjadp3gan4x2jfjchngnc4ca4mb95h1sbb28jydfkfw0z1zvj";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.CodeCoverage";
|
pname = "Microsoft.CodeCoverage";
|
||||||
version = "17.9.0";
|
version = "17.9.0";
|
||||||
sha256 = "1gljgi69k0fz8vy8bn6xlyxabj6q4vls2zza9wz7ng6ix3irm89r";
|
sha256 = "1gljgi69k0fz8vy8bn6xlyxabj6q4vls2zza9wz7ng6ix3irm89r";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.NET.Test.Sdk";
|
|
||||||
version = "17.8.0";
|
|
||||||
sha256 = "1syvl3g0hbrcgfi9rq6pld8s8hqqww4dflf1lxn59ccddyyx0gmv";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.NET.Test.Sdk";
|
pname = "Microsoft.NET.Test.Sdk";
|
||||||
version = "17.9.0";
|
version = "17.9.0";
|
||||||
@@ -281,21 +266,11 @@
|
|||||||
version = "8.0.0";
|
version = "8.0.0";
|
||||||
sha256 = "1gdx7n45wwia3yvang3ls92sk3wrymqcx9p349j8wba2lyjf9m44";
|
sha256 = "1gdx7n45wwia3yvang3ls92sk3wrymqcx9p349j8wba2lyjf9m44";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.TestPlatform.ObjectModel";
|
|
||||||
version = "17.8.0";
|
|
||||||
sha256 = "0b0i7lmkrcfvim8i3l93gwqvkhhhfzd53fqfnygdqvkg6np0cg7m";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.TestPlatform.ObjectModel";
|
pname = "Microsoft.TestPlatform.ObjectModel";
|
||||||
version = "17.9.0";
|
version = "17.9.0";
|
||||||
sha256 = "1kgsl9w9fganbm9wvlkqgk0ag9hfi58z88rkfybc6kvg78bx89ca";
|
sha256 = "1kgsl9w9fganbm9wvlkqgk0ag9hfi58z88rkfybc6kvg78bx89ca";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
|
||||||
pname = "Microsoft.TestPlatform.TestHost";
|
|
||||||
version = "17.8.0";
|
|
||||||
sha256 = "0f5jah93kjkvxwmhwb78lw11m9pkkq9fvf135hpymmmpxqbdh97q";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "Microsoft.TestPlatform.TestHost";
|
pname = "Microsoft.TestPlatform.TestHost";
|
||||||
version = "17.9.0";
|
version = "17.9.0";
|
||||||
@@ -316,11 +291,6 @@
|
|||||||
version = "3.6.133";
|
version = "3.6.133";
|
||||||
sha256 = "1cdw8krvsnx0n34f7fm5hiiy7bs6h3asvncqcikc0g46l50w2j80";
|
sha256 = "1cdw8krvsnx0n34f7fm5hiiy7bs6h3asvncqcikc0g46l50w2j80";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NETStandard.Library";
|
|
||||||
version = "2.0.0";
|
|
||||||
sha256 = "1bc4ba8ahgk15m8k4nd7x406nhi0kwqzbgjk2dmw52ss553xz7iy";
|
|
||||||
})
|
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NETStandard.Library";
|
pname = "NETStandard.Library";
|
||||||
version = "2.0.3";
|
version = "2.0.3";
|
||||||
@@ -338,28 +308,23 @@
|
|||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Common";
|
pname = "NuGet.Common";
|
||||||
version = "6.8.0";
|
version = "6.9.1";
|
||||||
sha256 = "0l3ij8iwy7wj6s7f93lzi9168r4wz8zyin6a08iwgk7hvq44cia1";
|
sha256 = "0ic3d46r9v05pkczpmskw86yzixm6iwshbw0ya8i2957nhhlymw8";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Configuration";
|
pname = "NuGet.Configuration";
|
||||||
version = "6.8.0";
|
version = "6.9.1";
|
||||||
sha256 = "0x03p408smkmv1gv7pmvsia4lkn0xaj4wfrkl58pjf8bbv51y0yw";
|
sha256 = "07z4qgbibpg59j2r05ifnqdyqf2xinm33rx7gjyr1f73kzg01m33";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Frameworks";
|
pname = "NuGet.Frameworks";
|
||||||
version = "6.5.0";
|
version = "6.9.1";
|
||||||
sha256 = "0s37d1p4md0k6d4cy6sq36f2dgkd9qfbzapxhkvi8awwh0vrynhj";
|
sha256 = "0s3az3ac53icjnmb14hfjcmkvzscvrkm62jgqf48yvsbysyhqm5s";
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NuGet.Frameworks";
|
|
||||||
version = "6.8.0";
|
|
||||||
sha256 = "0i2xvhgkjkjr496i3pg8hamwv6505fia45qhn7jg5m01wb3cvsjl";
|
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Packaging";
|
pname = "NuGet.Packaging";
|
||||||
version = "6.8.0";
|
version = "6.9.1";
|
||||||
sha256 = "031z4s905bxi94h3f0qy4j1b6jxdxgqgpkzqvvpfxch07szxcbim";
|
sha256 = "0w0arkmzg3qh1brq4vm10zrsjm7nw706ld4y5kqcmvjpd16f4b4y";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Protocol";
|
pname = "NuGet.Protocol";
|
||||||
@@ -368,18 +333,13 @@
|
|||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NuGet.Versioning";
|
pname = "NuGet.Versioning";
|
||||||
version = "6.8.0";
|
version = "6.9.1";
|
||||||
sha256 = "1sd25h46fd12ng780r02q4ijcx1imkb53kj1y2y7cwg5myh537ks";
|
sha256 = "0xrs82dydy9cgxf0qypr01wawwnq1nf6fc7rwisb4y5v4r259fdm";
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NUnit";
|
pname = "NUnit";
|
||||||
version = "3.13.3";
|
version = "4.1.0";
|
||||||
sha256 = "0wdzfkygqnr73s6lpxg5b1pwaqz9f414fxpvpdmf72bvh4jaqzv6";
|
sha256 = "0fj6xwgqaxq3mrai86bklclfmjkzf038mrslwfqf4ignaz9f7g5j";
|
||||||
})
|
|
||||||
(fetchNuGet {
|
|
||||||
pname = "NUnit";
|
|
||||||
version = "4.0.1";
|
|
||||||
sha256 = "0jgiq3dbwli5r70j0bw7021d69r7bhr58s8kphlpjmf7k47l5pcd";
|
|
||||||
})
|
})
|
||||||
(fetchNuGet {
|
(fetchNuGet {
|
||||||
pname = "NUnit3TestAdapter";
|
pname = "NUnit3TestAdapter";
|
||||||
|
|||||||
Reference in New Issue
Block a user