Fabulous.AST
What is AST?
AST
stands for Abstract Syntax Tree. It is a tree representation of the abstract syntactic structure of source code written in a programming language.
It is used by compilers to analyze, transform, and generate code.
Can I generate code without using AST?
You can generate code by just using strings and string interpolation. But there are several reasons why you should not do that.
Here are some of the reasons:
- It's error-prone and hard to maintain.
- If the code you are generating is complex, then it's even harder to generate it using string interpolation.
- You will have to write some extra code to handle edge cases and make sure that the generated code is valid, handle formatting and indentation.
This is a simple example of generating code using StringBuilder
and string interpolation:
open System.Text
let code = StringBuilder()
code.AppendLine("module MyModule =")
code.AppendLine(" let x = 12")
code |> string |> printfn "%s"
// produces the following code:
|
Quote from fantomas:
For mercy's sake don't use string concatenation when generating F# code, use Fantomas instead. It is battle tested and proven technology!
Why use AST?
ASTs are more verbose than string interpolation and requires you to think in terms of nodes and trees, which can be a bit hard to grasp at first, but it becomes very powerful when you use it to generate code.
Some of the benefits of using AST to generate code are:
- The code generated is compliant with the F# syntax and is will most likely be valid and compilable.
- It provides a more structured way to generate code.
- It allows you to manipulate the code programmatically.
- It allows you to generate more complex code in a more maintainable way.
How to use AST to generate code?
Let's explore three different ways to generate code using AST:
1. Compiler AST
- It is a very verbose and hard to read.
- It is hard manipulate or analyze programmatically.
- Contains a lot of information that is not relevant to the code itself.
You can see a live example using Fantomas tools
open Fantomas.FCS.Syntax
open Fantomas.FCS.SyntaxTrivia
open Fantomas.FCS.Text
open Fantomas.FCS.Xml
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fantomas.FCS.dll"
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fantomas.Core.dll"
ParsedInput.ImplFile(
ParsedImplFileInput.ParsedImplFileInput(
fileName = "tmp.fsx",
isScript = true,
qualifiedNameOfFile = QualifiedNameOfFile.QualifiedNameOfFile(Ident("Tmp$fsx", Range.Zero)),
scopedPragmas = [],
hashDirectives = [],
contents =
[ SynModuleOrNamespace.SynModuleOrNamespace(
longId = [ Ident("Tmp", Range.Zero) ],
isRecursive = false,
kind = SynModuleOrNamespaceKind.AnonModule,
decls =
[ SynModuleDecl.Let(
isRecursive = false,
bindings =
[ SynBinding.SynBinding(
accessibility = None,
kind = SynBindingKind.Normal,
isInline = false,
isMutable = false,
attributes = [],
xmlDoc = PreXmlDoc.Empty,
valData =
SynValData.SynValData(
memberFlags = None,
valInfo =
SynValInfo.SynValInfo(
curriedArgInfos = [],
returnInfo =
SynArgInfo.SynArgInfo(
attributes = [],
optional = false,
ident = None
)
),
thisIdOpt = None
),
headPat =
SynPat.Named(
ident = SynIdent.SynIdent(ident = Ident("x", Range.Zero), trivia = None),
isThisVal = false,
accessibility = None,
range = Range.Zero
),
returnInfo = None,
expr = SynExpr.Const(constant = SynConst.Int32(12), range = Range.Zero),
range = Range.Zero,
debugPoint = DebugPointAtBinding.Yes(Range.Zero),
trivia =
{ LeadingKeyword = SynLeadingKeyword.Let(Range.Zero)
InlineKeyword = None
EqualsRange = Some(Range.Zero) }
) ],
range = Range.Zero
) ],
xmlDoc = PreXmlDoc.Empty,
attribs = [],
accessibility = None,
range = Range.Zero,
trivia = { LeadingKeyword = SynModuleOrNamespaceLeadingKeyword.None }
) ],
flags = (false, false),
trivia =
{ ConditionalDirectives = []
CodeComments = [] },
identifiers = set []
)
)
// produces the following code:
let x = 12
2. Fantomas Oak AST
It is a simplified version of the official AST that is used by Fantomas to format F# code.
- It is more concise and easier to read.
- It is a bit easier to manipulate or analyze programmatically.
- It is a bit more human-readable. as it contains only the relevant information about the code itself.
- But it's still not very easy to work with, as we will need to provide a lot of optional values even for simple code.
You can see a live example using the online tool
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fantomas.FCS.dll"
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fantomas.Core.dll"
open Fantomas.FCS.Text
open Fantomas.Core
open Fantomas.Core.SyntaxOak
Oak(
[],
[ ModuleOrNamespaceNode(
None,
[ BindingNode(
None,
None,
MultipleTextsNode([ SingleTextNode("let", Range.Zero) ], Range.Zero),
false,
None,
None,
Choice1Of2(IdentListNode([ IdentifierOrDot.Ident(SingleTextNode("x", Range.Zero)) ], Range.Zero)),
None,
[],
None,
SingleTextNode("=", Range.Zero),
Expr.Constant(Constant.FromText(SingleTextNode("12", Range.Zero))),
Range.Zero
)
|> ModuleDecl.TopLevelBinding ],
Range.Zero
) ],
Range.Zero
)
|> CodeFormatter.FormatOakAsync
|> Async.RunSynchronously
|> printfn "%s"
// produces the following code:
|
3. Fabulous.AST DSL
So far we have seen how to generate code using the official F# compiler AST and Fantomas Oak AST.
You might be thinking that it's not worth the effort to use ASTs to generate code and still prefer string interpolation. But that's where Fabulous.AST
comes in.
Fabulous.AST
library provides a more user-friendly API to generate code using ASTs.
It is built on top of Fantomas Oak AST and provides a more concise and easier to use API to generate code.
It aims to really cut down on the boilerplate code required to generate code.
You can provide your own configuration to format the code as you like by using FormatConfig
.
type FormatConfig =
{ IndentSize: Num
MaxLineLength: Num
EndOfLine: EndOfLineStyle
InsertFinalNewline: bool
SpaceBeforeParameter: bool
SpaceBeforeLowercaseInvocation: bool
SpaceBeforeUppercaseInvocation: bool
SpaceBeforeClassConstructor: bool
SpaceBeforeMember: bool
SpaceBeforeColon: bool }
Now let's take a look at same example using Fabulous.AST:
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fabulous.AST.dll"
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fantomas.FCS.dll"
open Fabulous.AST
open type Fabulous.AST.Ast
Oak() { AnonymousModule() { Value("x", "12") } }
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces the following code:
|
What widgets to use to generate the code?
Fabulous.AST maps the Fantomas Oak AST nodes. So you can use the online tool to take a peak at the AST nodes and then use the corresponding widgets to generate the code.
For example, the following Oak AST node:
Oak (1,0-1,10)
ModuleOrNamespaceNode (1,0-1,10)
BindingNode (1,0-1,10)
MultipleTextsNode (1,0-1,3)
let (1,0-1,3)
IdentListNode (1,4-1,5)
x (1,4-1,5)
= (1,6-1,7)
12 (1,8-1,10)
Translates to the following Fabulous.AST code:
Oak() {
AnonymousModule() {
Value("x", "12")
}
}
We have cut down the boilerplate code from 70 lines to just 5 lines of code. And it's much easier to read and understand. But we can generate much more complex code using Fabulous.AST. Let's take a look at some more examples.
Example 1: Modules and Namespaces
- We will generate a namespace
Widgets
with a moduleWidgetsModule
and a valuex
with the value12
. - We will generate an implicit namespace
Widgets.WidgetModule
with a functionwidgetFunction
with two parametersx
andy
and the body12
.
To learn more about modules and namespaces in F#, you can read the official documentation.
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fabulous.AST.dll"
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fantomas.FCS.dll"
open Fabulous.AST
open type Fabulous.AST.Ast
Oak() {
AnonymousModule() { NoWarn(String "0044") }
Namespace("Widgets") { Module("WidgetsModule") { Value("x", String("12")) } }
Namespace("Widgets.WidgetModule") {
Function("widgetFunction", [ ParameterPat("x"); ParameterPat("y") ], String("12"))
}
|> _.toImplicit()
|> _.triviaBefore(Newline())
AnonymousModule() { Module("WidgetsModule") { Value("y", String("12")) } }
|> _.triviaBefore(Newline())
AnonymousModule() { Value("y", String("12")) } |> _.triviaBefore(Newline())
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces the following code:
|
Example 2: Records
- We will generate a record type with two fields
Name
andAge
. - We will use
Namespace
,Module
andRecord
widgets to generate the code. - We want the record to be formatted using
Stroustrup
style. - Create a person record instance with name
Jose
and age30
.
To learn more about records in F#, you can read the official documentation.
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fabulous.AST.dll"
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fantomas.FCS.dll"
open Fabulous.AST
open type Fabulous.AST.Ast
let formatConfig =
{ FormatConfig.Default with
MultilineBracketStyle = Stroustrup
RecordMultilineFormatter = NumberOfItems }
Oak() {
Namespace("MyNamespace") {
Module("Records") {
(Record("Person") {
Field("Name", "string")
Field("Age", "int")
})
.members() {
Member("this.Name", InterpolatedStringExpr([ Constant("this.Name"); Constant("this.Age") ]))
}
Value("person", RecordExpr([ RecordFieldExpr("Name", "Jose"); RecordFieldExpr("Age", "30") ]))
Record("Person") {
Field("Name", "string")
Field("Age", "int")
}
|> _.attribute(Attribute("Struct"))
}
}
}
|> Gen.mkOak
|> Gen.runWith formatConfig
|> printfn "%s"
// produces the following code:
|
Example 3: Discriminated unions
- We will generate a discriminated union type with two cases
Some 'a
andNone
. - We will use AnonymousModule, Union and UnionCase widgets to generate the code.
- We will provide xmlDocs for the union type and the union cases.
To learn more about discriminated unions in F#, you can read the official documentation.
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fabulous.AST.dll"
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fantomas.FCS.dll"
open type Fabulous.AST.Ast
Oak() {
AnonymousModule() {
Union("Option") {
UnionCase("Some", "'a")
.triviaBefore(SingleLine("Represents the Some case with a value."))
UnionCase("None").triviaBefore(SingleLine("Represents the None case."))
}
|> _.typeParams(PostfixList("'a"))
|> _.xmlDocs([ "Represents the option type." ])
Union("Option") {
UnionCase("Some", "'a")
.triviaBefore(SingleLine("Represents the Some case with a value."))
UnionCase("None").triviaBefore(SingleLine("Represents the None case."))
}
|> _.attribute(Attribute("Struct"))
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces the following code:
|
Example 4: Classes
- We will generate a class type with explicit constructor with two fields
Name
, LastNameand
Age`. - We will use AnonymousModule, TypeDefn and Member widgets to generate the code.
To learn more about classes in F#, you can read the official documentation.
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fabulous.AST.dll"
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fantomas.FCS.dll"
open type Fabulous.AST.Ast
Oak() {
AnonymousModule() {
TypeDefn(
"Person",
ParenPat(
TuplePat(
[ ParameterPat(ConstantPat(Constant("name")))
ParameterPat(ConstantPat(Constant("lastName")))
ParameterPat(ConstantPat(Constant("age"))) ]
)
)
) {
Member("this.Name", ConstantExpr("name"))
Member("this.LastName", ConstantExpr("lastName"))
Member("this.Age", ConstantExpr("age"))
}
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces the following code:
|
Example 4: Units of Measure
- We will generate a unit of measure type with 6 cases
cm
,ml
,m
,s
,kg
andN
. - We will use AnonymousModule, Measure, MeasurePower, Tuple, AppPostfix and LongIdent widgets to generate the code.
- We will provide xmlDocs for each unit of measure.
To learn more about units of measure in F#, you can read the official documentation.
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fabulous.AST.dll"
#r "../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fantomas.FCS.dll"
open type Fabulous.AST.Ast
Oak() {
AnonymousModule() {
Measure("cm").xmlDocs([ "Cm, centimeters." ])
Measure("ml", MeasurePower(LongIdent "cm", Integer "3"))
.xmlDocs([ "Ml, milliliters." ])
Measure("m").xmlDocs([ "Distance, meters." ])
Measure("s").xmlDocs([ "Time, seconds." ])
Measure("kg").xmlDocs([ "Mass, kilograms." ])
Measure(
"N",
Tuple(
[ AppPostfix(LongIdent "kg", LongIdent "m")
MeasurePower(LongIdent "s", Integer "2") ],
"/"
)
)
.xmlDocs([ "Force, Newtons." ])
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces the following code:
|
Conclusion
Hope by now you have a good understanding of what is an AST and how you can use it to generate code using Fabulous.AST
.
You can generate pretty much any F# code you want as long as you provide the correct widgets. Use the online tool to find the correct widgets for the code you want to generate.
References
type StringBuilder = interface ISerializable new: unit -> unit + 5 overloads member Append: value: bool -> StringBuilder + 25 overloads member AppendFormat: provider: IFormatProvider * format: string * arg0: obj -> StringBuilder + 12 overloads member AppendJoin: separator: char * [<ParamArray>] values: obj array -> StringBuilder + 5 overloads member AppendLine: unit -> StringBuilder + 3 overloads member Clear: unit -> StringBuilder member CopyTo: sourceIndex: int * destination: char array * destinationIndex: int * count: int -> unit + 1 overload member EnsureCapacity: capacity: int -> int member Equals: span: ReadOnlySpan<char> -> bool + 1 overload ...
<summary>Represents a mutable string of characters. This class cannot be inherited.</summary>
--------------------
StringBuilder() : StringBuilder
StringBuilder(capacity: int) : StringBuilder
StringBuilder(value: string) : StringBuilder
StringBuilder(capacity: int, maxCapacity: int) : StringBuilder
StringBuilder(value: string, capacity: int) : StringBuilder
StringBuilder(value: string, startIndex: int, length: int, capacity: int) : StringBuilder
StringBuilder.AppendLine(handler: byref<StringBuilder.AppendInterpolatedStringHandler>) : StringBuilder
StringBuilder.AppendLine(value: string) : StringBuilder
StringBuilder.AppendLine(provider: System.IFormatProvider, handler: byref<StringBuilder.AppendInterpolatedStringHandler>) : StringBuilder
val string: value: 'T -> string
--------------------
type string = System.String
union case ParsedImplFileInput.ParsedImplFileInput: fileName: string * isScript: bool * qualifiedNameOfFile: QualifiedNameOfFile * scopedPragmas: ScopedPragma list * hashDirectives: ParsedHashDirective list * contents: SynModuleOrNamespace list * flags: bool * bool * trivia: ParsedImplFileInputTrivia * identifiers: Set<string> -> ParsedImplFileInput
--------------------
type ParsedImplFileInput = | ParsedImplFileInput of fileName: string * isScript: bool * qualifiedNameOfFile: QualifiedNameOfFile * scopedPragmas: ScopedPragma list * hashDirectives: ParsedHashDirective list * contents: SynModuleOrNamespace list * flags: bool * bool * trivia: ParsedImplFileInputTrivia * identifiers: Set<string> member Contents: SynModuleOrNamespace list member FileName: string member HashDirectives: ParsedHashDirective list member IsExe: bool member IsLastCompiland: bool member IsScript: bool member QualifiedName: QualifiedNameOfFile member ScopedPragmas: ScopedPragma list member Trivia: ParsedImplFileInputTrivia
union case QualifiedNameOfFile.QualifiedNameOfFile: Ident -> QualifiedNameOfFile
--------------------
type QualifiedNameOfFile = | QualifiedNameOfFile of Ident member Id: Ident member Range: range member Text: string
[<Struct>] type Ident = new: text: string * range: range -> Ident member idRange: range member idText: string
--------------------
Ident ()
new: text: string * range: range -> Ident
module Range from Fantomas.FCS.Text
--------------------
[<Struct>] type Range = member End: pos member EndColumn: int member EndLine: int member EndRange: range member FileName: string member IsSynthetic: bool member Start: pos member StartColumn: int member StartLine: int member StartRange: range ...
union case SynModuleOrNamespace.SynModuleOrNamespace: longId: LongIdent * isRecursive: bool * kind: SynModuleOrNamespaceKind * decls: SynModuleDecl list * xmlDoc: PreXmlDoc * attribs: SynAttributes * accessibility: SynAccess option * range: range * trivia: SynModuleOrNamespaceTrivia -> SynModuleOrNamespace
--------------------
type SynModuleOrNamespace = | SynModuleOrNamespace of longId: LongIdent * isRecursive: bool * kind: SynModuleOrNamespaceKind * decls: SynModuleDecl list * xmlDoc: PreXmlDoc * attribs: SynAttributes * accessibility: SynAccess option * range: range * trivia: SynModuleOrNamespaceTrivia member Range: range
union case SynBinding.SynBinding: accessibility: SynAccess option * kind: SynBindingKind * isInline: bool * isMutable: bool * attributes: SynAttributes * xmlDoc: PreXmlDoc * valData: SynValData * headPat: SynPat * returnInfo: SynBindingReturnInfo option * expr: SynExpr * range: range * debugPoint: DebugPointAtBinding * trivia: SynBindingTrivia -> SynBinding
--------------------
type SynBinding = | SynBinding of accessibility: SynAccess option * kind: SynBindingKind * isInline: bool * isMutable: bool * attributes: SynAttributes * xmlDoc: PreXmlDoc * valData: SynValData * headPat: SynPat * returnInfo: SynBindingReturnInfo option * expr: SynExpr * range: range * debugPoint: DebugPointAtBinding * trivia: SynBindingTrivia member RangeOfBindingWithRhs: range member RangeOfBindingWithoutRhs: range member RangeOfHeadPattern: range
union case SynValData.SynValData: memberFlags: SynMemberFlags option * valInfo: SynValInfo * thisIdOpt: Ident option -> SynValData
--------------------
type SynValData = | SynValData of memberFlags: SynMemberFlags option * valInfo: SynValInfo * thisIdOpt: Ident option member SynValInfo: SynValInfo
union case SynValInfo.SynValInfo: curriedArgInfos: SynArgInfo list list * returnInfo: SynArgInfo -> SynValInfo
--------------------
type SynValInfo = | SynValInfo of curriedArgInfos: SynArgInfo list list * returnInfo: SynArgInfo member ArgNames: string list member CurriedArgInfos: SynArgInfo list list
union case SynArgInfo.SynArgInfo: attributes: SynAttributes * optional: bool * ident: Ident option -> SynArgInfo
--------------------
type SynArgInfo = | SynArgInfo of attributes: SynAttributes * optional: bool * ident: Ident option member Attributes: SynAttributes member Ident: Ident option
union case SynIdent.SynIdent: ident: Ident * trivia: IdentTrivia option -> SynIdent
--------------------
type SynIdent = | SynIdent of ident: Ident * trivia: IdentTrivia option member Range: range
type Oak = inherit NodeBase new: parsedHashDirectives: ParsedHashDirectiveNode list * modulesOrNamespaces: ModuleOrNamespaceNode list * m: range -> Oak override Children: Node array member ModulesOrNamespaces: ModuleOrNamespaceNode list member ParsedHashDirectives: ParsedHashDirectiveNode list
--------------------
new: parsedHashDirectives: ParsedHashDirectiveNode list * modulesOrNamespaces: ModuleOrNamespaceNode list * m: range -> Oak
type ModuleOrNamespaceNode = inherit NodeBase new: header: ModuleOrNamespaceHeaderNode option * decls: ModuleDecl list * range: range -> ModuleOrNamespaceNode override Children: Node array member Declarations: ModuleDecl list member Header: ModuleOrNamespaceHeaderNode option member IsNamed: bool
--------------------
new: header: ModuleOrNamespaceHeaderNode option * decls: ModuleDecl list * range: range -> ModuleOrNamespaceNode
type BindingNode = inherit NodeBase new: xmlDoc: XmlDocNode option * attributes: MultipleAttributeListNode option * leadingKeyword: MultipleTextsNode * isMutable: bool * inlineNode: SingleTextNode option * accessibility: SingleTextNode option * functionName: Choice<IdentListNode,Pattern> * genericTypeParameters: TyparDecls option * parameters: Pattern list * returnType: BindingReturnInfoNode option * equals: SingleTextNode * expr: Expr * range: range -> BindingNode member Accessibility: SingleTextNode option member Attributes: MultipleAttributeListNode option override Children: Node array member Equals: SingleTextNode member Expr: Expr member FunctionName: Choice<IdentListNode,Pattern> member GenericTypeParameters: TyparDecls option member Inline: SingleTextNode option ...
--------------------
new: xmlDoc: XmlDocNode option * attributes: MultipleAttributeListNode option * leadingKeyword: MultipleTextsNode * isMutable: bool * inlineNode: SingleTextNode option * accessibility: SingleTextNode option * functionName: Choice<IdentListNode,Pattern> * genericTypeParameters: TyparDecls option * parameters: Pattern list * returnType: BindingReturnInfoNode option * equals: SingleTextNode * expr: Expr * range: range -> BindingNode
type MultipleTextsNode = inherit NodeBase new: content: SingleTextNode list * range: range -> MultipleTextsNode override Children: Node array member Content: SingleTextNode list
--------------------
new: content: SingleTextNode list * range: range -> MultipleTextsNode
type SingleTextNode = inherit NodeBase new: idText: string * range: range -> SingleTextNode override Children: Node array member Text: string
--------------------
new: idText: string * range: range -> SingleTextNode
type IdentListNode = inherit NodeBase new: content: IdentifierOrDot list * range: range -> IdentListNode override Children: Node array member Content: IdentifierOrDot list member IsEmpty: bool static member Empty: IdentListNode
--------------------
new: content: IdentifierOrDot list * range: range -> IdentListNode
static member CodeFormatter.FormatOakAsync: oak: Oak * config: FormatConfig -> Async<string>
module Async from Fantomas.Core
--------------------
type Async = static member AsBeginEnd: computation: ('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit) static member AwaitEvent: event: IEvent<'Del,'T> * ?cancelAction: (unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate) static member AwaitIAsyncResult: iar: IAsyncResult * ?millisecondsTimeout: int -> Async<bool> static member AwaitTask: task: Task<'T> -> Async<'T> + 1 overload static member AwaitWaitHandle: waitHandle: WaitHandle * ?millisecondsTimeout: int -> Async<bool> static member CancelDefaultToken: unit -> unit static member Catch: computation: Async<'T> -> Async<Choice<'T,exn>> static member Choice: computations: Async<'T option> seq -> Async<'T option> static member FromBeginEnd: beginAction: (AsyncCallback * obj -> IAsyncResult) * endAction: (IAsyncResult -> 'T) * ?cancelAction: (unit -> unit) -> Async<'T> + 3 overloads static member FromContinuations: callback: (('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T> ...
--------------------
type Async<'T>
static member Ast.Oak: unit -> CollectionBuilder<Oak,'marker>
--------------------
module Oak from Fabulous.AST
--------------------
type Oak = inherit NodeBase new: parsedHashDirectives: ParsedHashDirectiveNode list * modulesOrNamespaces: ModuleOrNamespaceNode list * m: range -> Oak override Children: Node array member ModulesOrNamespaces: ModuleOrNamespaceNode list member ParsedHashDirectives: ParsedHashDirectiveNode list
--------------------
new: parsedHashDirectives: ParsedHashDirectiveNode list * modulesOrNamespaces: ModuleOrNamespaceNode list * m: range -> Oak
(+0 other overloads)
static member Ast.Value: name: string * value: string * returnType: WidgetBuilder<Type> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: string -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: WidgetBuilder<Constant> * returnType: string -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: WidgetBuilder<Constant> * returnType: WidgetBuilder<Type> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: WidgetBuilder<Constant> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: WidgetBuilder<Expr> * returnType: string -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: WidgetBuilder<Expr> * returnType: WidgetBuilder<Type> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: WidgetBuilder<Expr> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Value: name: WidgetBuilder<Constant> * value: WidgetBuilder<Constant> * returnType: string -> WidgetBuilder<BindingNode>
(+0 other overloads)
<summary> It takes the root of the widget tree and create the corresponding Fantomas node, and recursively creating all children nodes </summary>
static member Ast.NoWarn: value: WidgetBuilder<Constant> -> WidgetBuilder<ParsedHashDirectiveNode>
static member Ast.NoWarn: args: string list -> WidgetBuilder<ParsedHashDirectiveNode>
static member Ast.NoWarn: args: WidgetBuilder<Constant> list -> WidgetBuilder<ParsedHashDirectiveNode>
static member Ast.String: value: WidgetBuilder<Constant> -> WidgetBuilder<Constant>
static member Ast.String: value: string -> WidgetBuilder<Constant>
static member Ast.String: unit -> WidgetBuilder<Type>
--------------------
module String from Fabulous.AST
--------------------
module String from Fantomas.Core
--------------------
module String from Microsoft.FSharp.Core
(+0 other overloads)
static member Ast.Function: name: string * parameters: string * bodyExpr: string * returnType: WidgetBuilder<Type> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Function: name: string * parameters: string * bodyExpr: string -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Function: name: string * parameters: string * bodyExpr: WidgetBuilder<Constant> * returnType: string -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Function: name: string * parameters: string * bodyExpr: WidgetBuilder<Constant> * returnType: WidgetBuilder<Type> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Function: name: string * parameters: string * bodyExpr: WidgetBuilder<Constant> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Function: name: string * parameters: string * bodyExpr: WidgetBuilder<Expr> * returnType: string -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Function: name: string * parameters: string * bodyExpr: WidgetBuilder<Expr> * returnType: WidgetBuilder<Type> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Function: name: string * parameters: string * bodyExpr: WidgetBuilder<Expr> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Function: name: string * parameters: WidgetBuilder<Pattern> * bodyExpr: string * returnType: string -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.ParameterPat: name: WidgetBuilder<Constant> -> WidgetBuilder<Pattern>
static member Ast.ParameterPat: name: WidgetBuilder<Pattern> -> WidgetBuilder<Pattern>
static member Ast.ParameterPat: name: string * pType: string -> WidgetBuilder<Pattern>
static member Ast.ParameterPat: name: string * pType: WidgetBuilder<Type> -> WidgetBuilder<Pattern>
static member Ast.ParameterPat: name: WidgetBuilder<Constant> * pType: string -> WidgetBuilder<Pattern>
static member Ast.ParameterPat: name: WidgetBuilder<Constant> * pType: WidgetBuilder<Type> -> WidgetBuilder<Pattern>
static member Ast.ParameterPat: name: WidgetBuilder<Pattern> * pType: string -> WidgetBuilder<Pattern>
static member Ast.ParameterPat: name: WidgetBuilder<Pattern> * pType: WidgetBuilder<Type> -> WidgetBuilder<Pattern>
static member Ast.Newline: unit -> WidgetBuilder<TriviaContent>
--------------------
module Newline from Fabulous.AST
static member Ast.Record: name: string -> CollectionBuilder<TypeDefnRecordNode,FieldNode>
--------------------
module Record from Fabulous.AST
static member Ast.Field: name: string * fieldType: string -> WidgetBuilder<FieldNode>
static member Ast.Field: name: string * fieldType: WidgetBuilder<Type> -> WidgetBuilder<FieldNode>
static member Ast.Field: fieldType: string -> WidgetBuilder<FieldNode>
static member Ast.Field: fieldType: WidgetBuilder<Type> -> WidgetBuilder<FieldNode>
--------------------
module Field from Fabulous.AST
(+0 other overloads)
static member Ast.Member: name: string * body: string * returnType: WidgetBuilder<Type> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Member: name: string * body: string -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Member: name: string * body: WidgetBuilder<Constant> * returnType: string -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Member: name: string * body: WidgetBuilder<Constant> * returnType: WidgetBuilder<Type> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Member: name: string * body: WidgetBuilder<Constant> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Member: name: WidgetBuilder<Constant> * body: string * returnType: string -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Member: name: WidgetBuilder<Constant> * body: string * returnType: WidgetBuilder<Type> -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Member: name: WidgetBuilder<Constant> * body: string -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.Member: name: string * body: WidgetBuilder<Expr> * returnType: string -> WidgetBuilder<BindingNode>
(+0 other overloads)
static member Ast.InterpolatedStringExpr: parts: string list * ?isVerbatim: bool * ?dollars: int -> WidgetBuilder<Expr>
static member Ast.InterpolatedStringExpr: part: WidgetBuilder<Constant> * ?isVerbatim: bool * ?dollars: int -> WidgetBuilder<Expr>
static member Ast.InterpolatedStringExpr: parts: WidgetBuilder<Constant> list * ?isVerbatim: bool * ?dollars: int -> WidgetBuilder<Expr>
static member Ast.InterpolatedStringExpr: part: WidgetBuilder<Expr> * ?isVerbatim: bool * ?dollars: int -> WidgetBuilder<Expr>
static member Ast.InterpolatedStringExpr: parts: WidgetBuilder<Expr> list * ?isVerbatim: bool * ?dollars: int -> WidgetBuilder<Expr>
static member Ast.InterpolatedStringExpr: part: TextSegment * ?isVerbatim: bool * ?dollars: int -> WidgetBuilder<Expr>
static member Ast.InterpolatedStringExpr: parts: TextSegment list * ?isVerbatim: bool * ?dollars: int -> WidgetBuilder<Expr>
static member Ast.Constant: value: string -> WidgetBuilder<Constant>
--------------------
module Constant from Fabulous.AST
--------------------
type Constant = | FromText of SingleTextNode | Unit of UnitNode | Measure of ConstantMeasureNode static member Node: c: Constant -> NodeBase
static member Ast.RecordExpr: fields: WidgetBuilder<RecordFieldNode> list -> WidgetBuilder<Expr>
static member Ast.RecordExpr: copyInfo: string * fields: WidgetBuilder<RecordFieldNode> list -> WidgetBuilder<Expr>
static member Ast.RecordExpr: copyInfo: WidgetBuilder<Constant> * fields: WidgetBuilder<RecordFieldNode> list -> WidgetBuilder<Expr>
static member Ast.RecordExpr: copyInfo: WidgetBuilder<Expr> * fields: WidgetBuilder<RecordFieldNode> list -> WidgetBuilder<Expr>
--------------------
module RecordExpr from Fabulous.AST
static member Ast.RecordFieldExpr: name: string * expr: WidgetBuilder<Constant> -> WidgetBuilder<RecordFieldNode>
static member Ast.RecordFieldExpr: name: string * expr: WidgetBuilder<Expr> -> WidgetBuilder<RecordFieldNode>
static member Ast.Attribute: value: string * expr: WidgetBuilder<Constant> -> WidgetBuilder<AttributeNode>
static member Ast.Attribute: value: string * expr: WidgetBuilder<Expr> -> WidgetBuilder<AttributeNode>
static member Ast.Attribute: value: string -> WidgetBuilder<AttributeNode>
static member Ast.Union: name: string -> CollectionBuilder<TypeDefnUnionNode,UnionCaseNode>
--------------------
module Union from Fabulous.AST
static member Ast.UnionCase: name: string * fields: (string * WidgetBuilder<Type>) list -> WidgetBuilder<UnionCaseNode>
static member Ast.UnionCase: name: string * fields: (string * string) list -> WidgetBuilder<UnionCaseNode>
static member Ast.UnionCase: name: string * field: string -> WidgetBuilder<UnionCaseNode>
static member Ast.UnionCase: name: string * field: WidgetBuilder<FieldNode> -> WidgetBuilder<UnionCaseNode>
static member Ast.UnionCase: name: string * fields: string list -> WidgetBuilder<UnionCaseNode>
static member Ast.UnionCase: name: string * field: WidgetBuilder<Type> -> WidgetBuilder<UnionCaseNode>
static member Ast.UnionCase: name: string * fields: WidgetBuilder<Type> list -> WidgetBuilder<UnionCaseNode>
static member Ast.UnionCase: name: string * fields: WidgetBuilder<FieldNode> list -> WidgetBuilder<UnionCaseNode>
static member Ast.UnionCase: name: string -> WidgetBuilder<UnionCaseNode>
--------------------
module UnionCase from Fabulous.AST
static member Ast.PostfixList: decls: WidgetBuilder<TyparDeclNode> * constraints: WidgetBuilder<TypeConstraint> -> WidgetBuilder<TyparDecls>
static member Ast.PostfixList: constraints: WidgetBuilder<TypeConstraint> -> WidgetBuilder<TyparDecls>
static member Ast.PostfixList: constraints: WidgetBuilder<TypeConstraint> list -> WidgetBuilder<TyparDecls>
static member Ast.PostfixList: decl: string -> WidgetBuilder<TyparDecls>
static member Ast.PostfixList: decl: WidgetBuilder<TyparDeclNode> -> WidgetBuilder<TyparDecls>
static member Ast.PostfixList: decls: string list -> WidgetBuilder<TyparDecls>
static member Ast.PostfixList: decls: WidgetBuilder<TyparDeclNode> list -> WidgetBuilder<TyparDecls>
static member Ast.PostfixList: decls: string list * constraints: WidgetBuilder<TypeConstraint> list -> WidgetBuilder<TyparDecls>
static member Ast.PostfixList: decls: WidgetBuilder<TyparDeclNode> list * constraints: WidgetBuilder<TypeConstraint> list -> WidgetBuilder<TyparDecls>
static member Ast.TypeDefn: name: string -> CollectionBuilder<TypeDefnRegularNode,MemberDefn>
static member Ast.TypeDefn: name: string * constructor: WidgetBuilder<ImplicitConstructorNode> -> CollectionBuilder<TypeDefnRegularNode,MemberDefn>
static member Ast.TypeDefn: name: string * constructor: WidgetBuilder<Pattern> -> CollectionBuilder<TypeDefnRegularNode,MemberDefn>
--------------------
type TypeDefn = | Enum of TypeDefnEnumNode | Union of TypeDefnUnionNode | Record of TypeDefnRecordNode | None of TypeNameNode | Abbrev of TypeDefnAbbrevNode | Explicit of TypeDefnExplicitNode | Augmentation of TypeDefnAugmentationNode | Delegate of TypeDefnDelegateNode | Regular of TypeDefnRegularNode static member Node: x: TypeDefn -> Node static member TypeDefnNode: x: TypeDefn -> ITypeDefn
static member Ast.ParenPat: pat: string -> WidgetBuilder<Pattern>
static member Ast.ParenPat: pat: WidgetBuilder<Constant> -> WidgetBuilder<Pattern>
static member Ast.ParenPat: pat: WidgetBuilder<Pattern> -> WidgetBuilder<Pattern>
--------------------
module ParenPat from Fabulous.AST
static member Ast.TuplePat: values: string list -> WidgetBuilder<Pattern>
static member Ast.TuplePat: values: WidgetBuilder<Constant> list -> WidgetBuilder<Pattern>
static member Ast.TuplePat: value: WidgetBuilder<Pattern> list -> WidgetBuilder<Pattern>
--------------------
module TuplePat from Fabulous.AST
static member Ast.ConstantPat: value: WidgetBuilder<Constant> -> WidgetBuilder<Pattern>
static member Ast.ConstantExpr: value: WidgetBuilder<Constant> -> WidgetBuilder<Expr>
static member Ast.Measure: name: string * powerType: string -> WidgetBuilder<TypeDefnAbbrevNode>
static member Ast.Measure: name: string * powerType: WidgetBuilder<Type> -> WidgetBuilder<TypeDefnAbbrevNode>
static member Ast.Measure: name: string -> WidgetBuilder<TypeNameNode>
--------------------
module Measure from Fabulous.AST
--------------------
type Measure = | Single of SingleTextNode | Operator of MeasureOperatorNode | Divide of MeasureDivideNode | Power of MeasurePowerNode | Multiple of IdentListNode | Seq of MeasureSequenceNode | Paren of MeasureParenNode static member Node: m: Measure -> Node
--------------------
type MeasureAttribute = inherit Attribute new: unit -> MeasureAttribute
--------------------
new: unit -> MeasureAttribute
static member Ast.MeasurePower: measure: WidgetBuilder<Measure> * node: WidgetBuilder<RationalConstNode> -> WidgetBuilder<Measure>
static member Ast.MeasurePower: value: string * rational: WidgetBuilder<RationalConstNode> -> WidgetBuilder<Type>
static member Ast.MeasurePower: value: WidgetBuilder<Type> * rational: WidgetBuilder<RationalConstNode> -> WidgetBuilder<Type>
static member Ast.LongIdent: value: string -> WidgetBuilder<Type>
static member Ast.LongIdent: value: string list -> WidgetBuilder<Type>
--------------------
type LongIdent = Ident list
static member Ast.Integer: value: string -> WidgetBuilder<RationalConstNode>
static member Ast.Tuple: items: string list * exponent: string -> WidgetBuilder<Type>
static member Ast.Tuple: items: string list -> WidgetBuilder<Type>
static member Ast.Tuple: items: WidgetBuilder<Type> list * exponent: string -> WidgetBuilder<Type>
static member Ast.Tuple: items: WidgetBuilder<Type> list -> WidgetBuilder<Type>
--------------------
module Tuple from Fabulous.AST
static member Ast.AppPostfix: first: WidgetBuilder<Type> * last: string -> WidgetBuilder<Type>
static member Ast.AppPostfix: first: string * last: WidgetBuilder<Type> -> WidgetBuilder<Type>
static member Ast.AppPostfix: first: WidgetBuilder<Type> * last: WidgetBuilder<Type> -> WidgetBuilder<Type>