This commit is contained in:
Smaug123
2024-02-16 19:23:15 +00:00
parent a524c1104d
commit 1793e9490f
7 changed files with 256 additions and 151 deletions

View File

@@ -43,46 +43,51 @@ type Cata<'Expr, 'ExprBuilder> =
module ExprCata = module ExprCata =
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
type private Instruction = type private Instruction =
| ProcessExpr of Expr | Process__Expr of Expr
| ProcessExprBuilder of ExprBuilder | Process__ExprBuilder of ExprBuilder
| ExprPair of PairOpKind | Expr_Pair of PairOpKind
| ExprSequential of int | Expr_Sequential of int
| ExprBuilder | Expr_Builder
| ExprBuilderChild | ExprBuilder_Child
| ExprBuilderParent | ExprBuilder_Parent
let private loop (cata : Cata<_, _>) (instructions : ResizeArray<Instruction>) = let private loop (cata : Cata<_, _>) (instructions : ResizeArray<Instruction>) =
let ExprBuilderStack = ResizeArray () let exprBuilderStack = ResizeArray ()
let ExprStack = ResizeArray () let exprStack = ResizeArray ()
while instructions.Count > 0 do while instructions.Count > 0 do
let currentInstruction = instructions.[instructions.Count - 1] let currentInstruction = instructions.[instructions.Count - 1]
instructions.RemoveAt (instructions.Count - 1) instructions.RemoveAt (instructions.Count - 1)
match currentInstruction with match currentInstruction with
| Instruction.ProcessExpr x -> | Instruction.Process__Expr x ->
match x with match x with
| Expr.Const (arg0) -> () | Expr.Const (arg0) -> cata.Expr.Const arg0 |> exprStack.Add
| Expr.Pair (arg0, arg1, arg2) -> () | Expr.Pair (arg0, arg1, arg2) -> ()
| Expr.Sequential (arg0) -> () | Expr.Sequential (arg0) -> ()
| Expr.Builder (arg0, arg1) -> () | Expr.Builder (arg0, arg1) -> ()
| Instruction.ProcessExprBuilder x -> | Instruction.Process__ExprBuilder x ->
match x with match x with
| ExprBuilder.Child (arg0) -> () | ExprBuilder.Child (arg0) -> ()
| ExprBuilder.Parent (arg0) -> () | ExprBuilder.Parent (arg0) -> ()
| Instruction.Expr_Pair (arg2) -> ()
| Instruction.Expr_Sequential (n) -> ()
| Instruction.Expr_Builder -> ()
| Instruction.ExprBuilder_Child -> ()
| Instruction.ExprBuilder_Parent -> ()
ExprStack, ExprBuilderStack exprStack, exprBuilderStack
/// Execute the catamorphism. /// Execute the catamorphism.
let runExpr (cata : Cata<'ExprRet, 'ExprBuilderRet>) (x : Expr) : 'ExprRet = let runExpr (cata : Cata<'ExprRet, 'ExprBuilderRet>) (x : Expr) : 'ExprRet =
let instructions = ResizeArray () let instructions = ResizeArray ()
instructions.Add (Instruction.ProcessExpr x) instructions.Add (Instruction.Process__Expr x)
let ExprRetStack, ExprBuilderRetStack = loop cata instructions let exprRetStack, exprBuilderRetStack = loop cata instructions
Seq.exactlyOne ExprRetStack Seq.exactlyOne exprRetStack
/// Execute the catamorphism. /// Execute the catamorphism.
let runExprBuilder (cata : Cata<'ExprRet, 'ExprBuilderRet>) (x : ExprBuilder) : 'ExprBuilderRet = let runExprBuilder (cata : Cata<'ExprRet, 'ExprBuilderRet>) (x : ExprBuilder) : 'ExprBuilderRet =
let instructions = ResizeArray () let instructions = ResizeArray ()
instructions.Add (Instruction.ProcessExprBuilder x) instructions.Add (Instruction.Process__ExprBuilder x)
let ExprRetStack, ExprBuilderRetStack = loop cata instructions let exprRetStack, exprBuilderRetStack = loop cata instructions
Seq.exactlyOne ExprBuilderRetStack Seq.exactlyOne exprBuilderRetStack

View File

@@ -70,6 +70,18 @@ type internal RecordType =
Accessibility : SynAccess option Accessibility : SynAccess option
} }
type UnionField =
{
Type : SynType
Name : Ident option
}
type UnionCase =
{
Name : SynIdent
Fields : UnionField list
}
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module internal AstHelper = module internal AstHelper =
@@ -383,6 +395,27 @@ module internal AstHelper =
Accessibility = accessibility Accessibility = accessibility
} }
let getUnionCases (SynTypeDefn.SynTypeDefn (_, repr, _, _, _, _)) : UnionCase list =
match repr with
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_, cases, _), _) ->
cases
|> List.map (fun (SynUnionCase.SynUnionCase (_, ident, kind, _, _, _, _)) ->
match kind with
| SynUnionCaseKind.FullType _ -> failwith "FullType union cases not supported"
| SynUnionCaseKind.Fields fields ->
{
Name = ident
Fields =
fields
|> List.map (fun (SynField.SynField (_, _, id, ty, _, _, _, _, _)) ->
{
Type = ty
Name = id
}
)
}
)
| _ -> failwithf "Failed to get union cases for type that was: %+A" repr
[<AutoOpen>] [<AutoOpen>]
module internal SynTypePatterns = module internal SynTypePatterns =

View File

@@ -100,7 +100,8 @@ module internal CataGenerator =
SynExpr.CreateParen ( SynExpr.CreateParen (
SynExpr.CreateApp ( SynExpr.CreateApp (
SynExpr.CreateLongIdent ( SynExpr.CreateLongIdent (
SynLongIdent.Create [ "Instruction" ; "Process" + relevantTypeName.idText ] SynLongIdent.Create
[ "Instruction" ; "Process__" + relevantTypeName.idText ]
), ),
SynExpr.CreateLongIdent (SynLongIdent.CreateString "x") SynExpr.CreateLongIdent (SynLongIdent.CreateString "x")
) )
@@ -117,7 +118,9 @@ module internal CataGenerator =
false, false,
List.map List.map
(fun (t : Ident) -> (fun (t : Ident) ->
SynPat.CreateNamed (Ident.Create (t.idText + "Stack")) SynPat.CreateNamed (
Ident.Create (t.idText + "Stack") |> Ident.lowerFirstLetter
)
) )
allTyparNames, allTyparNames,
List.replicate (allTypars.Length - 1) range0, List.replicate (allTypars.Length - 1) range0,
@@ -136,7 +139,9 @@ module internal CataGenerator =
// TODO: add the "all other stacks are empty" sanity checks // TODO: add the "all other stacks are empty" sanity checks
SynExpr.CreateApp ( SynExpr.CreateApp (
SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "exactlyOne" ]), SynExpr.CreateLongIdent (SynLongIdent.Create [ "Seq" ; "exactlyOne" ]),
SynExpr.CreateIdent (Ident.Create (relevantTyparName.idText + "Stack")) SynExpr.CreateIdent (
Ident.Create (relevantTyparName.idText + "Stack") |> Ident.lowerFirstLetter
)
), ),
range0, range0,
{ {
@@ -153,11 +158,7 @@ module internal CataGenerator =
), ),
range0, range0,
DebugPointAtBinding.NoneAtLet, DebugPointAtBinding.NoneAtLet,
{ SynExpr.synBindingTriviaZero false
LeadingKeyword = SynLeadingKeyword.Let range0
InlineKeyword = None
EqualsRange = Some range0
}
) )
let getName (ty : SynTypeDefn) : LongIdent = let getName (ty : SynTypeDefn) : LongIdent =
@@ -172,47 +173,13 @@ module internal CataGenerator =
| SynType.LongIdent (SynLongIdent.SynLongIdent (name, _, _)) -> name |> List.map _.idText |> String.concat "/" | SynType.LongIdent (SynLongIdent.SynLongIdent (name, _, _)) -> name |> List.map _.idText |> String.concat "/"
| _ -> failwithf "unrecognised type: %+A" unionType | _ -> failwithf "unrecognised type: %+A" unionType
type UnionField =
{
Type : SynType
Name : Ident option
}
type UnionCase =
{
Name : SynIdent
Fields : UnionField list
}
let getCases (SynTypeDefn.SynTypeDefn (_, repr, _, _, _, _)) : UnionCase list =
match repr with
| SynTypeDefnRepr.Simple (SynTypeDefnSimpleRepr.Union (_, cases, _), range0) ->
cases
|> List.map (fun (SynUnionCase.SynUnionCase (_, ident, kind, _, _, _, _)) ->
match kind with
| SynUnionCaseKind.FullType _ -> failwith "FullType union cases not supported"
| SynUnionCaseKind.Fields fields ->
{
Name = ident
Fields =
fields
|> List.map (fun (SynField.SynField (_, _, id, ty, _, _, _, _, _)) ->
{
Type = ty
Name = id
}
)
}
)
| _ -> failwithf "Failed to get union cases for type that was: %+A" repr
type FieldDescription = type FieldDescription =
| ListSelf of SynType | ListSelf of SynType
/// One of the union types itself /// One of the union types itself
| Self of SynType | Self of SynType
| NonRecursive of SynType | NonRecursive of SynType
let analyse (allUnionTypes : SynTypeDefn list) (case : UnionCase) : FieldDescription list = let analyse (allUnionTypes : SynTypeDefn list) (case : UnionCase) : (Ident option * FieldDescription) list =
let rec go (ty : SynType) : FieldDescription = let rec go (ty : SynType) : FieldDescription =
let stripped = SynType.stripOptionalParen ty let stripped = SynType.stripOptionalParen ty
@@ -236,7 +203,7 @@ module internal CataGenerator =
| _ -> failwithf "Unrecognised type: %+A" stripped | _ -> failwithf "Unrecognised type: %+A" stripped
case.Fields |> List.map _.Type |> List.map go case.Fields |> List.map (fun x -> x.Name, go x.Type)
/// Returns whether this type recursively contains a Self, and the emitted TODO /// Returns whether this type recursively contains a Self, and the emitted TODO
let rec toInstructionCase (field : FieldDescription) : bool * SynType option = let rec toInstructionCase (field : FieldDescription) : bool * SynType option =
@@ -247,73 +214,102 @@ module internal CataGenerator =
// store the length of the list // store the length of the list
true, Some (SynType.Int ()) true, Some (SynType.Int ())
type InstructionCase =
{
Name : Ident
Fields : UnionField list
}
let getInstructionCaseName (thisUnionType : SynTypeDefn) (case : UnionCase) =
match case.Name with
| SynIdent.SynIdent (ident, _) ->
(List.last (getName thisUnionType)).idText + "_" + ident.idText |> Ident.Create
/// Given the input `| Pair of Expr * Expr * PairOpKind`, /// Given the input `| Pair of Expr * Expr * PairOpKind`,
/// strips out any members which contain recursive calls. /// strips out any members which contain recursive calls.
/// Stores a list as an int which is "the length of the list". /// Stores a list as an int which is "the length of the list".
/// TODO: support other compound types. /// TODO: support other compound types.
let createInstructionCases (allUnionTypes : SynTypeDefn list) (case : UnionCase) : UnionField list option = let getRecursiveInstruction
(allUnionTypes : SynTypeDefn list)
(thisUnionType : SynTypeDefn)
(case : UnionCase)
: InstructionCase option
=
let analysed = analyse allUnionTypes case let analysed = analyse allUnionTypes case
let hasRecursion, cases = let hasRecursion, cases =
((false, []), analysed) ((false, []), analysed)
||> List.fold (fun (hasRecursion, cases) field -> ||> List.fold (fun (hasRecursion, cases) (fieldName, field) ->
let newHasRecursion, case = toInstructionCase field let newHasRecursion, case = toInstructionCase field
let cases = let cases =
match case with match case with
| None -> cases | None -> cases
| Some case -> case :: cases | Some case -> (fieldName, case) :: cases
hasRecursion || newHasRecursion, cases hasRecursion || newHasRecursion, cases
) )
let name = getInstructionCaseName thisUnionType case
if hasRecursion then if hasRecursion then
cases let fields =
|> List.rev cases
|> List.map (fun ty -> |> List.rev
{ |> List.map (fun (name, ty) ->
Name = None {
Type = ty Name = name
} Type = ty
) }
)
{
Name = name
Fields = fields
}
|> Some |> Some
else else
None None
/// The instruction to "process an Expr"; the loop will have to descend
/// into this Expr and break it down to discover what recursive calls
/// and calls to the cata this will imply making.
let baseCases (allUnionTypes : SynTypeDefn list) : InstructionCase list =
allUnionTypes
|> List.map (fun unionType ->
let name = getName unionType
{
Name = Ident.Create ("Process__" + (List.last name).idText)
Fields =
{
Name = None
Type = SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent (getName unionType))
}
|> List.singleton
}
)
let recursiveCases (allUnionTypes : SynTypeDefn list) : InstructionCase list =
allUnionTypes
|> List.collect (fun unionType ->
AstHelper.getUnionCases unionType
|> List.choose (fun case -> getRecursiveInstruction allUnionTypes unionType case)
)
let createInstructionType (allUnionTypes : SynTypeDefn list) : SynTypeDefn = let createInstructionType (allUnionTypes : SynTypeDefn list) : SynTypeDefn =
// 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 =
allUnionTypes baseCases allUnionTypes
|> List.map (fun unionType -> |> List.map (fun unionCase ->
let name = getName unionType SynUnionCase.Create (unionCase.Name, unionCase.Fields |> List.map (fun f -> SynField.Create f.Type))
SynUnionCase.Create (
Ident.Create ("Process" + (List.last name).idText),
[
SynField.Create (SynType.CreateLongIdent (SynLongIdent.CreateFromLongIdent name))
]
)
) )
let casesFromCases = let casesFromCases =
allUnionTypes recursiveCases allUnionTypes
|> List.collect (fun unionType -> |> List.map (fun case ->
getCases unionType SynUnionCase.Create (case.Name, case.Fields |> List.map (fun field -> SynField.Create field.Type))
|> List.choose (fun case ->
let fields = createInstructionCases allUnionTypes case
match fields with
| None -> None
| Some fields ->
let name =
match case.Name with
| SynIdent.SynIdent (ident, _) ->
(List.last (getName unionType)).idText + ident.idText |> Ident.Create
SynUnionCase.Create (name, fields |> List.map (fun field -> SynField.Create field.Type))
|> Some
)
) )
let cases = casesFromProcess @ casesFromCases let cases = casesFromProcess @ casesFromCases
@@ -387,7 +383,7 @@ module internal CataGenerator =
SynMemberFlags.MemberKind = SynMemberKind.Member SynMemberFlags.MemberKind = SynMemberKind.Member
} }
getCases unionType AstHelper.getUnionCases unionType
|> List.map (fun case -> |> List.map (fun case ->
let caseName = let caseName =
match case.Name with match case.Name with
@@ -400,10 +396,12 @@ module internal CataGenerator =
) )
let ty = let ty =
// TODO: we should only have called this once; pass the resulting
// data structure in, rather than rederiving it
let analysed = analyse allUnionTypes case let analysed = analyse allUnionTypes case
(SynType.Var (ourGenericName, range0), List.rev analysed) (SynType.Var (ourGenericName, range0), List.rev analysed)
||> List.fold (fun acc field -> ||> List.fold (fun acc (_name, field) ->
let place : SynType = let place : SynType =
match field with match field with
| FieldDescription.Self ty -> | FieldDescription.Self ty ->
@@ -546,21 +544,6 @@ module internal CataGenerator =
} }
) )
let minusN (ident : SynLongIdent) (n : int) : SynExpr =
SynExpr.CreateApp (
SynExpr.CreateAppInfix (
SynExpr.CreateLongIdent (
SynLongIdent.SynLongIdent (
[ Ident.Create "op_Subtraction" ],
[],
[ Some (IdentTrivia.OriginalNotation "-") ]
)
),
SynExpr.CreateLongIdent ident
),
SynExpr.CreateConst (SynConst.Int32 n)
)
let createLoopFunction (allUnionTypes : SynTypeDefn list) : SynBinding = let createLoopFunction (allUnionTypes : SynTypeDefn list) : SynBinding =
let valData = let valData =
SynValData.SynValData ( SynValData.SynValData (
@@ -620,14 +603,14 @@ module internal CataGenerator =
allUnionTypes allUnionTypes
|> List.map (fun ty -> |> List.map (fun ty ->
// TODO this is jank // TODO this is jank
List.last(getName ty).idText + "Stack" |> Ident.Create List.last(getName ty).idText + "Stack" |> Ident.Create |> Ident.lowerFirstLetter
) )
// A clause for each type, splitting it into its cases: // A clause for each type, splitting it into its cases:
let baseMatchClauses = let baseMatchClauses =
List.zip stackNames allUnionTypes List.zip stackNames allUnionTypes
|> List.map (fun (stackName, unionType) -> |> List.map (fun (stackName, unionType) ->
let cases = getCases unionType let cases = AstHelper.getUnionCases unionType
let bodyMatch = let bodyMatch =
SynExpr.CreateMatch ( SynExpr.CreateMatch (
@@ -645,7 +628,7 @@ module internal CataGenerator =
analysis analysis
|> List.forall ( |> List.forall (
function function
| FieldDescription.NonRecursive ty -> true | _, FieldDescription.NonRecursive ty -> true
| _ -> false | _ -> false
) )
then then
@@ -675,7 +658,8 @@ module internal CataGenerator =
else else
// there's a recursive type in here, so we'll have to make some calls // there's a recursive type in here, so we'll have to make some calls
// and then come back. // and then come back.
failwith "TODO" // TODO
SynExpr.CreateConst SynConst.Unit
SynMatchClause.SynMatchClause ( SynMatchClause.SynMatchClause (
SynPat.CreateLongIdent ( SynPat.CreateLongIdent (
@@ -714,7 +698,7 @@ module internal CataGenerator =
SynMatchClause.SynMatchClause ( SynMatchClause.SynMatchClause (
SynPat.LongIdent ( SynPat.LongIdent (
// TODO this is also jank; should unify with DU generator // TODO this is also jank; should unify with DU generator
SynLongIdent.Create [ "Instruction" ; "Process" + (List.last (getName unionType)).idText ], SynLongIdent.Create [ "Instruction" ; "Process__" + (List.last (getName unionType)).idText ],
None, None,
None, None,
SynArgPats.Pats [ SynPat.CreateNamed (Ident.Create "x") ], SynArgPats.Pats [ SynPat.CreateNamed (Ident.Create "x") ],
@@ -733,7 +717,79 @@ module internal CataGenerator =
) )
// And a clause for each case with a recursive reference. // And a clause for each case with a recursive reference.
let recMatchClauses = [] let recMatchClauses : SynMatchClause list =
allUnionTypes
|> List.collect (fun unionType ->
let cases = AstHelper.getUnionCases unionType
cases
|> List.choose (fun case ->
let analysis = analyse allUnionTypes case
// We already know there is a recursive reference somewhere
// in `analysis`.
if
analysis
|> List.exists (fun (_, ty) ->
match ty with
| NonRecursive _ -> false
| _ -> true
)
then
Some (case, analysis)
else
None
)
|> List.map (fun (case, analysis) ->
let lhsNames =
analysis
|> Seq.mapi (fun i x -> (i, x))
|> Seq.choose (fun (i, (name, desc)) ->
match desc with
| FieldDescription.NonRecursive _ ->
match name with
| None -> Ident.Create $"arg%i{i}"
| Some name -> name
|> SynPat.CreateNamed
|> Some
| FieldDescription.ListSelf _ -> Ident.Create "n" |> SynPat.CreateNamed |> Some
| FieldDescription.Self _ -> None
)
|> Seq.toList
let lhs =
match lhsNames with
| [] -> []
| lhsNames ->
SynPat.Tuple (false, lhsNames, List.replicate (lhsNames.Length - 1) range0, range0)
|> SynPat.CreateParen
|> List.singleton
let pat =
SynPat.LongIdent (
SynLongIdent.CreateFromLongIdent
[ Ident.Create "Instruction" ; getInstructionCaseName unionType case ],
None,
None,
SynArgPats.Pats lhs,
None,
range0
)
let body = [ SynExpr.CreateConst SynConst.Unit ] |> SynExpr.CreateSequential
SynMatchClause.SynMatchClause (
pat,
None,
body,
range0,
DebugPointAtTarget.Yes,
{
ArrowRange = Some range0
BarRange = Some range0
}
)
)
)
let matchStatement = let matchStatement =
SynExpr.CreateMatch (SynExpr.CreateIdentString "currentInstruction", baseMatchClauses @ recMatchClauses) SynExpr.CreateMatch (SynExpr.CreateIdentString "currentInstruction", baseMatchClauses @ recMatchClauses)
@@ -743,7 +799,7 @@ module internal CataGenerator =
[ [
SynExpr.CreateApp ( SynExpr.CreateApp (
SynExpr.CreateLongIdent (SynLongIdent.Create [ "instructions" ; "RemoveAt" ]), SynExpr.CreateLongIdent (SynLongIdent.Create [ "instructions" ; "RemoveAt" ]),
SynExpr.CreateParen (minusN (SynLongIdent.Create [ "instructions" ; "Count" ]) 1) SynExpr.CreateParen (SynExpr.minusN (SynLongIdent.Create [ "instructions" ; "Count" ]) 1)
) )
matchStatement matchStatement
] ]
@@ -765,18 +821,13 @@ module internal CataGenerator =
None, None,
SynExpr.DotIndexedGet ( SynExpr.DotIndexedGet (
SynExpr.CreateIdentString "instructions", SynExpr.CreateIdentString "instructions",
minusN (SynLongIdent.Create [ "instructions" ; "Count" ]) 1, SynExpr.minusN (SynLongIdent.Create [ "instructions" ; "Count" ]) 1,
range0, range0,
range0 range0
), ),
range0, range0,
DebugPointAtBinding.Yes range0, DebugPointAtBinding.Yes range0,
SynExpr.synBindingTriviaZero false
{
LeadingKeyword = SynLeadingKeyword.Let range0
InlineKeyword = None
EqualsRange = Some range0
}
) )
], ],
body, body,
@@ -837,11 +888,7 @@ module internal CataGenerator =
), ),
range0, range0,
DebugPointAtBinding.Yes range0, DebugPointAtBinding.Yes range0,
{ SynExpr.synBindingTriviaZero false
LeadingKeyword = SynLeadingKeyword.Let range0
InlineKeyword = None
EqualsRange = Some range0
}
) )
], ],
body, body,
@@ -865,12 +912,7 @@ module internal CataGenerator =
body, body,
range0, range0,
DebugPointAtBinding.NoneAtLet, DebugPointAtBinding.NoneAtLet,
trivia = trivia = SynExpr.synBindingTriviaZero false
{
LeadingKeyword = SynLeadingKeyword.Let range0
InlineKeyword = None
EqualsRange = Some range0
}
) )
let createModule let createModule

View File

@@ -756,12 +756,6 @@ module internal HttpClientGenerator =
| _ -> None | _ -> None
) )
let lowerFirstLetter (x : Ident) : Ident =
let result = StringBuilder x.idText.Length
result.Append (Char.ToLowerInvariant x.idText.[0]) |> ignore
result.Append x.idText.[1..] |> ignore
Ident.Create ((result : StringBuilder).ToString ())
let createModule let createModule
(opens : SynOpenDeclTarget list) (opens : SynOpenDeclTarget list)
(ns : LongIdent) (ns : LongIdent)
@@ -891,7 +885,7 @@ module internal HttpClientGenerator =
Some (SynBindingReturnInfo.Create pi.Type), Some (SynBindingReturnInfo.Create pi.Type),
SynExpr.CreateApp ( SynExpr.CreateApp (
SynExpr.CreateLongIdent ( SynExpr.CreateLongIdent (
SynLongIdent.CreateFromLongIdent [ lowerFirstLetter pi.Identifier ] SynLongIdent.CreateFromLongIdent [ Ident.lowerFirstLetter pi.Identifier ]
), ),
SynExpr.CreateConst SynConst.Unit SynExpr.CreateConst SynConst.Unit
), ),
@@ -927,7 +921,7 @@ module internal HttpClientGenerator =
properties properties
|> List.map (fun (_, pi) -> |> List.map (fun (_, pi) ->
SynPat.CreateTyped ( SynPat.CreateTyped (
SynPat.CreateNamed (lowerFirstLetter pi.Identifier), SynPat.CreateNamed (Ident.lowerFirstLetter pi.Identifier),
SynType.CreateFun (SynType.CreateLongIdent "unit", pi.Type) SynType.CreateFun (SynType.CreateLongIdent "unit", pi.Type)
) )
|> SynPat.CreateParen |> SynPat.CreateParen

View File

@@ -0,0 +1,14 @@
namespace WoofWare.Myriad.Plugins
open System
open System.Text
open Fantomas.FCS.Syntax
open Myriad.Core
[<RequireQualifiedAccess>]
module internal Ident =
let lowerFirstLetter (x : Ident) : Ident =
let result = StringBuilder x.idText.Length
result.Append (Char.ToLowerInvariant x.idText.[0]) |> ignore
result.Append x.idText.[1..] |> ignore
Ident.Create ((result : StringBuilder).ToString ())

View File

@@ -275,3 +275,19 @@ module internal SynExpr =
else else
SynLeadingKeyword.Let range0 SynLeadingKeyword.Let range0
} }
/// {ident} - {n}
let minusN (ident : SynLongIdent) (n : int) : SynExpr =
SynExpr.CreateApp (
SynExpr.CreateAppInfix (
SynExpr.CreateLongIdent (
SynLongIdent.SynLongIdent (
[ Ident.Create "op_Subtraction" ],
[],
[ Some (IdentTrivia.OriginalNotation "-") ]
)
),
SynExpr.CreateLongIdent ident
),
SynExpr.CreateConst (SynConst.Int32 n)
)

View File

@@ -25,6 +25,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="List.fs"/> <Compile Include="List.fs"/>
<Compile Include="Ident.fs" />
<Compile Include="AstHelper.fs"/> <Compile Include="AstHelper.fs"/>
<Compile Include="SynExpr.fs"/> <Compile Include="SynExpr.fs"/>
<Compile Include="SynType.fs"/> <Compile Include="SynType.fs"/>