DEV Community

jkone27
jkone27

Posted on

Learning some Fantomas AST

Made a test encoder/decored for a simple namespace declaration with Fantomas OAK Ast, see fantomas tools page

given

Oak (1,0-1,15)
        ModuleOrNamespaceNode (1,0-1,15)
            ModuleOrNamespaceHeaderNode (1,0-1,15)
                MultipleTextsNode (1,0-1,9)
                    namespace (1,0-1,9)
                IdentListNode (1,10-1,15)
                    A (1,10-1,11)
                    B (1,12-1,13)
                    C (1,14-1,15)
Enter fullscreen mode Exit fullscreen mode

it will output A.B.C (lowered)

you can run it as dotnet fsi script.fsx or in vscode with dotnet sdk installed. cheers!

let oakAst = 
    "hello.one.two"
    |> FantomasWriter.makeNamespace  []

oakAst 
|> FantomasReader.extractNsFromOak 
|> Option.iter (printfn "NAMESPACE: %s")
Enter fullscreen mode Exit fullscreen mode

Fabulous.AST

if you want to make your life easier and drop the custom write part for Oak, you can make use of the awesome Fabulous.AST DSL nuget package

#r "nuget:Fabulous.AST"

open System
open Fabulous.AST
open type Fabulous.AST.Ast

// using Fabulous.AST life becomes easier for writing oak
let oakAst = 
    Ast.Oak(){
        Ast.Namespace("hello.one.two") {}
    }
    |> Gen.mkOak

Enter fullscreen mode Exit fullscreen mode

Here a Gist of It

#r "nuget:Fantomas.Core"
open Fantomas.Core
open Fantomas.Core.SyntaxOak
open Fantomas.FCS.Text
open System
(** `namespace A.B.C` : https://fsprojects.github.io/fantomas-tools
Oak (1,0-1,15)
ModuleOrNamespaceNode (1,0-1,15)
ModuleOrNamespaceHeaderNode (1,0-1,15)
MultipleTextsNode (1,0-1,9)
namespace (1,0-1,9)
IdentListNode (1,10-1,15)
A (1,10-1,11)
B (1,12-1,13)
C (1,14-1,15)
*)
module FantomasWriter =
let text v = SingleTextNode(v, Range.Zero)
let toMultipleTexts lst = MultipleTextsNode(lst |> Seq.map text |> Seq.toList ,Range.Zero)
let toIdentList (lst: string seq) =
let ll =
lst
|> Seq.map (fun l ->
let content = l |> text
if l = "." then
content |> IdentifierOrDot.KnownDot
else
content |> IdentifierOrDot.Ident
)
|> Seq.toList
if ll.Length > 0 then
IdentListNode(ll, Range.Zero) |> Some
else
None
let makeModuleOrNamespaceHeaderNode (nameSpaceString: string) =
let ns = nameSpaceString.ToLower().Trim().Split([|'.'|])
if ns.Length > 0 then
ModuleOrNamespaceHeaderNode(
None,
None,
[ "namespace" ] |> toMultipleTexts,
None,
false,
ns |> toIdentList,
Range.Zero) |> Some
else
None
let makeNamespace (nameSpaceString: string) decls =
let nsOpt = makeModuleOrNamespaceHeaderNode nameSpaceString
Oak([],
[
ModuleOrNamespaceNode(nsOpt, decls, Range.Zero)
], Range.Zero)
module FantomasReader =
let extractNs (iln: IdentListNode) =
iln.Content
|> List.collect (fun iod ->
match iod with
| IdentifierOrDot.Ident(stn) -> [ stn.Text ]
| _ -> []
)
|> fun l ->
if l.Length > 0 then
String.Join('.',l) |> Some
else
None
// Define a function to extract the namespace from an Oak AST
let extractNsFromOak (oak: Oak) =
oak.ModulesOrNamespaces.Head.Header
|> Option.bind (
fun header ->
match header.LeadingKeyword.Content with
| [x] when x.Text = "namespace" ->
header.Name
|> Option.bind extractNs
| _ -> None
)
// Example usage
let oakAst = FantomasWriter.makeNamespace "hello.one.two" []
oakAst
|> FantomasReader.extractNsFromOak
|> Option.iter (printfn "NAMESPACE: %s")

Reinvent your career. Join DEV.

It takes one minute and is worth it for your career.

Get started

Top comments (0)

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay