Use our DSLs a bit more (#154)

This commit is contained in:
Patrick Stevens
2024-05-31 19:20:28 +01:00
committed by GitHub
parent 8e47f39efc
commit 7b14e52e9d
17 changed files with 359 additions and 460 deletions

View File

@@ -195,7 +195,7 @@ type internal TypeWithInterfaceMock =
/// An implementation where every method throws. /// An implementation where every method throws.
static member Empty : TypeWithInterfaceMock = static member Empty : TypeWithInterfaceMock =
{ {
Dispose = (fun _ -> ()) Dispose = (fun () -> ())
Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function")) Mem1 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function")) Mem2 = (fun _ -> raise (System.NotImplementedException "Unimplemented mock function"))
} }

View File

@@ -193,12 +193,13 @@ module TestJsonSerde =
let decompose = FSharpValue.PreComputeUnionTagReader typeof<FirstDu> let decompose = FSharpValue.PreComputeUnionTagReader typeof<FirstDu>
Gen.listOf duGen let mutable i = 0
|> Gen.eval 100 (StdGen.StdGen (rand.Next (), rand.Next ()))
|> List.iter (fun du -> while i < 10_000 && Array.exists (fun i -> i = 0) counts do
let du = Gen.eval 10 (StdGen.StdGen (rand.Next (), rand.Next ())) duGen
let tag = decompose du let tag = decompose du
counts.[tag] <- counts.[tag] + 1 counts.[tag] <- counts.[tag] + 1
) i <- i + 1
for i in counts do for i in counts do
i |> shouldBeGreaterThan 0 i |> shouldBeGreaterThan 0

View File

@@ -3,7 +3,6 @@ namespace WoofWare.Myriad.Plugins
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range open Fantomas.FCS.Text.Range
open Fantomas.FCS.Xml open Fantomas.FCS.Xml
open Myriad.Core.AstExtensions
type internal ParameterInfo = type internal ParameterInfo =
{ {
@@ -137,12 +136,12 @@ module internal AstHelper =
| SynType.Paren (inner, _) -> | SynType.Paren (inner, _) ->
let result, _ = convertSigParam inner let result, _ = convertSigParam inner
result, true result, true
| SynType.LongIdent ident -> | SynType.LongIdent (SynLongIdent.SynLongIdent (ident, _, _)) ->
{ {
Attributes = [] Attributes = []
IsOptional = false IsOptional = false
Id = None Id = None
Type = SynType.CreateLongIdent ident Type = SynType.createLongIdent ident
}, },
false false
| SynType.SignatureParameter (attrs, opt, id, usedType, _) -> | SynType.SignatureParameter (attrs, opt, id, usedType, _) ->
@@ -191,7 +190,7 @@ module internal AstHelper =
let toFun (inputs : SynType list) (ret : SynType) : SynType = let toFun (inputs : SynType list) (ret : SynType) : SynType =
(ret, List.rev inputs) (ret, List.rev inputs)
||> List.fold (fun ty input -> SynType.CreateFun (input, ty)) ||> List.fold (fun ty input -> SynType.funFromDomain input ty)
/// Returns the args (where these are tuple types if curried) in order, and the return type. /// Returns the args (where these are tuple types if curried) in order, and the return type.
let rec getType (ty : SynType) : (SynType * bool) list * SynType = let rec getType (ty : SynType) : (SynType * bool) list * SynType =

View File

@@ -62,15 +62,15 @@ module internal CataGenerator =
Fields : CataUnionField list Fields : CataUnionField list
/// The corresponding method of the appropriate cata, fully-qualified as a call /// The corresponding method of the appropriate cata, fully-qualified as a call
/// into some specific cata /// into some specific cata
CataMethodName : SynLongIdent CataMethodName : LongIdent
/// The identifier of the method of the appropriate cata /// The identifier of the method of the appropriate cata
CataMethodIdent : SynIdent CataMethodIdent : SynIdent
/// The Instruction case which instructs the state machine to pull anything /// The Instruction case which instructs the state machine to pull anything
/// necessary from the stacks and call into the cata. /// necessary from the stacks and call into the cata.
AssociatedInstruction : SynLongIdent AssociatedInstruction : LongIdent
/// Matching on an element of this union type, if you match against this /// Matching on an element of this union type, if you match against this
/// left-hand side (and give appropriate field arguments), you will enter this union case. /// left-hand side (and give appropriate field arguments), you will enter this union case.
Match : SynLongIdent Match : LongIdent
} }
member this.FlattenedFields : CataUnionBasicField list = member this.FlattenedFields : CataUnionBasicField list =
@@ -98,7 +98,7 @@ module internal CataGenerator =
/// (i.e. when we enter the loop for the first time). /// (i.e. when we enter the loop for the first time).
/// The state machine interprets this instruction as "break me apart and /// The state machine interprets this instruction as "break me apart and
/// descend recursively if necessary before coming back to me". /// descend recursively if necessary before coming back to me".
AssociatedProcessInstruction : SynLongIdent AssociatedProcessInstruction : LongIdent
/// Name of the parent type: e.g. in `type Foo = | Blah`, this is `Foo`. /// Name of the parent type: e.g. in `type Foo = | Blah`, this is `Foo`.
ParentTypeName : LongIdent ParentTypeName : LongIdent
/// The name of the generic type parameter we'll use within the cata /// The name of the generic type parameter we'll use within the cata
@@ -165,7 +165,7 @@ module internal CataGenerator =
) )
[ [
SynExpr.CreateLongIdent analysis.AssociatedProcessInstruction SynExpr.createLongIdent' analysis.AssociatedProcessInstruction
|> SynExpr.applyTo (SynExpr.createLongIdent [ "x" ]) |> SynExpr.applyTo (SynExpr.createLongIdent [ "x" ])
|> SynExpr.paren |> SynExpr.paren
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "instructions" ; "Add" ]) |> SynExpr.applyFunction (SynExpr.createLongIdent [ "instructions" ; "Add" ])
@@ -178,17 +178,11 @@ module internal CataGenerator =
SynBinding.Let ( SynBinding.Let (
valData = SynValData.SynValData (None, SynValInfo.Empty, None), valData = SynValData.SynValData (None, SynValInfo.Empty, None),
pattern = pattern =
SynPat.Tuple ( SynPat.tupleNoParen (
false, allArtificialTyparNames
List.map |> List.map (fun (t : Ident) ->
(fun (t : Ident) -> SynPat.namedI (Ident.create (t.idText + "Stack") |> Ident.lowerFirstLetter)
SynPat.CreateNamed ( )
Ident.Create (t.idText + "Stack") |> Ident.lowerFirstLetter
)
)
allArtificialTyparNames,
List.replicate (allArtificialTyparNames.Length - 1) range0,
range0
), ),
expr = expr =
SynExpr.applyFunction SynExpr.applyFunction
@@ -197,17 +191,15 @@ module internal CataGenerator =
) )
] ]
] ]
|> SynExpr.CreateSequential |> SynExpr.sequential
|> SynExpr.createLet |> SynExpr.createLet
[ [
SynExpr.createIdent "ResizeArray" SynExpr.createIdent "ResizeArray"
|> SynExpr.applyTo (SynExpr.CreateConst ()) |> SynExpr.applyTo (SynExpr.CreateConst ())
|> SynBinding.basic (SynLongIdent.createS "instructions") [] |> SynBinding.basic [ Ident.create "instructions" ] []
] ]
|> SynExpr.typeAnnotate relevantTypar |> SynExpr.typeAnnotate relevantTypar
|> SynBinding.basic |> SynBinding.basic [ Ident.create ("run" + List.last(relevantTypeName).idText) ] [ cataObject ; inputObject ]
(SynLongIdent.createS ("run" + List.last(relevantTypeName).idText))
[ cataObject ; inputObject ]
|> SynBinding.withReturnAnnotation relevantTypar |> SynBinding.withReturnAnnotation relevantTypar
|> SynBinding.withXmlDoc (PreXmlDoc.create "Execute the catamorphism.") |> SynBinding.withXmlDoc (PreXmlDoc.create "Execute the catamorphism.")
@@ -361,7 +353,7 @@ module internal CataGenerator =
| FieldDescription.Self ty -> true, None | FieldDescription.Self ty -> true, None
| FieldDescription.ListSelf ty -> | FieldDescription.ListSelf ty ->
// store the length of the list // store the length of the list
true, Some (SynType.Int ()) true, Some SynType.int
type InstructionCase = type InstructionCase =
{ {
@@ -423,9 +415,7 @@ module internal CataGenerator =
unions unions
|> List.map (fun union -> |> List.map (fun union ->
{ {
Name = Name = List.last union.AssociatedProcessInstruction
match union.AssociatedProcessInstruction with
| SynLongIdent.SynLongIdent (i, _, _) -> List.last i
Fields = Fields =
{ {
Name = None Name = None
@@ -493,7 +483,7 @@ module internal CataGenerator =
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText) |> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|> List.distinct |> List.distinct
|> List.map (fun i -> |> List.map (fun i ->
SynTyparDecl.SynTyparDecl ([], SynTypar.SynTypar (Ident.Create i, TyparStaticReq.None, false)) SynTyparDecl.SynTyparDecl ([], SynTypar.SynTypar (Ident.create i, TyparStaticReq.None, false))
) )
SynTypeDefnRepr.union cases SynTypeDefnRepr.union cases
@@ -501,7 +491,7 @@ module internal CataGenerator =
SynComponentInfo.create (Ident.create "Instruction") SynComponentInfo.create (Ident.create "Instruction")
|> SynComponentInfo.withGenerics typars |> SynComponentInfo.withGenerics typars
|> SynComponentInfo.withAccessibility (SynAccess.Private range0) |> SynComponentInfo.withAccessibility (SynAccess.Private range0)
|> SynComponentInfo.addAttributes [ SynAttribute.RequireQualifiedAccess () ] |> SynComponentInfo.addAttributes [ SynAttribute.requireQualifiedAccess ]
) )
/// Build the cata interfaces, which a user will instantiate to specify a particular /// Build the cata interfaces, which a user will instantiate to specify a particular
@@ -577,7 +567,7 @@ module internal CataGenerator =
case.CataMethodIdent case.CataMethodIdent
None None
arity arity
(PreXmlDoc.create $"How to operate on the %s{List.last(case.Match.LongIdent).idText} case") (PreXmlDoc.create $"How to operate on the %s{List.last(case.Match).idText} case")
) )
|> SynTypeDefnRepr.interfaceType |> SynTypeDefnRepr.interfaceType
|> SynTypeDefn.create componentInfo |> SynTypeDefn.create componentInfo
@@ -607,7 +597,7 @@ module internal CataGenerator =
analysis.Typars analysis.Typars
|> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText) |> List.map (fun (SynTyparDecl.SynTyparDecl (_, SynTypar.SynTypar (ident, _, _))) -> ident.idText)
|> List.distinct |> List.distinct
|> List.map (fun i -> SynType.var (SynTypar.SynTypar (Ident.Create i, TyparStaticReq.None, false))) |> List.map (fun i -> SynType.var (SynTypar.SynTypar (Ident.create i, TyparStaticReq.None, false)))
let ty = let ty =
SynType.app' SynType.app'
@@ -713,20 +703,19 @@ module internal CataGenerator =
InstructionName = instructionName InstructionName = instructionName
Fields = analysis Fields = analysis
CaseName = name CaseName = name
CataMethodName = SynLongIdent.create (cataVarName :: unionTypeName @ [ unionCaseName ]) CataMethodName = cataVarName :: unionTypeName @ [ unionCaseName ]
CataMethodIdent = SynIdent.SynIdent (unionCaseName, None) CataMethodIdent = SynIdent.SynIdent (unionCaseName, None)
AssociatedInstruction = AssociatedInstruction = [ Ident.create "Instruction" ; instructionName ]
SynLongIdent.create [ Ident.create "Instruction" ; instructionName ] Match = unionTypeName @ [ unionCaseName ]
Match = SynLongIdent.create (unionTypeName @ [ unionCaseName ])
} }
) )
AssociatedProcessInstruction = AssociatedProcessInstruction =
SynLongIdent.createS' [
[ "Instruction"
"Instruction" // such jank!
// such jank! "Process__" + List.last(unionTypeName).idText
"Process__" + List.last(unionTypeName).idText ]
] |> List.map Ident.create
ParentTypeName = getName unionType ParentTypeName = getName unionType
GenericName = getName unionType |> List.map _.idText |> String.concat "" |> Ident.create GenericName = getName unionType |> List.map _.idText |> String.concat "" |> Ident.create
CataTypeName = List.last(getName unionType).idText + "CataCase" |> Ident.create CataTypeName = List.last(getName unionType).idText + "CataCase" |> Ident.create
@@ -734,9 +723,9 @@ module internal CataGenerator =
) )
let callCataAndPushResult (resultStackName : Ident) (unionCase : RenderedUnionCase) : SynExpr = let callCataAndPushResult (resultStackName : Ident) (unionCase : RenderedUnionCase) : SynExpr =
(SynExpr.CreateLongIdent unionCase.CataMethodName, unionCase.FlattenedFields) (SynExpr.createLongIdent' unionCase.CataMethodName, unionCase.FlattenedFields)
||> List.fold (fun body caseDesc -> SynExpr.applyFunction body (SynExpr.createIdent' caseDesc.ArgName)) ||> List.fold (fun body caseDesc -> SynExpr.applyFunction body (SynExpr.createIdent' caseDesc.ArgName))
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent' (resultStackName :: [ Ident.Create "Add" ])) |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent' (resultStackName :: [ Ident.create "Add" ]))
/// Create the state-machine matches which deal with receiving the instruction /// Create the state-machine matches which deal with receiving the instruction
/// to "process one of the user-specified DU cases, pushing recursion instructions onto /// to "process one of the user-specified DU cases, pushing recursion instructions onto
@@ -771,7 +760,7 @@ module internal CataGenerator =
// The instruction to process us again once our inputs are ready: // The instruction to process us again once our inputs are ready:
let reprocessCommand = let reprocessCommand =
if selfArgs.Length = unionCase.FlattenedFields.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.
listSelfArgs listSelfArgs
@@ -788,8 +777,8 @@ module internal CataGenerator =
) )
|> List.sortBy fst |> List.sortBy fst
|> List.map snd |> List.map snd
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
|> SynExpr.applyFunction (SynExpr.CreateLongIdent unionCase.AssociatedInstruction) |> SynExpr.applyFunction (SynExpr.createLongIdent' unionCase.AssociatedInstruction)
|> SynExpr.paren |> SynExpr.paren
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "instructions" ; "Add" ]) |> SynExpr.applyFunction (SynExpr.createLongIdent [ "instructions" ; "Add" ])
@@ -815,7 +804,7 @@ module internal CataGenerator =
(SynExpr.createLongIdent [ "instructions" ; "Add" ]) (SynExpr.createLongIdent [ "instructions" ; "Add" ])
(SynExpr.paren ( (SynExpr.paren (
SynExpr.applyFunction SynExpr.applyFunction
(SynExpr.CreateLongIdent analysis.AssociatedProcessInstruction) (SynExpr.createLongIdent' analysis.AssociatedProcessInstruction)
(SynExpr.createIdent "elt") (SynExpr.createIdent "elt")
)), )),
range0 range0
@@ -835,66 +824,36 @@ module internal CataGenerator =
|> SynExpr.paren |> SynExpr.paren
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "instructions" ; "Add" ]) |> SynExpr.applyFunction (SynExpr.createLongIdent [ "instructions" ; "Add" ])
] ]
|> SynExpr.CreateSequential |> SynExpr.sequential
let matchLhs = let matchLhs =
if unionCase.Fields.Length > 0 then if not unionCase.Fields.IsEmpty then
SynPat.Tuple ( unionCase.Fields
false, |> List.mapi (fun i case ->
unionCase.Fields match case with
|> List.mapi (fun i case -> | CataUnionField.Basic case -> SynPat.namedI (Ident.lowerFirstLetter case.ArgName)
match case with | CataUnionField.Record fields ->
| CataUnionField.Basic case -> let fields =
SynPat.CreateNamed (Ident.lowerFirstLetter case.ArgName) fields
| CataUnionField.Record fields -> |> List.map (fun (name, field) ->
let fields = ([], name), range0, SynPat.namedI (Ident.lowerFirstLetter name)
fields )
|> List.map (fun (name, field) ->
([], name), range0, SynPat.CreateNamed (Ident.lowerFirstLetter name)
)
SynPat.Record (fields, range0) SynPat.Record (fields, range0)
),
List.replicate (unionCase.Fields.Length - 1) range0,
range0
) )
|> SynPat.CreateParen |> SynPat.tuple
|> List.singleton |> List.singleton
else else
[] []
SynMatchClause.SynMatchClause ( SynMatchClause.create
SynPat.CreateLongIdent (unionCase.Match, matchLhs), (SynPat.CreateLongIdent (SynLongIdent.create unionCase.Match, matchLhs))
None, matchBody
matchBody,
range0,
DebugPointAtTarget.Yes,
{
ArrowRange = Some range0
BarRange = Some range0
}
)
) )
let bodyMatch = SynExpr.createMatch (SynExpr.createIdent "x") matchCases SynExpr.createMatch (SynExpr.createIdent "x") matchCases
|> SynMatchClause.create (
SynMatchClause.SynMatchClause ( SynPat.identWithArgs analysis.AssociatedProcessInstruction (SynArgPats.create [ Ident.create "x" ])
SynPat.LongIdent (
analysis.AssociatedProcessInstruction,
None,
None,
SynArgPats.create [ Ident.create "x" ],
None,
range0
),
None,
bodyMatch,
range0,
DebugPointAtTarget.Yes,
{
ArrowRange = Some range0
BarRange = Some range0
}
) )
/// Create the state-machine matches which deal with receiving the instruction /// Create the state-machine matches which deal with receiving the instruction
@@ -927,7 +886,7 @@ module internal CataGenerator =
None None
) )
|> List.map (fun unionCase -> |> List.map (fun unionCase ->
let lhsNames = let pat =
unionCase.FlattenedFields unionCase.FlattenedFields
|> Seq.mapi (fun i x -> (i, x)) |> Seq.mapi (fun i x -> (i, x))
|> Seq.choose (fun (i, case) -> |> Seq.choose (fun (i, case) ->
@@ -937,11 +896,8 @@ module internal CataGenerator =
| FieldDescription.Self _ -> None | FieldDescription.Self _ -> None
) )
|> Seq.toList |> Seq.toList
|> SynArgPats.create
let lhs = SynArgPats.create lhsNames |> SynPat.identWithArgs unionCase.AssociatedInstruction
let pat =
SynPat.LongIdent (unionCase.AssociatedInstruction, None, None, lhs, None, range0)
let populateArgs = let populateArgs =
unionCase.FlattenedFields unionCase.FlattenedFields
@@ -970,7 +926,7 @@ module internal CataGenerator =
range0, range0,
range0 range0
) )
|> SynBinding.basic (SynLongIdent.createI field.ArgName) [] |> SynBinding.basic [ field.ArgName ] []
] ]
|> Some |> Some
| ListSelf synType -> | ListSelf synType ->
@@ -1006,7 +962,7 @@ module internal CataGenerator =
) )
|> SynExpr.applyFunction (SynExpr.createIdent "seq") |> SynExpr.applyFunction (SynExpr.createIdent "seq")
|> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "Seq" ; "toList" ]) |> SynExpr.pipeThroughFunction (SynExpr.createLongIdent [ "Seq" ; "toList" ])
|> SynBinding.basic (SynLongIdent.createI field.ArgName) [] |> SynBinding.basic [ field.ArgName ] []
let shadowedIdent = Ident.create (field.ArgName.idText + "_len") let shadowedIdent = Ident.create (field.ArgName.idText + "_len")
@@ -1016,23 +972,18 @@ module internal CataGenerator =
(SynExpr.createIdent' shadowedIdent) (SynExpr.createIdent' shadowedIdent)
SynExpr.createIdent' shadowedIdent SynExpr.createIdent' shadowedIdent
] ]
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
|> SynExpr.applyFunction ( |> SynExpr.applyFunction (
SynExpr.createLongIdent' [ stackName ; Ident.create "RemoveRange" ] SynExpr.createLongIdent' [ stackName ; Ident.create "RemoveRange" ]
) )
|> SynExpr.createLet [ vals ] |> SynExpr.createLet [ vals ]
|> SynExpr.createLet |> SynExpr.createLet
[ [ SynBinding.basic [ shadowedIdent ] [] (SynExpr.createIdent' field.ArgName) ]
SynBinding.basic
(SynLongIdent.createI shadowedIdent)
[]
(SynExpr.createIdent' field.ArgName)
]
|> Some |> Some
) )
(populateArgs @ [ callCataAndPushResult analysis.StackName unionCase ]) (populateArgs @ [ callCataAndPushResult analysis.StackName unionCase ])
|> SynExpr.CreateSequential |> SynExpr.sequential
|> SynMatchClause.create pat |> SynMatchClause.create pat
) )
) )
@@ -1082,7 +1033,7 @@ module internal CataGenerator =
(SynExpr.paren (SynExpr.minusN (SynLongIdent.createS' [ "instructions" ; "Count" ]) 1)) (SynExpr.paren (SynExpr.minusN (SynLongIdent.createS' [ "instructions" ; "Count" ]) 1))
matchStatement matchStatement
] ]
|> SynExpr.CreateSequential |> SynExpr.sequential
|> SynExpr.createLet |> SynExpr.createLet
[ [
SynExpr.DotIndexedGet ( SynExpr.DotIndexedGet (
@@ -1091,11 +1042,11 @@ module internal CataGenerator =
range0, range0,
range0 range0
) )
|> SynBinding.basic (SynLongIdent.createS "currentInstruction") [] |> SynBinding.basic [ Ident.create "currentInstruction" ] []
] ]
let body = let body =
SynExpr.CreateSequential SynExpr.sequential
[ [
SynExpr.createWhile SynExpr.createWhile
(SynExpr.greaterThan (SynExpr.greaterThan
@@ -1126,11 +1077,11 @@ module internal CataGenerator =
range0 range0
) )
|> SynExpr.applyTo (SynExpr.CreateConst ()) |> SynExpr.applyTo (SynExpr.CreateConst ())
|> SynBinding.basic (SynLongIdent.createI unionCase.StackName) [] |> SynBinding.basic [ unionCase.StackName ] []
] ]
) )
SynBinding.basic (SynLongIdent.createS "loop") args body SynBinding.basic [ Ident.create "loop" ] args body
|> SynBinding.withAccessibility (Some (SynAccess.Private range0)) |> SynBinding.withAccessibility (Some (SynAccess.Private range0))
let createModule let createModule
@@ -1154,7 +1105,7 @@ module internal CataGenerator =
|> SynComponentInfo.withDocString ( |> SynComponentInfo.withDocString (
PreXmlDoc.Create $" Methods to perform a catamorphism over the type %s{parentName}" PreXmlDoc.Create $" Methods to perform a catamorphism over the type %s{parentName}"
) )
|> SynComponentInfo.addAttributes [ SynAttribute.RequireQualifiedAccess () ] |> SynComponentInfo.addAttributes [ SynAttribute.requireQualifiedAccess ]
let cataVarName = Ident.create "cata" let cataVarName = Ident.create "cata"
let analysis = makeUnionAnalyses cataVarName allRecordTypes allUnionTypes let analysis = makeUnionAnalyses cataVarName allRecordTypes allUnionTypes

View File

@@ -82,7 +82,7 @@ module internal HttpClientGenerator =
let matchingAttrs = let matchingAttrs =
attrs attrs
|> List.choose (fun attr -> |> List.choose (fun attr ->
match attr.TypeName.AsString with match SynLongIdent.toString attr.TypeName with
| "Get" | "Get"
| "GetAttribute" | "GetAttribute"
| "WoofWare.Myriad.Plugins.RestEase.Get" | "WoofWare.Myriad.Plugins.RestEase.Get"
@@ -144,7 +144,7 @@ module internal HttpClientGenerator =
let extractHeaderInformation (attrs : SynAttribute list) : SynExpr list list = let extractHeaderInformation (attrs : SynAttribute list) : SynExpr list list =
attrs attrs
|> List.choose (fun attr -> |> List.choose (fun attr ->
match attr.TypeName.AsString with match SynLongIdent.toString attr.TypeName with
| "Header" | "Header"
| "RestEase.Header" | "RestEase.Header"
| "WoofWare.Myriad.Plugins.RestEase.Header" -> | "WoofWare.Myriad.Plugins.RestEase.Header" ->
@@ -158,7 +158,7 @@ module internal HttpClientGenerator =
let shouldAllowAnyStatusCode (attrs : SynAttribute list) : bool = let shouldAllowAnyStatusCode (attrs : SynAttribute list) : bool =
attrs attrs
|> List.exists (fun attr -> |> List.exists (fun attr ->
match attr.TypeName.AsString with match SynLongIdent.toString attr.TypeName with
| "AllowAnyStatusCode" | "AllowAnyStatusCode"
| "AllowAnyStatusCodeAttribute" | "AllowAnyStatusCodeAttribute"
| "RestEase.AllowAnyStatusCode" | "RestEase.AllowAnyStatusCode"
@@ -225,25 +225,15 @@ module internal HttpClientGenerator =
| None -> failwith $"expected an optional cancellation token as final arg in %s{info.Identifier.idText}" | None -> failwith $"expected an optional cancellation token as final arg in %s{info.Identifier.idText}"
| Some (arg, _) -> arg | Some (arg, _) -> arg
let argPats =
let args = args |> List.map snd
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|> SynPat.CreateParen
|> List.singleton
|> SynArgPats.Pats
let headPat = let headPat =
let thisIdent = if variableHeaders.IsEmpty then "_" else "this" let thisIdent = if variableHeaders.IsEmpty then "_" else "this"
SynPat.LongIdent ( args
SynLongIdent.create [ Ident.create thisIdent ; info.Identifier ], |> List.map snd
None, |> SynPat.tuple
None, |> List.singleton
argPats, |> SynArgPats.Pats
None, |> SynPat.identWithArgs [ Ident.create thisIdent ; info.Identifier ]
range0
)
let requestUriTrailer = let requestUriTrailer =
(info.UrlTemplate, info.Args) (info.UrlTemplate, info.Args)
@@ -265,10 +255,10 @@ module internal HttpClientGenerator =
template template
|> SynExpr.callMethodArg |> SynExpr.callMethodArg
"Replace" "Replace"
(SynExpr.CreateParenedTuple (SynExpr.tuple
[ [
SynExpr.CreateConst ("{" + substituteId + "}") SynExpr.CreateConst ("{" + substituteId + "}")
SynExpr.callMethod "ToString" (SynExpr.CreateIdent varName) SynExpr.callMethod "ToString" (SynExpr.createIdent' varName)
|> SynExpr.pipeThroughFunction ( |> SynExpr.pipeThroughFunction (
SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ] SynExpr.createLongIdent [ "System" ; "Web" ; "HttpUtility" ; "UrlEncode" ]
) )
@@ -357,45 +347,37 @@ module internal HttpClientGenerator =
let baseAddress = let baseAddress =
[ [
SynMatchClause.Create ( SynMatchClause.create
SynPat.CreateNull, SynPat.createNull
None, (match info.BaseAddress with
match info.BaseAddress with | None ->
| None -> [
[ SynExpr.applyFunction (SynExpr.createIdent "nameof") (SynExpr.paren baseAddress)
SynExpr.applyFunction (SynExpr.createIdent "nameof") (SynExpr.paren baseAddress) SynExpr.CreateConst
SynExpr.CreateConst "No base address was supplied on the type, and no BaseAddress was on the HttpClient."
"No base address was supplied on the type, and no BaseAddress was on the HttpClient." ]
] |> SynExpr.tuple
|> SynExpr.CreateParenedTuple |> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "ArgumentNullException" ])
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "System" ; "ArgumentNullException" ]) |> SynExpr.paren
|> SynExpr.paren |> SynExpr.applyFunction (SynExpr.createIdent "raise")
|> SynExpr.applyFunction (SynExpr.createIdent "raise") | Some expr -> SynExpr.applyFunction uriIdent expr)
| Some expr -> SynExpr.applyFunction uriIdent expr SynMatchClause.create (SynPat.named "v") (SynExpr.createIdent "v")
)
SynMatchClause.Create (SynPat.named "v", None, SynExpr.createIdent "v")
] ]
|> SynExpr.createMatch baseAddress |> SynExpr.createMatch baseAddress
|> SynExpr.paren |> SynExpr.paren
SynExpr.App ( [
ExprAtomicFlag.Atomic, baseAddress
false, SynExpr.applyFunction
uriIdent, uriIdent
SynExpr.CreateParenedTuple (SynExpr.tuple
[ [
baseAddress requestUriTrailer
SynExpr.CreateApp ( SynExpr.createLongIdent [ "System" ; "UriKind" ; "Relative" ]
uriIdent, ])
SynExpr.CreateParenedTuple ]
[ |> SynExpr.tuple
requestUriTrailer |> SynExpr.applyFunction uriIdent
SynExpr.createLongIdent [ "System" ; "UriKind" ; "Relative" ]
]
)
],
range0
)
let bodyParams = let bodyParams =
info.Args info.Args
@@ -434,7 +416,7 @@ module internal HttpClientGenerator =
[ "System" ; "Net" ; "Http" ; "HttpMethod" ; httpMethodString info.HttpMethod ]) [ "System" ; "Net" ; "Http" ; "HttpMethod" ; httpMethodString info.HttpMethod ])
SynExpr.equals (SynExpr.createIdent "RequestUri") (SynExpr.createIdent "uri") SynExpr.equals (SynExpr.createIdent "RequestUri") (SynExpr.createIdent "uri")
] ]
|> SynExpr.CreateTuple |> SynExpr.tupleNoParen
let returnExpr = let returnExpr =
match info.TaskReturnType with match info.TaskReturnType with
@@ -559,7 +541,7 @@ module internal HttpClientGenerator =
SynExpr.applyFunction SynExpr.applyFunction
(SynExpr.createLongIdent (SynExpr.createLongIdent
[ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ; "ParseAsync" ]) [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ; "ParseAsync" ])
(SynExpr.CreateParenedTuple (SynExpr.tuple
[ [
SynExpr.createIdent "responseStream" SynExpr.createIdent "responseStream"
SynExpr.equals (SynExpr.createIdent "cancellationToken") (SynExpr.createIdent "ct") SynExpr.equals (SynExpr.createIdent "cancellationToken") (SynExpr.createIdent "ct")
@@ -574,10 +556,10 @@ module internal HttpClientGenerator =
headerName headerName
SynExpr.applyFunction SynExpr.applyFunction
(SynExpr.createLongIdent' (SynExpr.createLongIdent'
[ Ident.Create "this" ; callToGetValue ; Ident.Create "ToString" ]) [ Ident.create "this" ; callToGetValue ; Ident.create "ToString" ])
(SynExpr.CreateConst ()) (SynExpr.CreateConst ())
] ]
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ]) |> SynExpr.applyFunction (SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ])
|> Do |> Do
) )
@@ -587,7 +569,7 @@ module internal HttpClientGenerator =
|> List.map (fun (headerName, headerValue) -> |> List.map (fun (headerName, headerValue) ->
SynExpr.applyFunction SynExpr.applyFunction
(SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ]) (SynExpr.createLongIdent [ "httpMessage" ; "Headers" ; "Add" ])
(SynExpr.CreateParenedTuple [ headerName ; headerValue ]) (SynExpr.tuple [ headerName ; headerValue ])
|> Do |> Do
) )
@@ -613,8 +595,7 @@ module internal HttpClientGenerator =
SynExpr.awaitTask ( SynExpr.awaitTask (
SynExpr.applyFunction SynExpr.applyFunction
(SynExpr.createLongIdent [ "client" ; "SendAsync" ]) (SynExpr.createLongIdent [ "client" ; "SendAsync" ])
(SynExpr.CreateParenedTuple (SynExpr.tuple [ SynExpr.createIdent "httpMessage" ; SynExpr.createIdent "ct" ])
[ SynExpr.createIdent "httpMessage" ; SynExpr.createIdent "ct" ])
) )
) )
if info.EnsureSuccessHttpCode then if info.EnsureSuccessHttpCode then
@@ -638,7 +619,7 @@ module internal HttpClientGenerator =
yield jsonNode yield jsonNode
] ]
|> SynExpr.createCompExpr "async" returnExpr |> SynExpr.createCompExpr "async" returnExpr
|> SynExpr.startAsTask (SynLongIdent.createI cancellationTokenArg) |> SynExpr.startAsTask cancellationTokenArg
SynBinding.SynBinding ( SynBinding.SynBinding (
None, None,
@@ -661,7 +642,7 @@ module internal HttpClientGenerator =
let getHttpAttributes (attrs : SynAttribute list) : HttpAttribute list = let getHttpAttributes (attrs : SynAttribute list) : HttpAttribute list =
attrs attrs
|> List.choose (fun attr -> |> List.choose (fun attr ->
match attr.TypeName.AsString with match SynLongIdent.toString attr.TypeName with
| "RestEase.Query" | "RestEase.Query"
| "RestEase.QueryAttribute" | "RestEase.QueryAttribute"
| "WoofWare.Myriad.Plugins.RestEase.Query" | "WoofWare.Myriad.Plugins.RestEase.Query"
@@ -702,7 +683,7 @@ module internal HttpClientGenerator =
let extractBasePath (attrs : SynAttribute list) : SynExpr option = let extractBasePath (attrs : SynAttribute list) : SynExpr option =
attrs attrs
|> List.tryPick (fun attr -> |> List.tryPick (fun attr ->
match attr.TypeName.AsString with match SynLongIdent.toString attr.TypeName with
| "BasePath" | "BasePath"
| "RestEase.BasePath" | "RestEase.BasePath"
| "WoofWare.Myriad.Plugins.RestEase.BasePath" | "WoofWare.Myriad.Plugins.RestEase.BasePath"
@@ -715,7 +696,7 @@ module internal HttpClientGenerator =
let extractBaseAddress (attrs : SynAttribute list) : SynExpr option = let extractBaseAddress (attrs : SynAttribute list) : SynExpr option =
attrs attrs
|> List.tryPick (fun attr -> |> List.tryPick (fun attr ->
match attr.TypeName.AsString with match SynLongIdent.toString attr.TypeName with
| "BaseAddress" | "BaseAddress"
| "RestEase.BaseAddress" | "RestEase.BaseAddress"
| "WoofWare.Myriad.Plugins.RestEase.BaseAddress" | "WoofWare.Myriad.Plugins.RestEase.BaseAddress"
@@ -947,7 +928,7 @@ module internal HttpClientGenerator =
let createFunc = let createFunc =
if spec.ExtensionMethods then if spec.ExtensionMethods then
let binding = let binding =
SynBinding.basic (SynLongIdent.createS "make") (headerArgs @ [ clientCreationArg ]) interfaceImpl SynBinding.basic [ Ident.create "make" ] (headerArgs @ [ clientCreationArg ]) interfaceImpl
|> SynBinding.withXmlDoc xmlDoc |> SynBinding.withXmlDoc xmlDoc
|> SynBinding.withReturnAnnotation returnInfo |> SynBinding.withReturnAnnotation returnInfo
|> SynMemberDefn.staticMember |> SynMemberDefn.staticMember
@@ -964,7 +945,7 @@ module internal HttpClientGenerator =
SynModuleDecl.Types ([ containingType ], range0) SynModuleDecl.Types ([ containingType ], range0)
else else
SynBinding.basic (SynLongIdent.createS "make") (headerArgs @ [ clientCreationArg ]) interfaceImpl SynBinding.basic [ Ident.create "make" ] (headerArgs @ [ clientCreationArg ]) interfaceImpl
|> SynBinding.withXmlDoc xmlDoc |> SynBinding.withXmlDoc xmlDoc
|> SynBinding.withReturnAnnotation returnInfo |> SynBinding.withReturnAnnotation returnInfo
|> List.singleton |> List.singleton
@@ -980,10 +961,7 @@ module internal HttpClientGenerator =
if spec.ExtensionMethods then if spec.ExtensionMethods then
[ SynAttribute.autoOpen ] [ SynAttribute.autoOpen ]
else else
[ [ SynAttribute.compilationRepresentation ; SynAttribute.requireQualifiedAccess ]
SynAttribute.compilationRepresentation
SynAttribute.RequireQualifiedAccess ()
]
let modInfo = let modInfo =
SynComponentInfo.create moduleName SynComponentInfo.create moduleName

View File

@@ -49,13 +49,13 @@ module internal InterfaceMockGenerator =
let failwithFun = let failwithFun =
SynExpr.createLongIdent [ "System" ; "NotImplementedException" ] SynExpr.createLongIdent [ "System" ; "NotImplementedException" ]
|> SynExpr.applyTo (SynExpr.CreateConst "Unimplemented mock function") |> SynExpr.applyTo (SynExpr.CreateConst "Unimplemented mock function")
|> SynExpr.CreateParen |> SynExpr.paren
|> SynExpr.applyFunction (SynExpr.createIdent "raise") |> SynExpr.applyFunction (SynExpr.createIdent "raise")
|> SynExpr.createLambda "_" |> SynExpr.createLambda "_"
let constructorReturnType = let constructorReturnType =
match interfaceType.Generics with match interfaceType.Generics with
| None -> SynType.CreateLongIdent name | None -> SynType.createLongIdent' [ name ]
| Some generics -> | Some generics ->
let generics = let generics =
@@ -67,7 +67,7 @@ module internal InterfaceMockGenerator =
let constructorFields = let constructorFields =
let extras = let extras =
if inherits.Contains KnownInheritance.IDisposable then if inherits.Contains KnownInheritance.IDisposable then
let unitFun = SynExpr.createLambda "_" SynExpr.CreateUnit let unitFun = SynExpr.createThunk (SynExpr.CreateConst ())
[ (SynLongIdent.createS "Dispose", true), Some unitFun ] [ (SynLongIdent.createS "Dispose", true), Some unitFun ]
else else
@@ -81,14 +81,14 @@ module internal InterfaceMockGenerator =
let constructor = let constructor =
SynBinding.basic SynBinding.basic
(SynLongIdent.createS "Empty") [ Ident.create "Empty" ]
(if interfaceType.Generics.IsNone then (if interfaceType.Generics.IsNone then
[] []
else else
[ SynPat.CreateConst SynConst.Unit ]) [ SynPat.unit ])
(AstHelper.instantiateRecord constructorFields) (AstHelper.instantiateRecord constructorFields)
|> SynBinding.makeStaticMember |> SynBinding.makeStaticMember
|> SynBinding.withXmlDoc (PreXmlDoc.Create " An implementation where every method throws.") |> SynBinding.withXmlDoc (PreXmlDoc.create "An implementation where every method throws.")
|> SynBinding.withReturnAnnotation constructorReturnType |> SynBinding.withReturnAnnotation constructorReturnType
|> fun m -> SynMemberDefn.Member (m, range0) |> fun m -> SynMemberDefn.Member (m, range0)
@@ -97,9 +97,9 @@ module internal InterfaceMockGenerator =
if inherits.Contains KnownInheritance.IDisposable then if inherits.Contains KnownInheritance.IDisposable then
[ [
SynField.Create ( SynField.Create (
SynType.CreateFun (SynType.CreateUnit, SynType.CreateUnit), SynType.funFromDomain SynType.unit SynType.unit,
Ident.Create "Dispose", Ident.create "Dispose",
xmldoc = PreXmlDoc.Create " Implementation of IDisposable.Dispose" xmldoc = PreXmlDoc.create "Implementation of IDisposable.Dispose"
) )
] ]
else else
@@ -159,22 +159,20 @@ module internal InterfaceMockGenerator =
tupledArgs.Args tupledArgs.Args
|> List.mapi (fun j ty -> |> List.mapi (fun j ty ->
match ty.Type with match ty.Type with
| UnitType -> SynPat.Const (SynConst.Unit, range0) | UnitType -> SynPat.unit
| _ -> SynPat.CreateNamed (Ident.Create $"arg_%i{i}_%i{j}") | _ -> SynPat.named $"arg_%i{i}_%i{j}"
) )
match args with match args with
| [] -> failwith "somehow got no args at all" | [] -> failwith "somehow got no args at all"
| [ arg ] -> arg | [ arg ] -> arg
| args -> | args -> SynPat.tuple args
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0) |> fun i -> if tupledArgs.HasParen then SynPat.paren i else i
|> SynPat.CreateParen
|> fun i -> if tupledArgs.HasParen then SynPat.Paren (i, range0) else i
) )
let headPat = let headPat =
SynPat.LongIdent ( SynPat.LongIdent (
SynLongIdent.create [ Ident.Create "this" ; memberInfo.Identifier ], SynLongIdent.create [ Ident.create "this" ; memberInfo.Identifier ],
None, None,
None, None,
SynArgPats.Pats headArgs, SynArgPats.Pats headArgs,
@@ -192,7 +190,7 @@ module internal InterfaceMockGenerator =
| UnitType -> SynExpr.CreateConst () | UnitType -> SynExpr.CreateConst ()
| _ -> SynExpr.createIdent $"arg_%i{i}_%i{j}" | _ -> SynExpr.createIdent $"arg_%i{i}_%i{j}"
) )
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
) )
match tuples |> List.rev with match tuples |> List.rev with
@@ -200,9 +198,9 @@ module internal InterfaceMockGenerator =
| last :: rest -> | last :: rest ->
(last, rest) (last, rest)
||> List.fold (fun trail next -> SynExpr.CreateApp (next, trail)) ||> List.fold SynExpr.applyTo
|> SynExpr.applyFunction ( |> SynExpr.applyFunction (
SynExpr.createLongIdent' [ Ident.Create "this" ; memberInfo.Identifier ] SynExpr.createLongIdent' [ Ident.create "this" ; memberInfo.Identifier ]
) )
SynMemberDefn.Member ( SynMemberDefn.Member (
@@ -261,17 +259,16 @@ module internal InterfaceMockGenerator =
match inheritance with match inheritance with
| KnownInheritance.IDisposable -> | KnownInheritance.IDisposable ->
let binding = let binding =
SynBinding.basic SynExpr.createLongIdent [ "this" ; "Dispose" ]
(SynLongIdent.createS' [ "this" ; "Dispose" ]) |> SynExpr.applyTo (SynExpr.CreateConst ())
[ SynPat.CreateConst SynConst.Unit ] |> SynBinding.basic [ Ident.create "this" ; Ident.create "Dispose" ] [ SynPat.unit ]
(SynExpr.CreateApp (SynExpr.createLongIdent [ "this" ; "Dispose" ], SynExpr.CreateUnit)) |> SynBinding.withReturnAnnotation SynType.unit
|> SynBinding.withReturnAnnotation (SynType.Unit ())
|> SynBinding.makeInstanceMember |> SynBinding.makeInstanceMember
let mem = SynMemberDefn.Member (binding, range0) let mem = SynMemberDefn.Member (binding, range0)
SynMemberDefn.Interface ( SynMemberDefn.Interface (
SynType.CreateLongIdent (SynLongIdent.createS' [ "System" ; "IDisposable" ]), SynType.createLongIdent' [ "System" ; "IDisposable" ],
Some range0, Some range0,
Some [ mem ], Some [ mem ],
range0 range0
@@ -281,7 +278,7 @@ module internal InterfaceMockGenerator =
let record = let record =
{ {
Name = Ident.Create name Name = Ident.create name
Fields = fields Fields = fields
Members = Some ([ constructor ; interfaceMembers ] @ extraInterfaces) Members = Some ([ constructor ; interfaceMembers ] @ extraInterfaces)
XmlDoc = Some xmlDoc XmlDoc = Some xmlDoc
@@ -334,7 +331,7 @@ module internal InterfaceMockGenerator =
= =
let interfaceType = AstHelper.parseInterface interfaceType let interfaceType = AstHelper.parseInterface interfaceType
let fields = interfaceType.Members |> List.map constructMember let fields = interfaceType.Members |> List.map constructMember
let docString = PreXmlDoc.Create " Mock record type for an interface" let docString = PreXmlDoc.create "Mock record type for an interface"
let name = let name =
List.last interfaceType.Name List.last interfaceType.Name

View File

@@ -4,7 +4,6 @@ open System
open System.Text open System.Text
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Xml
open Myriad.Core open Myriad.Core
type internal JsonParseOutputSpec = type internal JsonParseOutputSpec =
@@ -42,7 +41,7 @@ module internal JsonParseGenerator =
|> SynExpr.applyFunction (SynExpr.createIdent "raise") |> SynExpr.applyFunction (SynExpr.createIdent "raise")
[ [
SynMatchClause.create SynPat.CreateNull raiseExpr SynMatchClause.create SynPat.createNull raiseExpr
SynMatchClause.create (SynPat.named "v") (SynExpr.createIdent "v") SynMatchClause.create (SynPat.named "v") (SynExpr.createIdent "v")
] ]
|> SynExpr.createMatch indexed |> SynExpr.createMatch indexed
@@ -104,7 +103,7 @@ module internal JsonParseGenerator =
let body = SynExpr.pipeThroughFunction (SynExpr.createIdent "Some") body let body = SynExpr.pipeThroughFunction (SynExpr.createIdent "Some") body
[ [
SynMatchClause.create SynPat.CreateNull (SynExpr.createIdent "None") SynMatchClause.create SynPat.createNull (SynExpr.createIdent "None")
SynMatchClause.create (SynPat.named "v") body SynMatchClause.create (SynPat.named "v") body
] ]
|> SynExpr.createMatch node |> SynExpr.createMatch node
@@ -308,14 +307,14 @@ module internal JsonParseGenerator =
if spec.ExtensionMethods then if spec.ExtensionMethods then
let binding = let binding =
SynBinding.basic (SynLongIdent.createI functionName) [ arg ] functionBody SynBinding.basic [ functionName ] [ arg ] functionBody
|> SynBinding.withXmlDoc xmlDoc |> SynBinding.withXmlDoc xmlDoc
|> SynBinding.withReturnAnnotation returnInfo |> SynBinding.withReturnAnnotation returnInfo
|> SynMemberDefn.staticMember |> SynMemberDefn.staticMember
let componentInfo = let componentInfo =
SynComponentInfo.createLong typeName SynComponentInfo.createLong typeName
|> SynComponentInfo.withDocString (PreXmlDoc.Create " Extension methods for JSON parsing") |> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for JSON parsing")
let containingType = let containingType =
SynTypeDefnRepr.augmentation () SynTypeDefnRepr.augmentation ()
@@ -324,7 +323,7 @@ module internal JsonParseGenerator =
SynModuleDecl.Types ([ containingType ], range0) SynModuleDecl.Types ([ containingType ], range0)
else else
SynBinding.basic (SynLongIdent.createI functionName) [ arg ] functionBody SynBinding.basic [ functionName ] [ arg ] functionBody
|> SynBinding.withXmlDoc xmlDoc |> SynBinding.withXmlDoc xmlDoc
|> SynBinding.withReturnAnnotation returnInfo |> SynBinding.withReturnAnnotation returnInfo
|> List.singleton |> List.singleton
@@ -333,7 +332,10 @@ module internal JsonParseGenerator =
let getParseOptions (fieldAttrs : SynAttribute list) = let getParseOptions (fieldAttrs : SynAttribute list) =
(JsonParseOption.None, fieldAttrs) (JsonParseOption.None, fieldAttrs)
||> List.fold (fun options attr -> ||> List.fold (fun options attr ->
if attr.TypeName.AsString.EndsWith ("JsonNumberHandling", StringComparison.Ordinal) then if
(SynLongIdent.toString attr.TypeName)
.EndsWith ("JsonNumberHandling", StringComparison.Ordinal)
then
let qualifiedEnumValue = let qualifiedEnumValue =
match SynExpr.stripOptionalParen attr.ArgExpr with match SynExpr.stripOptionalParen attr.ArgExpr with
| SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident -> | SynExpr.LongIdent (_, SynLongIdent (ident, _, _), _, _) when isJsonNumberHandling ident ->
@@ -356,15 +358,15 @@ module internal JsonParseGenerator =
options options
) )
let createRecordMaker (spec : JsonParseOutputSpec) (fields : SynFieldData<Ident> list) =
let createRecordMaker (spec : JsonParseOutputSpec) (typeName : LongIdent) (fields : SynFieldData<Ident> list) =
let assignments = let assignments =
fields fields
|> List.mapi (fun i fieldData -> |> List.mapi (fun i fieldData ->
let propertyNameAttr = let propertyNameAttr =
fieldData.Attrs fieldData.Attrs
|> List.tryFind (fun attr -> |> List.tryFind (fun attr ->
attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal) (SynLongIdent.toString attr.TypeName)
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
) )
let options = getParseOptions fieldData.Attrs let options = getParseOptions fieldData.Attrs
@@ -384,7 +386,7 @@ module internal JsonParseGenerator =
| Some name -> name.ArgExpr | Some name -> name.ArgExpr
createParseRhs options propertyName fieldData.Type createParseRhs options propertyName fieldData.Type
|> SynBinding.basic (SynLongIdent.createS $"arg_%i{i}") [] |> SynBinding.basic [ Ident.create $"arg_%i{i}" ] []
) )
let finalConstruction = let finalConstruction =
@@ -412,13 +414,13 @@ module internal JsonParseGenerator =
let options = getParseOptions field.Attrs let options = getParseOptions field.Attrs
createParseRhs options propertyName field.Type createParseRhs options propertyName field.Type
) )
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
|> SynExpr.applyFunction (SynExpr.createLongIdent' (typeName @ [ case.Ident ])) |> SynExpr.applyFunction (SynExpr.createLongIdent' (typeName @ [ case.Ident ]))
|> SynExpr.createLet |> SynExpr.createLet
[ [
SynExpr.index (SynExpr.CreateConst "data") (SynExpr.createIdent "node") SynExpr.index (SynExpr.CreateConst "data") (SynExpr.createIdent "node")
|> assertNotNull (SynExpr.CreateConst "data") |> assertNotNull (SynExpr.CreateConst "data")
|> SynBinding.basic (SynLongIdent.createS "node") [] |> SynBinding.basic [ Ident.create "node" ] []
] ]
match propertyName with match propertyName with
@@ -471,7 +473,7 @@ module internal JsonParseGenerator =
"v" "v"
(SynExpr.callGenericMethod "GetValue" [ Ident.create "string" ] (SynExpr.createIdent "v")) (SynExpr.callGenericMethod "GetValue" [ Ident.create "string" ] (SynExpr.createIdent "v"))
) )
|> SynBinding.basic (SynLongIdent.createS "ty") [] |> SynBinding.basic [ Ident.create "ty" ] []
] ]
let createModule (namespaceId : LongIdent) (spec : JsonParseOutputSpec) (typeDefn : SynTypeDefn) = let createModule (namespaceId : LongIdent) (spec : JsonParseOutputSpec) (typeDefn : SynTypeDefn) =
@@ -485,10 +487,7 @@ module internal JsonParseGenerator =
if spec.ExtensionMethods then if spec.ExtensionMethods then
[ SynAttribute.autoOpen ] [ SynAttribute.autoOpen ]
else else
[ [ SynAttribute.requireQualifiedAccess ; SynAttribute.compilationRepresentation ]
SynAttribute.RequireQualifiedAccess ()
SynAttribute.compilationRepresentation
]
let xmlDoc = let xmlDoc =
let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "." let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "."
@@ -499,8 +498,8 @@ module internal JsonParseGenerator =
else else
"methods" "methods"
$" Module containing JSON parsing %s{description} for the %s{fullyQualified} type" $"Module containing JSON parsing %s{description} for the %s{fullyQualified} type"
|> PreXmlDoc.Create |> PreXmlDoc.create
let moduleName = let moduleName =
if spec.ExtensionMethods then if spec.ExtensionMethods then
@@ -525,20 +524,17 @@ module internal JsonParseGenerator =
let decl = let decl =
match synTypeDefnRepr with match synTypeDefnRepr with
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, fields, _range), _) -> | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Record (_accessibility, fields, _range), _) ->
let fields = fields |> List.map SynField.extractWithIdent fields |> List.map SynField.extractWithIdent |> createRecordMaker spec
createRecordMaker spec ident fields
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_accessibility, cases, _range), _) -> | SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_accessibility, cases, _range), _) ->
let optionGet (i : Ident option) = let optionGet (i : Ident option) =
match i with match i with
| None -> failwith "WoofWare.Myriad requires union cases to have identifiers on each field." | None -> failwith "WoofWare.Myriad requires union cases to have identifiers on each field."
| Some i -> i | Some i -> i
let cases = cases
cases |> List.map SynUnionCase.extract
|> List.map SynUnionCase.extract |> List.map (UnionCase.mapIdentFields optionGet)
|> List.map (UnionCase.mapIdentFields optionGet) |> createUnionMaker spec ident
createUnionMaker spec ident cases
| _ -> failwithf "Not a record or union type" | _ -> failwithf "Not a record or union type"
let mdl = let mdl =

View File

@@ -3,8 +3,6 @@ namespace WoofWare.Myriad.Plugins
open System open System
open System.Text open System.Text
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Xml
open Myriad.Core open Myriad.Core
type internal JsonSerializeOutputSpec = type internal JsonSerializeOutputSpec =
@@ -40,28 +38,23 @@ module internal JsonSerializeGenerator =
) )
| OptionType ty -> | OptionType ty ->
// fun field -> match field with | None -> JsonValue.Create null | Some v -> {serializeNode ty} field // fun field -> match field with | None -> JsonValue.Create null | Some v -> {serializeNode ty} field
[ let noneClause =
SynMatchClause.Create ( // The absolutely galaxy-brained implementation of JsonValue has `JsonValue.Parse "null"`
SynPat.CreateLongIdent (SynLongIdent.createS "None", []), // identically equal to null. We have to work around this later, but we might as well just
None, // be efficient here and whip up the null directly.
// The absolutely galaxy-brained implementation of JsonValue has `JsonValue.Parse "null"` SynExpr.createNull ()
// identically equal to null. We have to work around this later, but we might as well just |> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
// be efficient here and whip up the null directly. |> SynMatchClause.create (SynPat.named "None")
SynExpr.CreateNull
|> SynExpr.upcast' (
SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ]
) let someClause =
SynExpr.applyFunction (serializeNode ty) (SynExpr.createIdent "field")
|> SynExpr.paren
|> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
|> SynMatchClause.create (
SynPat.CreateLongIdent (SynLongIdent.createS "Some", [ SynPat.named "field" ])
) )
SynMatchClause.Create ( [ noneClause ; someClause ]
SynPat.CreateLongIdent (SynLongIdent.createS "Some", [ SynPat.named "field" ]),
None,
SynExpr.applyFunction (serializeNode ty) (SynExpr.createIdent "field")
|> SynExpr.paren
|> SynExpr.upcast' (SynType.createLongIdent' [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonNode" ])
)
]
|> SynExpr.createMatch (SynExpr.createIdent "field") |> SynExpr.createMatch (SynExpr.createIdent "field")
|> SynExpr.createLambda "field" |> SynExpr.createLambda "field"
| ArrayType ty | ArrayType ty
@@ -79,18 +72,18 @@ module internal JsonSerializeGenerator =
SynPat.named "mem", SynPat.named "mem",
SynExpr.createIdent "field", SynExpr.createIdent "field",
SynExpr.applyFunction SynExpr.applyFunction
(SynExpr.CreateLongIdent (SynLongIdent.createS' [ "arr" ; "Add" ])) (SynExpr.createLongIdent [ "arr" ; "Add" ])
(SynExpr.CreateParen (SynExpr.CreateApp (serializeNode ty, SynExpr.createIdent "mem"))), (SynExpr.paren (SynExpr.applyFunction (serializeNode ty) (SynExpr.createIdent "mem"))),
range0 range0
) )
SynExpr.createIdent "arr" SynExpr.createIdent "arr"
] ]
|> SynExpr.CreateSequential |> SynExpr.sequential
|> SynExpr.createLet |> SynExpr.createLet
[ [
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonArray" ] SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonArray" ]
|> SynExpr.applyTo (SynExpr.CreateConst ()) |> SynExpr.applyTo (SynExpr.CreateConst ())
|> SynBinding.basic (SynLongIdent.createS "arr") [] |> SynBinding.basic [ Ident.create "arr" ] []
] ]
|> SynExpr.createLambda "field" |> SynExpr.createLambda "field"
| IDictionaryType (_keyType, valueType) | IDictionaryType (_keyType, valueType)
@@ -108,46 +101,31 @@ module internal JsonSerializeGenerator =
DebugPointAtInOrTo.Yes range0, DebugPointAtInOrTo.Yes range0,
SeqExprOnly.SeqExprOnly false, SeqExprOnly.SeqExprOnly false,
true, true,
SynPat.CreateParen ( SynPat.paren (
SynPat.CreateLongIdent ( SynPat.CreateLongIdent (
SynLongIdent.createS "KeyValue", SynLongIdent.createS "KeyValue",
[ [ SynPat.tuple [ SynPat.named "key" ; SynPat.named "value" ] ]
SynPat.CreateParen (
SynPat.Tuple (
false,
[
SynPat.CreateNamed (Ident.Create "key")
SynPat.CreateNamed (Ident.Create "value")
],
[ range0 ],
range0
)
)
]
) )
), ),
SynExpr.CreateIdent (Ident.Create "field"), SynExpr.createIdent "field",
SynExpr.CreateApp ( SynExpr.applyFunction
SynExpr.createLongIdent [ "ret" ; "Add" ], (SynExpr.createLongIdent [ "ret" ; "Add" ])
SynExpr.CreateParenedTuple (SynExpr.tuple
[ [
SynExpr.CreateApp ( SynExpr.createLongIdent [ "key" ; "ToString" ]
SynExpr.createLongIdent [ "key" ; "ToString" ], |> SynExpr.applyTo (SynExpr.CreateConst ())
SynExpr.CreateConst () SynExpr.applyFunction (serializeNode valueType) (SynExpr.createIdent "value")
) ]),
SynExpr.CreateApp (serializeNode valueType, SynExpr.createIdent "value")
]
),
range0 range0
) )
SynExpr.createIdent "ret" SynExpr.createIdent "ret"
] ]
|> SynExpr.CreateSequential |> SynExpr.sequential
|> SynExpr.createLet |> SynExpr.createLet
[ [
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ] SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|> SynExpr.applyTo (SynExpr.CreateConst ()) |> SynExpr.applyTo (SynExpr.CreateConst ())
|> SynBinding.basic (SynLongIdent.createS "ret") [] |> SynBinding.basic [ Ident.create "ret" ] []
] ]
|> SynExpr.createLambda "field" |> SynExpr.createLambda "field"
| _ -> | _ ->
@@ -157,7 +135,7 @@ module internal JsonSerializeGenerator =
| SynType.LongIdent ident -> ident.LongIdent | SynType.LongIdent ident -> ident.LongIdent
| _ -> failwith $"Unrecognised type: %+A{fieldType}" | _ -> failwith $"Unrecognised type: %+A{fieldType}"
SynExpr.createLongIdent' (typeName @ [ Ident.Create "toJsonNode" ]) SynExpr.createLongIdent' (typeName @ [ Ident.create "toJsonNode" ])
/// propertyName is probably a string literal, but it could be a [<Literal>] variable /// propertyName is probably a string literal, but it could be a [<Literal>] variable
/// `node.Add ({propertyName}, {toJsonNode})` /// `node.Add ({propertyName}, {toJsonNode})`
@@ -168,13 +146,16 @@ module internal JsonSerializeGenerator =
(serializeNode fieldType) (serializeNode fieldType)
(SynExpr.createLongIdent' [ Ident.create "input" ; fieldId ]) (SynExpr.createLongIdent' [ Ident.create "input" ; fieldId ])
] ]
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ]) |> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
let getPropertyName (fieldId : Ident) (attrs : SynAttribute list) : SynExpr = let getPropertyName (fieldId : Ident) (attrs : SynAttribute list) : SynExpr =
let propertyNameAttr = let propertyNameAttr =
attrs attrs
|> List.tryFind (fun attr -> attr.TypeName.AsString.EndsWith ("JsonPropertyName", StringComparison.Ordinal)) |> List.tryFind (fun attr ->
(SynLongIdent.toString attr.TypeName)
.EndsWith ("JsonPropertyName", StringComparison.Ordinal)
)
match propertyNameAttr with match propertyNameAttr with
| None -> | None ->
@@ -213,12 +194,12 @@ module internal JsonSerializeGenerator =
populateNode populateNode
SynExpr.Upcast (SynExpr.createIdent "node", SynType.Anon range0, range0) SynExpr.Upcast (SynExpr.createIdent "node", SynType.Anon range0, range0)
] ]
|> SynExpr.CreateSequential |> SynExpr.sequential
|> SynExpr.createLet |> SynExpr.createLet
[ [
SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ] SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonObject" ]
|> SynExpr.applyTo (SynExpr.CreateConst ()) |> SynExpr.applyTo (SynExpr.CreateConst ())
|> SynBinding.basic (SynLongIdent.createS "node") [] |> SynBinding.basic [ Ident.create "node" ] []
] ]
let pattern = let pattern =
@@ -228,11 +209,11 @@ module internal JsonSerializeGenerator =
if spec.ExtensionMethods then if spec.ExtensionMethods then
let componentInfo = let componentInfo =
SynComponentInfo.createLong typeName SynComponentInfo.createLong typeName
|> SynComponentInfo.withDocString (PreXmlDoc.Create " Extension methods for JSON parsing") |> SynComponentInfo.withDocString (PreXmlDoc.create "Extension methods for JSON parsing")
let memberDef = let memberDef =
assignments assignments
|> SynBinding.basic (SynLongIdent.createI functionName) [ pattern ] |> SynBinding.basic [ functionName ] [ pattern ]
|> SynBinding.withXmlDoc xmlDoc |> SynBinding.withXmlDoc xmlDoc
|> SynBinding.withReturnAnnotation returnInfo |> SynBinding.withReturnAnnotation returnInfo
|> SynMemberDefn.staticMember |> SynMemberDefn.staticMember
@@ -246,7 +227,7 @@ module internal JsonSerializeGenerator =
else else
let binding = let binding =
assignments assignments
|> SynBinding.basic (SynLongIdent.createI functionName) [ pattern ] |> SynBinding.basic [ functionName ] [ pattern ]
|> SynBinding.withReturnAnnotation returnInfo |> SynBinding.withReturnAnnotation returnInfo
|> SynBinding.withXmlDoc xmlDoc |> SynBinding.withXmlDoc xmlDoc
@@ -261,7 +242,7 @@ module internal JsonSerializeGenerator =
let propertyName = getPropertyName fieldData.Ident fieldData.Attrs let propertyName = getPropertyName fieldData.Ident fieldData.Attrs
createSerializeRhsRecord propertyName fieldData.Ident fieldData.Type createSerializeRhsRecord propertyName fieldData.Ident fieldData.Type
) )
|> SynExpr.CreateSequential |> SynExpr.sequential
|> fun expr -> SynExpr.Do (expr, range0) |> fun expr -> SynExpr.Do (expr, range0)
|> scaffolding spec typeName inputArg |> scaffolding spec typeName inputArg
@@ -294,7 +275,7 @@ module internal JsonSerializeGenerator =
(SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ]) (SynExpr.createLongIdent [ "System" ; "Text" ; "Json" ; "Nodes" ; "JsonValue" ; "Create" ])
propertyName propertyName
] ]
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ]) |> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
let dataNode = let dataNode =
@@ -316,17 +297,17 @@ module internal JsonSerializeGenerator =
SynExpr.applyFunction (serializeNode fieldData.Type) (SynExpr.createIdent' caseName) SynExpr.applyFunction (serializeNode fieldData.Type) (SynExpr.createIdent' caseName)
[ propertyName ; node ] [ propertyName ; node ]
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "dataNode" ; "Add" ]) |> SynExpr.applyFunction (SynExpr.createLongIdent [ "dataNode" ; "Add" ])
) )
let assignToNode = let assignToNode =
[ SynExpr.CreateConst "data" ; SynExpr.createIdent "dataNode" ] [ SynExpr.CreateConst "data" ; SynExpr.createIdent "dataNode" ]
|> SynExpr.CreateParenedTuple |> SynExpr.tuple
|> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ]) |> SynExpr.applyFunction (SynExpr.createLongIdent [ "node" ; "Add" ])
let dataNode = let dataNode =
SynExpr.CreateSequential (dataBindings @ [ assignToNode ]) SynExpr.sequential (dataBindings @ [ assignToNode ])
|> SynExpr.createLet [ dataNode ] |> SynExpr.createLet [ dataNode ]
let action = let action =
@@ -335,7 +316,7 @@ module internal JsonSerializeGenerator =
if not dataBindings.IsEmpty then if not dataBindings.IsEmpty then
yield dataNode yield dataNode
] ]
|> SynExpr.CreateSequential |> SynExpr.sequential
SynMatchClause.create pattern action SynMatchClause.create pattern action
) )
@@ -358,10 +339,7 @@ module internal JsonSerializeGenerator =
if spec.ExtensionMethods then if spec.ExtensionMethods then
[ SynAttribute.autoOpen ] [ SynAttribute.autoOpen ]
else else
[ [ SynAttribute.requireQualifiedAccess ; SynAttribute.compilationRepresentation ]
SynAttribute.RequireQualifiedAccess ()
SynAttribute.compilationRepresentation
]
let xmlDoc = let xmlDoc =
let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "." let fullyQualified = ident |> Seq.map (fun i -> i.idText) |> String.concat "."

View File

@@ -1,9 +1,7 @@
namespace WoofWare.Myriad.Plugins namespace WoofWare.Myriad.Plugins
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Xml open Fantomas.FCS.Xml
open Myriad.Core
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal RemoveOptionsGenerator = module internal RemoveOptionsGenerator =
@@ -83,26 +81,15 @@ module internal RemoveOptionsGenerator =
let body = let body =
match fieldData.Type with match fieldData.Type with
| OptionType _ -> | OptionType _ ->
SynExpr.applyFunction accessor
(SynExpr.CreateAppInfix ( |> SynExpr.pipeThroughFunction (
SynExpr.LongIdent ( SynExpr.applyFunction
false,
SynLongIdent.SynLongIdent (
[ Ident.Create "op_PipeRight" ],
[],
[ Some (IdentTrivia.OriginalNotation "|>") ]
),
None,
range0
),
accessor
))
(SynExpr.applyFunction
(SynExpr.createLongIdent [ "Option" ; "defaultWith" ]) (SynExpr.createLongIdent [ "Option" ; "defaultWith" ])
(SynExpr.createLongIdent' ( (SynExpr.createLongIdent' (
withoutOptionsType withoutOptionsType
@ [ Ident.create (sprintf "Default%s" fieldData.Ident.idText) ] @ [ Ident.create (sprintf "Default%s" fieldData.Ident.idText) ]
))) ))
)
| _ -> accessor | _ -> accessor
(SynLongIdent.createI fieldData.Ident, true), Some body (SynLongIdent.createI fieldData.Ident, true), Some body
@@ -111,7 +98,7 @@ module internal RemoveOptionsGenerator =
let binding = let binding =
SynBinding.basic SynBinding.basic
(SynLongIdent.createI functionName) [ functionName ]
[ [
SynPat.named inputArg.idText SynPat.named inputArg.idText
|> SynPat.annotateType (SynType.LongIdent (SynLongIdent.create withoutOptionsType)) |> SynPat.annotateType (SynType.LongIdent (SynLongIdent.create withoutOptionsType))
@@ -150,13 +137,15 @@ module internal RemoveOptionsGenerator =
SynComponentInfo.createLong recordId SynComponentInfo.createLong recordId
|> SynComponentInfo.withDocString xmlDoc |> SynComponentInfo.withDocString xmlDoc
|> SynComponentInfo.addAttributes [ SynAttribute.compilationRepresentation ] |> SynComponentInfo.addAttributes [ SynAttribute.compilationRepresentation ]
|> SynComponentInfo.addAttributes [ SynAttribute.RequireQualifiedAccess () ] |> SynComponentInfo.addAttributes [ SynAttribute.requireQualifiedAccess ]
let mdl = SynModuleDecl.CreateNestedModule (info, decls) let mdl = SynModuleDecl.CreateNestedModule (info, decls)
SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ]) SynModuleOrNamespace.CreateNamespace (namespaceId, decls = [ mdl ])
| _ -> failwithf "Not a record type" | _ -> failwithf "Not a record type"
open Myriad.Core
/// Myriad generator that stamps out a record with option types stripped /// Myriad generator that stamps out a record with option types stripped
/// from the fields at the top level. /// from the fields at the top level.
[<MyriadGenerator("remove-options")>] [<MyriadGenerator("remove-options")>]

View File

@@ -1,7 +1,6 @@
namespace WoofWare.Myriad.Plugins namespace WoofWare.Myriad.Plugins
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal SynArgPats = module internal SynArgPats =
@@ -11,8 +10,7 @@ module internal SynArgPats =
else else
caseNames caseNames
|> List.map (fun ident -> SynPat.Named (SynIdent.SynIdent (ident, None), false, None, range0)) |> List.map (fun i -> SynPat.named i.idText)
|> fun ps -> SynPat.Tuple (false, ps, List.replicate (ps.Length - 1) range0, range0) |> SynPat.tuple
|> fun p -> SynPat.Paren (p, range0)
|> List.singleton |> List.singleton
|> SynArgPats.Pats |> SynArgPats.Pats

View File

@@ -2,7 +2,6 @@ namespace WoofWare.Myriad.Plugins
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
open Fantomas.FCS.Text.Range open Fantomas.FCS.Text.Range
open Myriad.Core
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal SynAttribute = module internal SynAttribute =
@@ -10,12 +9,18 @@ module internal SynAttribute =
{ {
TypeName = SynLongIdent.createS "CompilationRepresentation" TypeName = SynLongIdent.createS "CompilationRepresentation"
ArgExpr = ArgExpr =
SynExpr.CreateLongIdent ( [ "CompilationRepresentationFlags" ; "ModuleSuffix" ]
false, |> SynExpr.createLongIdent
SynLongIdent.createS' [ "CompilationRepresentationFlags" ; "ModuleSuffix" ], |> SynExpr.paren
None Target = None
) AppliesToGetterAndSetter = false
|> SynExpr.CreateParen Range = range0
}
let internal requireQualifiedAccess : SynAttribute =
{
TypeName = SynLongIdent.createS "RequireQualifiedAccess"
ArgExpr = SynExpr.CreateConst ()
Target = None Target = None
AppliesToGetterAndSetter = false AppliesToGetterAndSetter = false
Range = range0 Range = range0
@@ -24,7 +29,7 @@ module internal SynAttribute =
let internal autoOpen : SynAttribute = let internal autoOpen : SynAttribute =
{ {
TypeName = SynLongIdent.createS "AutoOpen" TypeName = SynLongIdent.createS "AutoOpen"
ArgExpr = SynExpr.CreateConst SynConst.Unit ArgExpr = SynExpr.CreateConst ()
Target = None Target = None
AppliesToGetterAndSetter = false AppliesToGetterAndSetter = false
Range = range0 Range = range0

View File

@@ -36,7 +36,7 @@ module internal SynBinding =
SynLeadingKeyword.Let range0 SynLeadingKeyword.Let range0
} }
let basic (name : SynLongIdent) (args : SynPat list) (body : SynExpr) : SynBinding = let basic (name : LongIdent) (args : SynPat list) (body : SynExpr) : SynBinding =
let valInfo : SynValInfo = let valInfo : SynValInfo =
args args
|> List.map (fun pat -> [ SynArgInfo.SynArgInfo (SynAttributes.Empty, false, getName pat) ]) |> List.map (fun pat -> [ SynArgInfo.SynArgInfo (SynAttributes.Empty, false, getName pat) ])
@@ -50,7 +50,7 @@ module internal SynBinding =
[], [],
PreXmlDoc.Empty, PreXmlDoc.Empty,
SynValData.SynValData (None, valInfo, None), SynValData.SynValData (None, valInfo, None),
SynPat.LongIdent (name, None, None, SynArgPats.Pats args, None, range0), SynPat.identWithArgs name (SynArgPats.Pats args),
None, None,
body, body,
range0, range0,

View File

@@ -23,20 +23,11 @@ module internal SynExpr =
let applyFunction (f : SynExpr) (x : SynExpr) : SynExpr = SynExpr.CreateApp (f, x) let applyFunction (f : SynExpr) (x : SynExpr) : SynExpr = SynExpr.CreateApp (f, x)
/// {f} {x} /// {f} {x}
let applyTo (x : SynExpr) (f : SynExpr) : SynExpr = SynExpr.CreateApp (f, x) let inline applyTo (x : SynExpr) (f : SynExpr) : SynExpr = applyFunction f x
/// {expr} |> {func} /// {expr} |> {func}
let pipeThroughFunction (func : SynExpr) (expr : SynExpr) : SynExpr = let pipeThroughFunction (func : SynExpr) (expr : SynExpr) : SynExpr =
SynExpr.CreateAppInfix ( SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.pipe, expr)
SynExpr.CreateLongIdent (
SynLongIdent.SynLongIdent (
[ Ident.Create "op_PipeRight" ],
[],
[ Some (IdentTrivia.OriginalNotation "|>") ]
)
),
expr
)
|> applyTo func |> applyTo func
/// if {cond} then {trueBranch} else {falseBranch} /// if {cond} then {trueBranch} else {falseBranch}
@@ -80,17 +71,7 @@ module internal SynExpr =
/// {a} = {b} /// {a} = {b}
let equals (a : SynExpr) (b : SynExpr) = let equals (a : SynExpr) (b : SynExpr) =
SynExpr.CreateAppInfix ( SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.eq, a) |> applyTo b
SynExpr.CreateLongIdent (
SynLongIdent.SynLongIdent (
Ident.CreateLong "op_Equality",
[],
[ Some (IdentTrivia.OriginalNotation "=") ]
)
),
a
)
|> applyTo b
/// {a} + {b} /// {a} + {b}
let plus (a : SynExpr) (b : SynExpr) = let plus (a : SynExpr) (b : SynExpr) =
@@ -116,7 +97,7 @@ module internal SynExpr =
SynExpr.DotGet ( SynExpr.DotGet (
obj, obj,
range0, range0,
SynLongIdent.SynLongIdent (id = [ Ident.Create meth ], dotRanges = [], trivia = [ None ]), SynLongIdent.SynLongIdent (id = [ Ident.create meth ], dotRanges = [], trivia = [ None ]),
range0 range0
) )
|> applyTo arg |> applyTo arg
@@ -142,7 +123,7 @@ module internal SynExpr =
SynExpr.TypeApp ( SynExpr.TypeApp (
SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0), SynExpr.DotGet (obj, range0, SynLongIdent.createS meth, range0),
range0, range0,
[ SynType.CreateLongIdent ty ], [ SynType.createLongIdent' [ ty ] ],
[], [],
Some range0, Some range0,
range0, range0,
@@ -150,9 +131,12 @@ module internal SynExpr =
) )
|> applyTo (SynExpr.CreateConst ()) |> applyTo (SynExpr.CreateConst ())
let index (property : SynExpr) (obj : SynExpr) : SynExpr = let inline index (property : SynExpr) (obj : SynExpr) : SynExpr =
SynExpr.DotIndexedGet (obj, property, range0, range0) SynExpr.DotIndexedGet (obj, property, range0, range0)
let inline paren (e : SynExpr) : SynExpr =
SynExpr.Paren (e, range0, Some range0, range0)
/// (fun {varName} -> {body}) /// (fun {varName} -> {body})
let createLambda (varName : string) (body : SynExpr) : SynExpr = let createLambda (varName : string) (body : SynExpr) : SynExpr =
let parsedDataPat = [ SynPat.named varName ] let parsedDataPat = [ SynPat.named varName ]
@@ -168,59 +152,68 @@ module internal SynExpr =
ArrowRange = Some range0 ArrowRange = Some range0
} }
) )
|> SynExpr.CreateParen |> paren
let createThunk (body : SynExpr) : SynExpr = let createThunk (body : SynExpr) : SynExpr =
let parsedDataPat = [ SynPat.Const (SynConst.Unit, range0) ]
SynExpr.Lambda ( SynExpr.Lambda (
false, false,
false, false,
SynSimplePats.Create [], SynSimplePats.Create [],
body, body,
Some (parsedDataPat, body), Some ([ SynPat.unit ], body),
range0, range0,
{ {
ArrowRange = Some range0 ArrowRange = Some range0
} }
) )
|> SynExpr.CreateParen |> paren
/// {body} |> fun a -> Async.StartAsTask (a, ?cancellationToken=ct)
let startAsTask (ct : SynLongIdent) (body : SynExpr) =
let lambda =
[
SynExpr.CreateLongIdent (SynLongIdent.createS "a")
equals
(SynExpr.LongIdent (true, SynLongIdent.createS "cancellationToken", None, range0))
(SynExpr.CreateLongIdent ct)
]
|> SynExpr.CreateParenedTuple
|> applyFunction (SynExpr.CreateLongIdent (SynLongIdent.createS' [ "Async" ; "StartAsTask" ]))
|> createLambda "a"
pipeThroughFunction lambda body
let inline createIdent (s : string) : SynExpr = SynExpr.Ident (Ident (s, range0)) let inline createIdent (s : string) : SynExpr = SynExpr.Ident (Ident (s, range0))
let inline createIdent' (i : Ident) : SynExpr = SynExpr.Ident i let inline createIdent' (i : Ident) : SynExpr = SynExpr.Ident i
let inline createLongIdent (ident : string list) : SynExpr =
SynExpr.CreateLongIdent (SynLongIdent.createS' ident)
let inline createLongIdent' (ident : Ident list) : SynExpr = let inline createLongIdent' (ident : Ident list) : SynExpr =
SynExpr.CreateLongIdent (SynLongIdent.create ident) SynExpr.LongIdent (false, SynLongIdent.create ident, None, range0)
let inline createLongIdent (ident : string list) : SynExpr =
createLongIdent' (ident |> List.map Ident.create)
let tupleNoParen (args : SynExpr list) : SynExpr =
SynExpr.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
let inline tuple (args : SynExpr list) = args |> tupleNoParen |> paren
/// {body} |> fun a -> Async.StartAsTask (a, ?cancellationToken=ct)
let startAsTask (ct : Ident) (body : SynExpr) =
let lambda =
[
createIdent "a"
equals
(SynExpr.LongIdent (true, SynLongIdent.createS "cancellationToken", None, range0))
(createIdent' ct)
]
|> tuple
|> applyFunction (createLongIdent [ "Async" ; "StartAsTask" ])
|> createLambda "a"
pipeThroughFunction lambda body
let inline createLet (bindings : SynBinding list) (body : SynExpr) : SynExpr = let inline createLet (bindings : SynBinding list) (body : SynExpr) : SynExpr =
SynExpr.LetOrUse (false, false, bindings, body, range0, SynExprLetOrUseTrivia.empty) SynExpr.LetOrUse (false, false, bindings, body, range0, SynExprLetOrUseTrivia.empty)
let inline createMatch (matchOn : SynExpr) (cases : SynMatchClause list) : SynExpr = let inline createMatch (matchOn : SynExpr) (cases : SynMatchClause list) : SynExpr =
SynExpr.CreateMatch (matchOn, cases) SynExpr.Match (
DebugPointAtBinding.Yes range0,
matchOn,
cases,
range0,
{
MatchKeyword = range0
WithKeyword = range0
}
)
let typeAnnotate (ty : SynType) (expr : SynExpr) : SynExpr = SynExpr.CreateTyped (expr, ty) let typeAnnotate (ty : SynType) (expr : SynExpr) : SynExpr = SynExpr.Typed (expr, ty, range0)
let inline paren (e : SynExpr) : SynExpr =
SynExpr.Paren (e, range0, Some range0, range0)
let inline createNew (ty : SynType) (args : SynExpr) : SynExpr = let inline createNew (ty : SynType) (args : SynExpr) : SynExpr =
SynExpr.New (false, ty, paren args, range0) SynExpr.New (false, ty, paren args, range0)
@@ -228,8 +221,14 @@ module internal SynExpr =
let inline createWhile (cond : SynExpr) (body : SynExpr) : SynExpr = let inline createWhile (cond : SynExpr) (body : SynExpr) : SynExpr =
SynExpr.While (DebugPointAtWhile.Yes range0, cond, body, range0) SynExpr.While (DebugPointAtWhile.Yes range0, cond, body, range0)
let inline createNull () : SynExpr = SynExpr.Null range0
let reraise : SynExpr = createIdent "reraise" |> applyTo (SynExpr.CreateConst ()) let reraise : SynExpr = createIdent "reraise" |> applyTo (SynExpr.CreateConst ())
let sequential (exprs : SynExpr list) : SynExpr =
exprs
|> List.reduce (fun a b -> SynExpr.Sequential (DebugPointAtSequential.SuppressNeither, false, a, b, range0))
/// {compExpr} { {lets} ; return {ret} } /// {compExpr} { {lets} ; return {ret} }
let createCompExpr (compExpr : string) (retBody : SynExpr) (lets : CompExprBinding list) : SynExpr = let createCompExpr (compExpr : string) (retBody : SynExpr) (lets : CompExprBinding list) : SynExpr =
let retStatement = SynExpr.YieldOrReturn ((false, true), retBody, range0) let retStatement = SynExpr.YieldOrReturn ((false, true), retBody, range0)
@@ -252,25 +251,22 @@ module internal SynExpr =
EqualsRange = Some range0 EqualsRange = Some range0
} }
) )
| Let (lhs, rhs) -> createLet [ SynBinding.basic (SynLongIdent.createS lhs) [] rhs ] state | Let (lhs, rhs) -> createLet [ SynBinding.basic [ Ident.create lhs ] [] rhs ] state
| Use (lhs, rhs) -> | Use (lhs, rhs) ->
SynExpr.LetOrUse ( SynExpr.LetOrUse (
false, false,
true, true,
[ SynBinding.basic (SynLongIdent.createS lhs) [] rhs ], [ SynBinding.basic [ Ident.create lhs ] [] rhs ],
state, state,
range0, range0,
{ {
SynExprLetOrUseTrivia.InKeyword = None SynExprLetOrUseTrivia.InKeyword = None
} }
) )
| Do body -> SynExpr.CreateSequential [ SynExpr.Do (body, range0) ; state ] | Do body -> sequential [ SynExpr.Do (body, range0) ; state ]
) )
SynExpr.CreateApp ( applyFunction (createIdent compExpr) (SynExpr.ComputationExpr (false, contents, range0))
SynExpr.CreateIdent (Ident.Create compExpr),
SynExpr.ComputationExpr (false, contents, range0)
)
/// {expr} |> Async.AwaitTask /// {expr} |> Async.AwaitTask
let awaitTask (expr : SynExpr) : SynExpr = let awaitTask (expr : SynExpr) : SynExpr =
@@ -288,49 +284,17 @@ module internal SynExpr =
/// {ident} - {rhs} /// {ident} - {rhs}
let minus (ident : SynLongIdent) (rhs : SynExpr) : SynExpr = let minus (ident : SynLongIdent) (rhs : SynExpr) : SynExpr =
SynExpr.CreateApp ( SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.sub, SynExpr.CreateLongIdent ident)
SynExpr.CreateAppInfix ( |> applyTo rhs
SynExpr.CreateLongIdent (
SynLongIdent.SynLongIdent (
[ Ident.Create "op_Subtraction" ],
[],
[ Some (IdentTrivia.OriginalNotation "-") ]
)
),
SynExpr.CreateLongIdent ident
),
rhs
)
/// {ident} - {n} /// {ident} - {n}
let minusN (ident : SynLongIdent) (n : int) : SynExpr = minus ident (SynExpr.CreateConst n) let minusN (ident : SynLongIdent) (n : int) : SynExpr = minus ident (SynExpr.CreateConst n)
/// {y} > {x} /// {y} > {x}
let greaterThan (x : SynExpr) (y : SynExpr) : SynExpr = let greaterThan (x : SynExpr) (y : SynExpr) : SynExpr =
SynExpr.CreateApp ( SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.ge, y) |> applyTo x
SynExpr.CreateAppInfix (
SynExpr.CreateLongIdent (
SynLongIdent.SynLongIdent (
[ Ident.Create "op_GreaterThan" ],
[],
[ Some (IdentTrivia.OriginalNotation ">") ]
)
),
y
),
x
)
/// {y} >= {x} /// {y} >= {x}
let greaterThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr = let greaterThanOrEqual (x : SynExpr) (y : SynExpr) : SynExpr =
SynExpr.CreateAppInfix ( SynExpr.CreateAppInfix (SynExpr.CreateLongIdent SynLongIdent.geq, y)
SynExpr.CreateLongIdent (
SynLongIdent.SynLongIdent (
[ Ident.Create "op_GreaterThanOrEqual" ],
[],
[ Some (IdentTrivia.OriginalNotation ">=") ]
)
),
y
)
|> applyTo x |> applyTo x

View File

@@ -1,11 +1,34 @@
namespace WoofWare.Myriad.Plugins namespace WoofWare.Myriad.Plugins
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Text.Range open Fantomas.FCS.Text.Range
open Fantomas.FCS.Syntax open Fantomas.FCS.Syntax
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal SynLongIdent = module internal SynLongIdent =
let geq =
SynLongIdent.SynLongIdent (
[ Ident.create "op_GreaterThanOrEqual" ],
[],
[ Some (IdentTrivia.OriginalNotation ">=") ]
)
let ge =
SynLongIdent.SynLongIdent ([ Ident.create "op_GreaterThan" ], [], [ Some (IdentTrivia.OriginalNotation ">") ])
let sub =
SynLongIdent.SynLongIdent ([ Ident.create "op_Subtraction" ], [], [ Some (IdentTrivia.OriginalNotation "-") ])
let eq =
SynLongIdent.SynLongIdent ([ Ident.create "op_Equality" ], [], [ Some (IdentTrivia.OriginalNotation "=") ])
let pipe =
SynLongIdent.SynLongIdent ([ Ident.create "op_PipeRight" ], [], [ Some (IdentTrivia.OriginalNotation "|>") ])
let toString (sli : SynLongIdent) : string =
sli.LongIdent |> List.map _.idText |> String.concat "."
let create (ident : LongIdent) : SynLongIdent = let create (ident : LongIdent) : SynLongIdent =
let commas = let commas =
match ident with match ident with

View File

@@ -6,11 +6,28 @@ open Fantomas.FCS.Text.Range
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal SynPat = module internal SynPat =
let annotateType (ty : SynType) (pat : SynPat) = let inline annotateType (ty : SynType) (pat : SynPat) =
SynPat.Paren (SynPat.Typed (pat, ty, range0), range0) SynPat.Paren (SynPat.Typed (pat, ty, range0), range0)
let named (s : string) : SynPat = let inline named (s : string) : SynPat =
SynPat.Named (SynIdent.SynIdent (Ident (s, range0), None), false, None, range0) SynPat.Named (SynIdent.SynIdent (Ident (s, range0), None), false, None, range0)
let namedI (i : Ident) : SynPat = let inline namedI (i : Ident) : SynPat =
SynPat.Named (SynIdent.SynIdent (i, None), false, None, range0) SynPat.Named (SynIdent.SynIdent (i, None), false, None, range0)
let inline identWithArgs (i : LongIdent) (args : SynArgPats) : SynPat =
SynPat.LongIdent (SynLongIdent.create i, None, None, args, None, range0)
let inline tupleNoParen (elements : SynPat list) : SynPat =
match elements with
| [] -> failwith "Can't tuple no elements in a pattern"
| [ p ] -> p
| elements -> SynPat.Tuple (false, elements, List.replicate (elements.Length - 1) range0, range0)
let inline paren (pat : SynPat) : SynPat = SynPat.Paren (pat, range0)
let inline tuple (elements : SynPat list) : SynPat = tupleNoParen elements |> paren
let unit = SynPat.Const (SynConst.Unit, range0)
let createNull = SynPat.Null range0

View File

@@ -44,6 +44,9 @@ module internal SynType =
let inline var (ty : SynTypar) : SynType = SynType.Var (ty, range0) let inline var (ty : SynTypar) : SynType = SynType.Var (ty, range0)
let unit : SynType = named "unit"
let int : SynType = named "int"
[<AutoOpen>] [<AutoOpen>]
module internal SynTypePatterns = module internal SynTypePatterns =
let (|OptionType|_|) (fieldType : SynType) = let (|OptionType|_|) (fieldType : SynType) =

View File

@@ -30,13 +30,12 @@
<Compile Include="SynExpr\Ident.fs" /> <Compile Include="SynExpr\Ident.fs" />
<Compile Include="SynExpr\SynLongIdent.fs" /> <Compile Include="SynExpr\SynLongIdent.fs" />
<Compile Include="SynExpr\SynExprLetOrUseTrivia.fs" /> <Compile Include="SynExpr\SynExprLetOrUseTrivia.fs" />
<Compile Include="SynExpr\SynPat.fs" />
<Compile Include="SynExpr\SynBinding.fs" /> <Compile Include="SynExpr\SynBinding.fs" />
<Compile Include="SynExpr\SynType.fs" /> <Compile Include="SynExpr\SynType.fs" />
<Compile Include="SynExpr\SynMatchClause.fs" /> <Compile Include="SynExpr\SynMatchClause.fs" />
<Compile Include="SynExpr\SynPat.fs" />
<Compile Include="SynExpr\CompExpr.fs" /> <Compile Include="SynExpr\CompExpr.fs" />
<Compile Include="SynExpr\SynExpr.fs" /> <Compile Include="SynExpr\SynExpr.fs" />
<Compile Include="SynExpr\SynAttribute.fs" />
<Compile Include="SynExpr\SynArgPats.fs" /> <Compile Include="SynExpr\SynArgPats.fs" />
<Compile Include="SynExpr\SynField.fs" /> <Compile Include="SynExpr\SynField.fs" />
<Compile Include="SynExpr\SynUnionCase.fs" /> <Compile Include="SynExpr\SynUnionCase.fs" />
@@ -44,6 +43,7 @@
<Compile Include="SynExpr\SynTypeDefn.fs" /> <Compile Include="SynExpr\SynTypeDefn.fs" />
<Compile Include="SynExpr\SynComponentInfo.fs" /> <Compile Include="SynExpr\SynComponentInfo.fs" />
<Compile Include="SynExpr\SynMemberDefn.fs" /> <Compile Include="SynExpr\SynMemberDefn.fs" />
<Compile Include="SynExpr\SynAttribute.fs" />
<Compile Include="AstHelper.fs" /> <Compile Include="AstHelper.fs" />
<Compile Include="RemoveOptionsGenerator.fs"/> <Compile Include="RemoveOptionsGenerator.fs"/>
<Compile Include="InterfaceMockGenerator.fs"/> <Compile Include="InterfaceMockGenerator.fs"/>