Add ability to mock out curried functions (#58)

This commit is contained in:
Patrick Stevens
2023-12-31 12:28:51 +00:00
committed by GitHub
parent ff2c08d54f
commit 7b3bd32323
8 changed files with 298 additions and 126 deletions

View File

@@ -62,7 +62,7 @@ module internal InterfaceMockGenerator =
SynPat.LongIdent (
SynLongIdent.CreateString "Empty",
None,
generics,
None, // no generics on the "Empty", only on the return type
SynArgPats.Pats (
if generics.IsNone then
[]
@@ -126,7 +126,7 @@ module internal InterfaceMockGenerator =
let synValData =
SynValData.SynValData (
Some (
Some
{
IsInstance = true
IsDispatchSlot = false
@@ -134,14 +134,27 @@ module internal InterfaceMockGenerator =
IsFinal = false
GetterOrSetterIsCompilerGenerated = false
MemberKind = SynMemberKind.Member
}
),
},
valInfo =
SynValInfo.SynValInfo (
curriedArgInfos =
[
[ SynArgInfo.SynArgInfo (attributes = [], optional = false, ident = None) ]
[]
yield
[
SynArgInfo.SynArgInfo (
attributes = [],
optional = false,
ident = None
)
]
yield!
memberInfo.Args
|> List.mapi (fun i arg ->
arg.Args
|> List.mapi (fun j arg ->
SynArgInfo.CreateIdString $"arg_%i{i}_%i{j}"
)
)
],
returnInfo =
SynArgInfo.SynArgInfo (attributes = [], optional = false, ident = None)
@@ -150,25 +163,50 @@ module internal InterfaceMockGenerator =
)
let headArgs =
SynPat.Tuple (
false,
memberInfo.Args
|> List.mapi (fun i _arg -> SynPat.CreateNamed (Ident.Create $"arg%i{i}")),
List.replicate (memberInfo.Args.Length - 1) range0,
range0
memberInfo.Args
|> List.mapi (fun i tupledArgs ->
let args =
tupledArgs.Args
|> List.mapi (fun j _ -> SynPat.CreateNamed (Ident.Create $"arg_%i{i}_%i{j}"))
SynPat.Tuple (false, args, List.replicate (args.Length - 1) range0, range0)
|> SynPat.CreateParen
|> fun i -> if tupledArgs.HasParen then SynPat.Paren (i, range0) else i
)
|> SynPat.CreateParen
let headPat =
SynPat.LongIdent (
SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; memberInfo.Identifier ],
None,
None,
SynArgPats.Pats [ headArgs ],
SynArgPats.Pats headArgs,
None,
range0
)
let body =
let tuples =
memberInfo.Args
|> List.mapi (fun i args ->
args.Args
|> List.mapi (fun j args -> SynExpr.CreateIdentString $"arg_%i{i}_%i{j}")
|> SynExpr.CreateParenedTuple
)
match tuples |> List.rev with
| [] -> failwith "expected args but got none"
| last :: rest ->
(last, rest)
||> List.fold (fun trail next -> SynExpr.CreateApp (next, trail))
|> fun args ->
SynExpr.CreateApp (
SynExpr.CreateLongIdent (
SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; memberInfo.Identifier ]
),
args
)
SynMemberDefn.Member (
SynBinding.SynBinding (
None,
@@ -180,16 +218,7 @@ module internal InterfaceMockGenerator =
synValData,
headPat,
None,
SynExpr.CreateApp (
SynExpr.CreateLongIdent (
SynLongIdent.CreateFromLongIdent [ Ident.Create "this" ; memberInfo.Identifier ]
),
SynExpr.CreateParen (
memberInfo.Args
|> List.mapi (fun i _arg -> SynExpr.CreateIdentString $"arg%i{i}")
|> SynExpr.CreateTuple
)
),
body,
range0,
DebugPointAtBinding.Yes range0,
{
@@ -250,23 +279,30 @@ module internal InterfaceMockGenerator =
SynModuleDecl.Types ([ typeDecl ], range0)
let constructMember (mem : MemberInfo) : SynField =
let inputType =
match mem.Args |> List.map (fun pi -> pi.Type) |> List.rev with
| [] -> failwith "no-arg functions not supported yet"
| [ x ] -> x
| last :: rest ->
([ SynTupleTypeSegment.Type last ], rest)
||> List.fold (fun ty nextArg ->
SynTupleTypeSegment.Type nextArg :: SynTupleTypeSegment.Star range0 :: ty
)
|> fun segs -> SynType.Tuple (false, segs, range0)
let private buildType (x : ParameterInfo) : SynType =
if x.IsOptional then
SynType.App (SynType.CreateLongIdent "option", Some range0, [ x.Type ], [], Some range0, false, range0)
else
x.Type
let funcType = SynType.CreateFun (inputType, mem.ReturnType)
let private constructMemberSinglePlace (tuple : TupledArg) : SynType =
match tuple.Args |> List.rev |> List.map buildType with
| [] -> failwith "no-arg functions not supported yet"
| [ x ] -> x
| last :: rest ->
([ SynTupleTypeSegment.Type last ], rest)
||> List.fold (fun ty nextArg -> SynTupleTypeSegment.Type nextArg :: SynTupleTypeSegment.Star range0 :: ty)
|> fun segs -> SynType.Tuple (false, segs, range0)
|> fun ty -> if tuple.HasParen then SynType.Paren (ty, range0) else ty
let constructMember (mem : MemberInfo) : SynField =
let inputType = mem.Args |> List.map constructMemberSinglePlace
let funcType = AstHelper.toFun inputType mem.ReturnType
SynField.SynField (
[],
true,
false,
Some mem.Identifier,
funcType,
false,