47
loading...
This website collects cookies to deliver better user experience
using System.Collections;
using System.Linq;
using System.Text;
namespace FunWithSyntaxTrees
{
class Program
{
static void Main(string[] args)
{
// ...
}
}
}
Microsoft.CodeAnalysis.CSharp
and importing that into your project.open Microsoft.CodeAnalysis
open Microsoft.CodeAnalysis.CSharp
open Microsoft.CodeAnalysis.CSharp.Syntax
module Main =
[<EntryPoint>]
let main argv =
0
open
directives, we will hardcode the C# source code from above into the file, above the main
entrypoint function.// ... open directives
let code = """
using System.Collections;
using System.Linq;
using System.Text;
namespace FunWithSyntaxTrees
{
class Program
{
static void Main(string[] args)
{
// ...
}
}
}
"""
module Main =
[<EntryPoint>]
let main argv =
0
let code = File.ReadAllText "/path/to/file"
, instead of hardcoding the string like we did, but for this tutorial it is fine for demonstration.[<EntryPoint>]
let main argv =
let syntaxTree: SyntaxTree = CSharpSyntaxTree.ParseText code
0
Note: I will write out the Type
's of all the variables, but it is unnecessary most of the time since F#'s type inference is very capable of inferring the type itself. Just like in C# when you use the var
keyword, it is capable of knowing the underlying type, in F# this inference is even more powerful and applies to arguments, functions and everything in-between.
using
directives in the file. We start by getting the root node of the file, then we iterate over all the child nodes inside the root node and find the ones that are the correct UsingDirective
type.[<EntryPoint>]
let main argv =
let syntaxTree: SyntaxTree = CSharpSyntaxTree.ParseText code
let rootNode: CompilationUnitSyntax = syntaxTree.GetCompilationUnitRoot()
let rootNodeChildren: SyntaxNode seq = rootNode.ChildNodes()
0
rootNodeChildren
variable holds all the child SyntaxNode
's of the root node. The root node is basically the first node of the SyntaxTree
which holds everything, and a SyntaxNode
is the most general type of node.SyntaxNode
for using
directives since that is what we are looking for. We will declare a small helper function to help find them.let usingDirectiveNode (node: SyntaxNode): UsingDirectiveSyntax option =
match node with
| :? UsingDirectiveSyntax as usingDirective -> Some usingDirective
| _ -> None
[<EntryPoint>]
let main argv =
let syntaxTree: SyntaxTree = CSharpSyntaxTree.ParseText code
let rootNode: CompilationUnitSyntax = syntaxTree.GetCompilationUnitRoot()
let rootNodeChildren: SyntaxNode seq = rootNode.ChildNodes()
let usingDirectives: UsingDirectiveSyntax seq =
Seq.choose usingDirectiveNode rootNodeChildren
0
usingDirectiveNode
takes a generic SyntaxNode
and checks if it is of the UsingDirectiveSyntax
variety, if it is, it returns an F# Option type containing the using
directive node.Note: An F# Option type is a way to represent a "nullable" value, since there are no real null values in F#, nullable values are representated as Algebraic Data Types, such as the Option type.
Seq.choose
to filter out any None
types and keep all the Some
types. It also unwraps the Some
types so we can keep using them without Option mapping.Seq.choose
is just a fancy way of doing Seq.map
and then Seq.filter
specifically with Option types since the type signature is ('T -> 'U option) -> seq<'T> -> seq<'U>
.using
directives in a variable, we can get the specific properties of a using
directive. For now we wil just print them out as proof.let usingDirectiveNode (node: SyntaxNode): UsingDirectiveSyntax option =
match node with
| :? UsingDirectiveSyntax as usingDirective -> Some usingDirective
| _ -> None
[<EntryPoint>]
let main argv =
let syntaxTree: SyntaxTree = CSharpSyntaxTree.ParseText code
let rootNode: CompilationUnitSyntax = syntaxTree.GetCompilationUnitRoot()
let rootNodeChildren: SyntaxNode seq = rootNode.ChildNodes()
let usingDirectives: UsingDirectiveSyntax seq =
Seq.choose usingDirectiveNode rootNodeChildren
usingDirectives
|> List.ofSeq
|> List.map (fun u -> printfn $"{u.ToString()}")
|> ignore
0
using System.Collections;
using System.Linq;
using System.Text;