Oak
Overview
The Oak widget is the root container for all F# AST nodes in the Fabulous.AST DSL. It serves as the entry point for creating F# code and must be used as the outermost container for your AST structure.
Basic Usage
#r "../../src/Fabulous.AST/bin/Release/netstandard2.1/publish/Fantomas.Core.dll"
#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
open Fantomas.FCS.Text
Oak() { AnonymousModule() { Value("x", Int(42)) } }
|> Gen.mkOak // Convert to an Oak AST node
|> Gen.run // Generate the F# code string
|> printfn "%s"
// produces the following code:
|
Structure
The Oak widget can contain any combination of the following top-level nodes:
AnonymousModule: For file-level codeNamespace: For organizing code in namespacesHashDirective: For compiler directives
Note:
Modulenodes must be nested inside eitherAnonymousModuleorNamespacenodes.
Adding Hash Directives
Add compiler directives at the Oak level:
Oak() { AnonymousModule() { NoWarn("0044") } }
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces the following code:
|
Example with Multiple Components
Here's a more complete example showing how Oak can contain multiple components:
Oak() {
// Hash directive at the file level
AnonymousModule() { NoWarn("0044") }
// A namespace with a module
Namespace("Widgets") { Module("WidgetModule") { Value("x", String("12")) } }
// An anonymous module with code
AnonymousModule() { Value("y", String("12")) } |> _.triviaBefore(Newline())
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces the following code:
|
Using EscapeHatch for raw SyntaxOak nodes
Example: injecting a raw top-level binding node into an anonymous module.
open Fantomas.Core.SyntaxOak
open type Fabulous.AST.Ast
Oak() {
AnonymousModule() {
// Use the DSL normally
Value("x", Int 42)
// If you must inject a raw SyntaxOak node, wrap it in EscapeHatch
EscapeHatch(
ModuleDecl.TopLevelBinding(
BindingNode(
None,
None,
MultipleTextsNode([ SingleTextNode("let", Range.Zero) ], Range.Zero),
false,
None,
None,
Choice1Of2(IdentListNode([ IdentifierOrDot.Ident(SingleTextNode("y", Range.Zero)) ], Range.Zero)),
None,
List.Empty,
None,
SingleTextNode("=", Range.Zero),
Expr.Constant(Constant.FromText(SingleTextNode("12", Range.Zero))),
Range.Zero
)
)
)
}
}
|> Gen.mkOak
|> Gen.run
|> printfn "%s"
// produces the following code:
|
Likewise, if you have other raw nodes (e.g., TypeDefn.Abbrev, EnumCaseNode, etc.), inject them via EscapeHatch(...).
The preferred approach remains to use the provided widgets (Abbrev, EnumCase, Record, Value, ...), which do not require EscapeHatch.
static member Ast.Oak: unit -> CollectionBuilder<Fantomas.Core.SyntaxOak.Oak,'marker>
--------------------
module Oak from Fabulous.AST
(+0 other overloads)
static member Ast.Value: name: string * value: string * returnType: WidgetBuilder<Fantomas.Core.SyntaxOak.Type> -> WidgetBuilder<Fantomas.Core.SyntaxOak.BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: string -> WidgetBuilder<Fantomas.Core.SyntaxOak.BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: WidgetBuilder<Fantomas.Core.SyntaxOak.Constant> * returnType: string -> WidgetBuilder<Fantomas.Core.SyntaxOak.BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: WidgetBuilder<Fantomas.Core.SyntaxOak.Constant> * returnType: WidgetBuilder<Fantomas.Core.SyntaxOak.Type> -> WidgetBuilder<Fantomas.Core.SyntaxOak.BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: WidgetBuilder<Fantomas.Core.SyntaxOak.Constant> -> WidgetBuilder<Fantomas.Core.SyntaxOak.BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: WidgetBuilder<Fantomas.Core.SyntaxOak.Expr> * returnType: string -> WidgetBuilder<Fantomas.Core.SyntaxOak.BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: WidgetBuilder<Fantomas.Core.SyntaxOak.Expr> * returnType: WidgetBuilder<Fantomas.Core.SyntaxOak.Type> -> WidgetBuilder<Fantomas.Core.SyntaxOak.BindingNode>
(+0 other overloads)
static member Ast.Value: name: string * value: WidgetBuilder<Fantomas.Core.SyntaxOak.Expr> -> WidgetBuilder<Fantomas.Core.SyntaxOak.BindingNode>
(+0 other overloads)
static member Ast.Value: name: WidgetBuilder<Fantomas.Core.SyntaxOak.Constant> * value: WidgetBuilder<Fantomas.Core.SyntaxOak.Constant> * returnType: string -> WidgetBuilder<Fantomas.Core.SyntaxOak.BindingNode>
(+0 other overloads)
static member Ast.Int: unit -> WidgetBuilder<Fantomas.Core.SyntaxOak.Type>
<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<Fantomas.Core.SyntaxOak.Constant> -> WidgetBuilder<Fantomas.Core.SyntaxOak.ModuleDecl>
static member Ast.NoWarn: args: string seq -> WidgetBuilder<Fantomas.Core.SyntaxOak.ModuleDecl>
static member Ast.NoWarn: args: WidgetBuilder<Fantomas.Core.SyntaxOak.Constant> seq -> WidgetBuilder<Fantomas.Core.SyntaxOak.ModuleDecl>
static member Ast.String: value: WidgetBuilder<Fantomas.Core.SyntaxOak.Constant> -> WidgetBuilder<Fantomas.Core.SyntaxOak.Constant>
static member Ast.String: value: string -> WidgetBuilder<Fantomas.Core.SyntaxOak.Constant>
static member Ast.String: unit -> WidgetBuilder<Fantomas.Core.SyntaxOak.Type>
--------------------
module String from Fabulous.AST
--------------------
module String from Microsoft.FSharp.Core
static member Ast.Newline: unit -> WidgetBuilder<Fantomas.Core.SyntaxOak.TriviaContent>
--------------------
module Newline from Fabulous.AST
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)
static member Ast.Int: unit -> WidgetBuilder<Type>
static member Ast.EscapeHatch: node: 'T -> WidgetBuilder<'T>
--------------------
module EscapeHatch from Fabulous.AST
module ModuleDecl from Fabulous.AST
<summary> Shared attribute definitions used across module declaration widget types </summary>
--------------------
type ModuleDecl = | OpenList of OpenListNode | HashDirectiveList of HashDirectiveListNode | Attributes of ModuleDeclAttributesNode | DeclExpr of Expr | Exception of ExceptionDefnNode | ExternBinding of ExternBindingNode | TopLevelBinding of BindingNode | ModuleAbbrev of ModuleAbbrevNode | NestedModule of NestedModuleNode | TypeDefn of TypeDefn ... static member Node: x: ModuleDecl -> Node
module BindingNode from Fabulous.AST
--------------------
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
module SingleTextNode from Fabulous.AST
--------------------
type SingleTextNode = inherit NodeBase new: idText: string * range: range -> SingleTextNode override Children: Node array member Text: string
--------------------
new: idText: string * range: range -> SingleTextNode
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 ...
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 Ast.List: unit -> WidgetBuilder<Type>
--------------------
module List from Fabulous.AST
--------------------
module List from Microsoft.FSharp.Collections
--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T member IsEmpty: bool member Item: index: int -> 'T with get ...
union case TextSegment.Expr: WidgetBuilder<FillExprNode> * int -> TextSegment
--------------------
module Expr from Fabulous.AST
--------------------
type Expr = | Lazy of ExprLazyNode | Single of ExprSingleNode | Constant of Constant | Null of SingleTextNode | Quote of ExprQuoteNode | Typed of ExprTypedNode | New of ExprNewNode | Tuple of ExprTupleNode | StructTuple of ExprStructTupleNode | ArrayOrList of ExprArrayOrListNode ... static member Node: x: Expr -> Node member HasParentheses: bool
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
Fabulous.AST