Hey, some additional pointers for the AST traversal.
Sometimes there is duplicate information inside the syntax tree:
When a return type is present inside a SynBinding, this body expression will be wrapped inside a SynExpr.Typed. The type inside SynExpr.Typed will be the same that is present in SynBindingReturnInfo.
You can ignore one of the types. Although, be aware that a SynExpr.Typed could also be used as the body of a SynBinding when there is no return type.
SynValData can be skipped in your algorithm, the same information will be present in SynType.
SynExpr.Lambda contains an optimized version of the arguments and body inside parsedData, you can use that instead of looking into the nested SynExpr.Lambda.
For infix operators (SynExpr.App(_, true, ...)(example), you can safely assume the operator will be SynExpr.LongIdent. No need to traverse it, of course in practice that won't make much difference.
On some levels, you could easily collect the information in parallel (using PLinq or something else):
SynModuleDecl
SynModuleDeclSig
SynMemberDefn
SynMemberDefnSig
The bindings inside a recursive let SynModuleDecl.Let
Recursive types inside SynModuleDecl.Types
SynMatchClause
SynUnionCase
visitMulti could become something along the lines of
open System.Linq
let visitMulti (f: 't -> 'i seq) (items: 't seq) : 'i seq =
items.AsParallel().SelectMany(f)
Hey, some additional pointers for the AST traversal.
Sometimes there is duplicate information inside the syntax tree:
SynExpr.Typed
. The type insideSynExpr.Typed
will be the same that is present inSynBindingReturnInfo
. You can ignore one of the types. Although, be aware that aSynExpr.Typed
could also be used as the body of aSynBinding
when there is no return type.SynValData
can be skipped in your algorithm, the same information will be present inSynType
.parsedData
, you can use that instead of looking into the nested SynExpr.Lambda.SynExpr.App(_, true, ...)
(example), you can safely assume the operator will beSynExpr.LongIdent
. No need to traverse it, of course in practice that won't make much difference.On some levels, you could easily collect the information in parallel (using PLinq or something else):
SynModuleDecl.Let
SynModuleDecl.Types
visitMulti
could become something along the lines ofI hope that helps.
Cheers!