Skip to content

Commit

Permalink
Add ClassEnd wiget + More tests
Browse files Browse the repository at this point in the history
  • Loading branch information
edgarfgp committed Jun 12, 2023
1 parent 086de2d commit 16cd3c9
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 12 deletions.
95 changes: 90 additions & 5 deletions src/Fabulous.AST.Tests/TypeDefinitions/Class.fs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ type Person =
)
)

AnonymousModule() { (Class("Person") { EscapeHatch(memberNode) }).parameters([]) }
AnonymousModule() { (Class("Person") { EscapeHatch(memberNode) }).implicitConstructorParameters([]) }
|> produces
"""
type Person () =
Expand Down Expand Up @@ -113,7 +113,10 @@ type Person () =
[ "name"; "lastName"; "age" ]
|> List.map(fun n -> SimplePatNode(None, false, SingleTextNode(n, Range.Zero), None, Range.Zero))

AnonymousModule() { (Class("Person") { EscapeHatch(memberNode) }).parameters(param) }
AnonymousModule() {
(Class("Person") { EscapeHatch(memberNode) })
.implicitConstructorParameters(param)
}
|> produces
"""
type Person (name, lastName, age) =
Expand Down Expand Up @@ -162,7 +165,10 @@ type Person (name, lastName, age) =
Range.Zero
))

AnonymousModule() { (Class("Person") { EscapeHatch(memberNode) }).parameters(param) }
AnonymousModule() {
(Class("Person") { EscapeHatch(memberNode) })
.implicitConstructorParameters(param)
}
|> produces
"""
type Person (name: string, lastName: string, ?age: int) =
Expand Down Expand Up @@ -200,7 +206,11 @@ type Person (name: string, lastName: string, ?age: int) =
let param =
SimplePatNode(None, false, SingleTextNode("name", Range.Zero), Some(Type.FromString("string")), Range.Zero)

AnonymousModule() { (Class("Person") { EscapeHatch(memberNode) }).isStruct().parameters([ param ]) }
AnonymousModule() {
(Class("Person") { EscapeHatch(memberNode) })
.isStruct()
.implicitConstructorParameters([ param ])
}
|> produces
"""
[<Struct>]
Expand Down Expand Up @@ -240,7 +250,7 @@ type Person (name: string) =
AnonymousModule() {
(Class("Person") { EscapeHatch(memberNode) })
.attributes([ "Sealed"; "AbstractClass" ])
.parameters([])
.implicitConstructorParameters([])
}
|> produces
"""
Expand Down Expand Up @@ -287,3 +297,78 @@ type MyClass =
member this.Area with set value = ()
member this.Pi = 3.14
"""

[<Test>]
let ``Produces a class with constructor that implements an interface`` () =
let parameters =
[ (Type.FromString("int"), SingleTextNode.rightArrow)
(Type.FromString("int"), SingleTextNode.rightArrow) ]

let method =
MemberDefnAbstractSlotNode.Method(
"Add",
Type.Funs(TypeFunsNode(parameters, Type.FromString("int"), Range.Zero))
)

let property = MemberDefnAbstractSlotNode.Property("Pi", Type.FromString("float"))

let getSetProperty =
MemberDefnAbstractSlotNode.GetSet("Area", Type.FromString("float"))

let interfaceWidget () =
Interface("MyInterface") {
EscapeHatch(method)
EscapeHatch(property)
EscapeHatch(getSetProperty)
}

AnonymousModule() {
EmptyClass("MyClass")
.implicitConstructorParameters([])
.implements(interfaceWidget())

}
|> produces
"""
type MyClass () =
interface MyInterface with
member this.Add(var0) (var1)= var0 + var1
member this.Area = 4.
member this.Area with set value = ()
member this.Pi = 3.14
"""

[<Test>]
let ``Produces a class end`` () =
AnonymousModule() { ClassEnd("MyClass") }
|> produces
"""
type MyClass =
class
end
"""

[<Test>]
let ``Produces a class end with constructor`` () =
AnonymousModule() { ClassEnd("MyClass").implicitConstructorParameters([]) }
|> produces
"""
type MyClass () =
class
end
"""

[<Test>]
let ``Produces a class end with constructor and attributes`` () =
AnonymousModule() {
ClassEnd("MyClass")
.attributes([ "Sealed"; "AbstractClass" ])
.implicitConstructorParameters([])
}
|> produces
"""
[<Sealed; AbstractClass>]
type MyClass () =
class
end
"""
1 change: 1 addition & 0 deletions src/Fabulous.AST/Fabulous.AST.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
<Compile Include="Widgets\TypeDefinitions\Record.fs" />
<Compile Include="Widgets\TypeDefinitions\Interface.fs" />
<Compile Include="Widgets\TypeDefinitions\Class.fs" />
<Compile Include="Widgets\TypeDefinitions\ClassEnd.fs" />
<Compile Include="Widgets\TypeDefinitions\GenericInterface.fs" />
<Compile Include="Widgets\ControlFlow\IfThen.fs" />
<Compile Include="Widgets\ControlFlow\IfThenElif.fs" />
Expand Down
4 changes: 4 additions & 0 deletions src/Fabulous.AST/Widgets/Common.fs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ module Auxiliary =
let leftParenthesis = SingleTextNode.Create "("
let rightParenthesis = SingleTextNode.Create ")"
let ``abstract`` = SingleTextNode.Create "abstract"
let ``interface`` = SingleTextNode.Create "interface"
let ``class`` = SingleTextNode.Create "class"
let ``end`` = SingleTextNode.Create "end"
let ``with`` = SingleTextNode.Create "with"
let ``member`` = SingleTextNode.Create "member"
let rightArrow = SingleTextNode.Create "->"
let lefArrow = SingleTextNode.Create "<-"
Expand Down
21 changes: 14 additions & 7 deletions src/Fabulous.AST/Widgets/TypeDefinitions/Class.fs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ type ClassTypeDefnRegularNode
TypeNameNode(
None,
multipleAttributes,
SingleTextNode("type", Range.Zero),
SingleTextNode.``type``,
Some(name),
IdentListNode([], Range.Zero),
None,
[],
implicitConstructor,
Some(SingleTextNode("=", Range.Zero)),
Some(SingleTextNode.equals),
None,
Range.Zero
),
Expand Down Expand Up @@ -86,9 +86,9 @@ module Class =
let interfaceMemberDefn =
MemberDefn.Interface(
MemberDefnInterfaceNode(
SingleTextNode("interface", Range.Zero),
SingleTextNode.``interface``,
Type.FromString(name),
Some(SingleTextNode("with", Range.Zero)),
Some(SingleTextNode.``with``),
members,
Range.Zero
)
Expand Down Expand Up @@ -119,9 +119,9 @@ module Class =
let interfaceMemberDefn =
MemberDefn.Interface(
MemberDefnInterfaceNode(
SingleTextNode("interface", Range.Zero),
SingleTextNode.``interface``,
Type.FromString(name),
Some(SingleTextNode("with", Range.Zero)),
Some(SingleTextNode.``with``),
members,
Range.Zero
)
Expand Down Expand Up @@ -188,8 +188,11 @@ module ClassBuilders =
AttributesBundle(StackList.empty(), ValueSome [| Class.Name.WithValue(name.Compile()) |], ValueNone)
)


static member inline Class(node: SingleTextNode) = Ast.Class(Ast.EscapeHatch(node))

static member inline EmptyClass(node: SingleTextNode) = Ast.EmptyClass(Ast.EscapeHatch(node))

static member inline Class(name: string) = Ast.Class(SingleTextNode.Create(name))

static member inline EmptyClass(name: string) =
Expand All @@ -206,7 +209,11 @@ type ClassModifiers =
this.AddScalar(Class.MultipleAttributes.WithValue(attributes))

[<Extension>]
static member inline parameters(this: WidgetBuilder<ClassTypeDefnRegularNode>, parameters: SimplePatNode list) =
static member inline implicitConstructorParameters
(
this: WidgetBuilder<ClassTypeDefnRegularNode>,
parameters: SimplePatNode list
) =
this.AddScalar(Class.Parameters.WithValue(parameters))

[<Extension>]
Expand Down
139 changes: 139 additions & 0 deletions src/Fabulous.AST/Widgets/TypeDefinitions/ClassEnd.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
namespace Fabulous.AST

open System.Runtime.CompilerServices
open Fantomas.FCS.Text
open Fabulous.AST.StackAllocatedCollections
open Fantomas.Core.SyntaxOak
open Fabulous.AST.StackAllocatedCollections.StackList
open Microsoft.FSharp.Collections

module ClassEnd =
let Name = Attributes.defineWidget "Name"
let Parameters = Attributes.defineScalar<SimplePatNode list> "Parameters"
let Members = Attributes.defineWidgetCollection "Members"
let MultipleAttributes = Attributes.defineScalar<string list> "MultipleAttributes"

let WidgetKey =
Widgets.register "ClassEnd" (fun widget ->
let name = Helpers.getNodeFromWidget<SingleTextNode> widget Name
let parameters = Helpers.tryGetScalarValue widget Parameters
let attributes = Helpers.tryGetScalarValue widget MultipleAttributes

let multipleAttributes =
match attributes with
| ValueSome values -> MultipleAttributeListNode.Create values |> Some
| ValueNone -> None

let implicitConstructor =
match parameters with
| ValueNone -> None
| ValueSome(parameters) when parameters.IsEmpty ->
Some(
ImplicitConstructorNode(
None,
None,
None,
SingleTextNode.leftParenthesis,
[],
SingleTextNode.rightParenthesis,
None,
Range.Zero
)
)
| ValueSome(simplePatNodes) ->
let simplePats =
match simplePatNodes with
| [] -> []
| head :: tail ->
[ yield Choice1Of2 head
for p in tail do
yield Choice2Of2 SingleTextNode.comma
yield Choice1Of2 p ]

Some(
ImplicitConstructorNode(
None,
None,
None,
SingleTextNode.leftParenthesis,
simplePats,
SingleTextNode.rightParenthesis,
None,
Range.Zero
)
)

TypeDefnExplicitNode(
TypeNameNode(
None,
multipleAttributes,
SingleTextNode.``type``,
Some(name),
IdentListNode([], Range.Zero),
None,
[],
implicitConstructor,
Some(SingleTextNode.equals),
None,
Range.Zero
),
TypeDefnExplicitBodyNode(SingleTextNode.``class``, [], SingleTextNode.``end``, Range.Zero),
[],
Range.Zero
))

[<AutoOpen>]
module ClassEndBuilders =
type Ast with

static member inline ClassEnd(name: WidgetBuilder<#SingleTextNode>) =
WidgetBuilder<TypeDefnExplicitNode>(
ClassEnd.WidgetKey,
AttributesBundle(StackList.empty(), ValueSome [| ClassEnd.Name.WithValue(name.Compile()) |], ValueNone)
)

static member inline ClassEnd(node: SingleTextNode) = Ast.ClassEnd(Ast.EscapeHatch(node))

static member inline ClassEnd(name: string) =
Ast.ClassEnd(SingleTextNode.Create(name))

[<Extension>]
type ClassEndModifiers =
[<Extension>]
static member inline isStruct(this: WidgetBuilder<TypeDefnExplicitNode>) =
this.AddScalar(ClassEnd.MultipleAttributes.WithValue([ "Struct" ]))

[<Extension>]
static member inline attributes(this: WidgetBuilder<TypeDefnExplicitNode>, attributes: string list) =
this.AddScalar(ClassEnd.MultipleAttributes.WithValue(attributes))

[<Extension>]
static member inline implicitConstructorParameters
(
this: WidgetBuilder<TypeDefnExplicitNode>,
parameters: SimplePatNode list
) =
this.AddScalar(ClassEnd.Parameters.WithValue(parameters))

[<Extension>]
type ClassEndYieldExtensions =
[<Extension>]
static member inline Yield
(
_: CollectionBuilder<'parent, ModuleDecl>,
x: WidgetBuilder<TypeDefnExplicitNode>
) : CollectionContent =
let node = Tree.compile x
let typeDefn = TypeDefn.Explicit(node)
let typeDefn = ModuleDecl.TypeDefn(typeDefn)
let widget = Ast.EscapeHatch(typeDefn).Compile()
{ Widgets = MutStackArray1.One(widget) }

[<Extension>]
static member inline Yield
(
_: CollectionBuilder<TypeDefnExplicitNode, MemberDefn>,
x: MemberDefn
) : CollectionContent =
let widget = Ast.EscapeHatch(x).Compile()
{ Widgets = MutStackArray1.One(widget) }

0 comments on commit 16cd3c9

Please sign in to comment.