Skip to content

Add VisitValSig to SyntaxVisitorBase. #15930

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 136 additions & 1 deletion src/Compiler/Service/ServiceParseTreeWalk.fs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ type SyntaxNode =
| SynMemberDefn of SynMemberDefn
| SynMatchClause of SynMatchClause
| SynBinding of SynBinding
| SynModuleOrNamespaceSig of SynModuleOrNamespaceSig
| SynModuleSigDecl of SynModuleSigDecl
| SynValSig of SynValSig
| SynTypeDefnSig of SynTypeDefnSig
| SynMemberSig of SynMemberSig

type SyntaxVisitorPath = SyntaxNode list

Expand Down Expand Up @@ -184,6 +189,28 @@ type SyntaxVisitorBase<'T>() =
ignore (path, attributes)
None

/// VisitModuleOrNamespaceSig allows overriding behavior when visiting module or namespaces
abstract VisitModuleOrNamespaceSig: path: SyntaxVisitorPath * synModuleOrNamespaceSig: SynModuleOrNamespaceSig -> 'T option

default _.VisitModuleOrNamespaceSig(path, synModuleOrNamespaceSig) =
ignore (path, synModuleOrNamespaceSig)
None

/// VisitModuleDecl allows overriding signature module declaration behavior
abstract VisitModuleSigDecl:
path: SyntaxVisitorPath * defaultTraverse: (SynModuleSigDecl -> 'T option) * synModuleSigDecl: SynModuleSigDecl -> 'T option

default _.VisitModuleSigDecl(path, defaultTraverse, synModuleSigDecl) =
ignore path
defaultTraverse synModuleSigDecl

/// VisitValSig allows overriding SynValSig behavior
abstract VisitValSig: path: SyntaxVisitorPath * defaultTraverse: (SynValSig -> 'T option) * valSig: SynValSig -> 'T option

default _.VisitValSig(path, defaultTraverse, valSig) =
ignore path
defaultTraverse valSig

/// A range of utility functions to assist with traversing an AST
module SyntaxTraversal =
// treat ranges as though they are half-open: [,)
Expand Down Expand Up @@ -926,6 +953,101 @@ module SyntaxTraversal =
attributes
|> List.map (fun attributes -> dive () attributes.Range (fun () -> visitor.VisitAttributeApplication(origPath, attributes)))

and traverseSynModuleOrNamespaceSig origPath (SynModuleOrNamespaceSig (decls = synModuleSigDecls; range = range) as mors) =
match visitor.VisitModuleOrNamespaceSig(origPath, mors) with
| Some x -> Some x
| None ->
let path = SyntaxNode.SynModuleOrNamespaceSig mors :: origPath

synModuleSigDecls
|> List.map (fun x -> dive x x.Range (traverseSynModuleSigDecl path))
|> pick range mors

and traverseSynModuleSigDecl origPath (decl: SynModuleSigDecl) =
let pick = pick decl.Range

let defaultTraverse m =
let path = SyntaxNode.SynModuleSigDecl m :: origPath

match m with
| SynModuleSigDecl.ModuleAbbrev (_ident, _longIdent, _range) -> None
| SynModuleSigDecl.NestedModule (moduleDecls = synModuleDecls; moduleInfo = SynComponentInfo (attributes = attributes)) ->
synModuleDecls
|> List.map (fun x -> dive x x.Range (traverseSynModuleSigDecl path))
|> List.append (attributeApplicationDives path attributes)
|> pick decl
| SynModuleSigDecl.Val (synValSig, range) -> [ dive synValSig range (traverseSynValSig path) ] |> pick decl
| SynModuleSigDecl.Types (types = types; range = range) ->
types
|> List.map (fun t -> dive t range (traverseSynTypeDefnSig path))
|> pick decl
| SynModuleSigDecl.Exception (_synExceptionDefn, _range) -> None
| SynModuleSigDecl.Open (_target, _range) -> None
| SynModuleSigDecl.HashDirective (parsedHashDirective, range) ->
visitor.VisitHashDirective(path, parsedHashDirective, range)
| SynModuleSigDecl.NamespaceFragment synModuleOrNamespaceSig -> traverseSynModuleOrNamespaceSig path synModuleOrNamespaceSig

visitor.VisitModuleSigDecl(origPath, defaultTraverse, decl)

and traverseSynValSig origPath (valSig: SynValSig) =
let defaultTraverse (SynValSig (synType = t; attributes = attributes; synExpr = expr; range = m)) =
let path = SyntaxNode.SynValSig valSig :: origPath

[
yield! attributeApplicationDives path attributes
yield dive t t.Range (traverseSynType path)
match expr with
| Some expr -> yield dive expr expr.Range (traverseSynExpr path)
| None -> ()
]
|> pick m valSig

visitor.VisitValSig(origPath, defaultTraverse, valSig)

and traverseSynTypeDefnSig origPath (SynTypeDefnSig (synComponentInfo, typeRepr, members, tRange, _) as tydef) =
let path = SyntaxNode.SynTypeDefnSig tydef :: origPath

match visitor.VisitComponentInfo(origPath, synComponentInfo) with
| Some x -> Some x
| None ->
match synComponentInfo with
| SynComponentInfo (attributes = attributes) ->
[
yield! attributeApplicationDives path attributes

match typeRepr with
| SynTypeDefnSigRepr.Exception _ ->
// This node is generated in CheckExpressions.fs, not in the AST.
// But note exception declarations are missing from this tree walk.
()
| SynTypeDefnSigRepr.ObjectModel (memberSigs = memberSigs) ->
yield! memberSigs |> List.map (fun ms -> dive ms ms.Range (traverseSynMemberSig path))
| SynTypeDefnSigRepr.Simple (synTypeDefnSimpleRepr, _range) ->
match synTypeDefnSimpleRepr with
| SynTypeDefnSimpleRepr.Record (_synAccessOption, fields, m) ->
yield dive () typeRepr.Range (fun () -> traverseRecordDefn path fields m)
| SynTypeDefnSimpleRepr.Union (_synAccessOption, cases, m) ->
yield dive () typeRepr.Range (fun () -> traverseUnionDefn path cases m)
| SynTypeDefnSimpleRepr.Enum (cases, m) ->
yield dive () typeRepr.Range (fun () -> traverseEnumDefn path cases m)
| SynTypeDefnSimpleRepr.TypeAbbrev (_, synType, m) ->
yield dive typeRepr typeRepr.Range (fun _ -> visitor.VisitTypeAbbrev(path, synType, m))
| _ -> ()
yield! members |> List.map (fun ms -> dive ms ms.Range (traverseSynMemberSig path))
]
|> pick tRange tydef

and traverseSynMemberSig path (m: SynMemberSig) =
let path = SyntaxNode.SynMemberSig m :: path

match m with
| SynMemberSig.Member (memberSig = memberSig) -> traverseSynValSig path memberSig
| SynMemberSig.Interface (interfaceType = synType) -> traverseSynType path synType
| SynMemberSig.Inherit (inheritedType = synType) -> traverseSynType path synType
| SynMemberSig.ValField(field = SynField (attributes = attributes)) ->
attributeApplicationDives path attributes |> pick m.Range attributes
| SynMemberSig.NestedType (nestedType = nestedType) -> traverseSynTypeDefnSig path nestedType

match parseTree with
| ParsedInput.ImplFile file ->
let l = file.Contents
Expand All @@ -941,4 +1063,17 @@ module SyntaxTraversal =
l
|> List.map (fun x -> dive x x.Range (traverseSynModuleOrNamespace []))
|> pick fileRange l
| ParsedInput.SigFile _sigFile -> None
| ParsedInput.SigFile sigFile ->
let l = sigFile.Contents

let fileRange =
#if DEBUG
match l with
| [] -> range0
| _ -> l |> List.map (fun x -> x.Range) |> List.reduce unionRanges
#else
range0 // only used for asserting, does not matter in non-debug
#endif
l
|> List.map (fun x -> dive x x.Range (traverseSynModuleOrNamespaceSig []))
|> pick fileRange l
23 changes: 23 additions & 0 deletions src/Compiler/Service/ServiceParseTreeWalk.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ type SyntaxNode =
| SynMemberDefn of SynMemberDefn
| SynMatchClause of SynMatchClause
| SynBinding of SynBinding
| SynModuleOrNamespaceSig of SynModuleOrNamespaceSig
| SynModuleSigDecl of SynModuleSigDecl
| SynValSig of SynValSig
| SynTypeDefnSig of SynTypeDefnSig
| SynMemberSig of SynMemberSig

type SyntaxVisitorPath = SyntaxNode list

Expand Down Expand Up @@ -151,6 +156,24 @@ type SyntaxVisitorBase<'T> =
abstract VisitAttributeApplication: path: SyntaxVisitorPath * attributes: SynAttributeList -> 'T option
default VisitAttributeApplication: path: SyntaxVisitorPath * attributes: SynAttributeList -> 'T option

abstract VisitModuleOrNamespaceSig:
path: SyntaxVisitorPath * synModuleOrNamespaceSig: SynModuleOrNamespaceSig -> 'T option
default VisitModuleOrNamespaceSig:
path: SyntaxVisitorPath * synModuleOrNamespaceSig: SynModuleOrNamespaceSig -> 'T option

abstract VisitModuleSigDecl:
path: SyntaxVisitorPath * defaultTraverse: (SynModuleSigDecl -> 'T option) * synModuleSigDecl: SynModuleSigDecl ->
'T option
default VisitModuleSigDecl:
path: SyntaxVisitorPath * defaultTraverse: (SynModuleSigDecl -> 'T option) * synModuleSigDecl: SynModuleSigDecl ->
'T option

abstract VisitValSig:
path: SyntaxVisitorPath * defaultTraverse: (SynValSig -> 'T option) * valSig: SynValSig -> 'T option

default VisitValSig:
path: SyntaxVisitorPath * defaultTraverse: (SynValSig -> 'T option) * valSig: SynValSig -> 'T option

module public SyntaxTraversal =

val internal rangeContainsPosLeftEdgeInclusive: m1: range -> p: pos -> bool
Expand Down
Loading