Header menu logo Fabulous.AST

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:
let x = 42

Structure

The Oak widget can contain any combination of the following top-level nodes:

Note: Module nodes must be nested inside either AnonymousModule or Namespace nodes.

Adding Hash Directives

Add compiler directives at the Oak level:

Oak() { AnonymousModule() { NoWarn("0044") } }
|> Gen.mkOak
|> Gen.run
|> printfn "%s"

// produces the following code:
#nowarn 0044

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:
#nowarn 0044
namespace Widgets

module WidgetModule =
    let x = "12"

let y = "12"

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:
let x = 42
let y = 12

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.

namespace Fabulous
namespace Fabulous.AST
type Ast = class end
namespace Fantomas
namespace Fantomas.FCS
namespace Fantomas.FCS.Text
Multiple items
static member Ast.Oak: unit -> CollectionBuilder<Fantomas.Core.SyntaxOak.Oak,'marker>

--------------------
module Oak from Fabulous.AST
static member Ast.AnonymousModule: unit -> CollectionBuilder<Fantomas.Core.SyntaxOak.ModuleOrNamespaceNode,Fantomas.Core.SyntaxOak.ModuleDecl>
static member Ast.Value: name: string * value: string * returnType: string -> WidgetBuilder<Fantomas.Core.SyntaxOak.BindingNode>
   (+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: value: int -> WidgetBuilder<Fantomas.Core.SyntaxOak.Constant>
static member Ast.Int: unit -> WidgetBuilder<Fantomas.Core.SyntaxOak.Type>
module Gen from Fabulous.AST
<summary> It takes the root of the widget tree and create the corresponding Fantomas node, and recursively creating all children nodes </summary>
val mkOak: root: WidgetBuilder<'node> -> 'node
val run: oak: Fantomas.Core.SyntaxOak.Oak -> string
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
static member Ast.NoWarn: value: string -> WidgetBuilder<Fantomas.Core.SyntaxOak.ModuleDecl>
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.Namespace: name: string -> CollectionBuilder<Fantomas.Core.SyntaxOak.ModuleOrNamespaceNode,Fantomas.Core.SyntaxOak.ModuleDecl>
static member Ast.Module: name: string -> CollectionBuilder<Fantomas.Core.SyntaxOak.ModuleDecl,Fantomas.Core.SyntaxOak.ModuleDecl>
Multiple items
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
Multiple items
static member Ast.Newline: unit -> WidgetBuilder<Fantomas.Core.SyntaxOak.TriviaContent>

--------------------
module Newline from Fabulous.AST
namespace Fantomas.Core
module SyntaxOak from Fantomas.Core
Multiple items
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
static member Ast.AnonymousModule: unit -> CollectionBuilder<ModuleOrNamespaceNode,ModuleDecl>
static member Ast.Value: name: string * value: string * returnType: string -> WidgetBuilder<BindingNode>
   (+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: value: int -> WidgetBuilder<Constant>
static member Ast.Int: unit -> WidgetBuilder<Type>
Multiple items
static member Ast.EscapeHatch: node: 'T -> WidgetBuilder<'T>

--------------------
module EscapeHatch from Fabulous.AST
Multiple items
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
union case ModuleDecl.TopLevelBinding: BindingNode -> ModuleDecl
Multiple items
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
union case Option.None: Option<'T>
Multiple items
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
Multiple items
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
Multiple items
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 ...
property Range.Zero: range with get
union case Choice.Choice1Of2: 'T1 -> Choice<'T1,'T2>
Multiple items
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
type IdentifierOrDot = | Ident of SingleTextNode | KnownDot of SingleTextNode | UnknownDot member Equals: IdentifierOrDot * IEqualityComparer -> bool member Range: range option
union case IdentifierOrDot.Ident: SingleTextNode -> IdentifierOrDot
Multiple items
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 ...
property List.Empty: 'T list with get
Multiple items
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
union case Expr.Constant: Constant -> Expr
Multiple items
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
union case Constant.FromText: SingleTextNode -> Constant
val run: oak: Oak -> string

Type something to start searching.