@@ -16,10 +16,12 @@ type Node =
1616 AST : ParsedInput
1717 Top : LongIdent
1818 ModuleRefs : LongIdent []
19+ // Order of the file in the project. Files with lower number cannot depend on files with higher number
20+ Idx : int
1921 }
2022
2123/// Filenames with dependencies
22- type Graph = ( Node * Node [])[]
24+ type Graph = ( string * string [])[]
2325
2426let extractModuleSegments ( stuff : Stuff ) : LongIdent [] =
2527 stuff
@@ -40,7 +42,7 @@ type TrieNode =
4042 {
4143 // parent?
4244 // TODO Use ValueTuples if not already
43- Children : System . Collections . Generic . IDictionary < ModuleSegment , TrieNode >
45+ Children : IDictionary < ModuleSegment , TrieNode >
4446 mutable Reachable : bool
4547 mutable Visited : bool
4648 /// Files/graph nodes represented by this TrieNode
@@ -61,7 +63,7 @@ let rec cloneTrie (trie : TrieNode) : TrieNode =
6163 )
6264 |> dict
6365 // TODO Avoid tow dicts
64- System.Collections.Generic. Dictionary<_,_>( children)
66+ Dictionary<_,_>( children)
6567 {
6668 GraphNodes = List<_>( trie.GraphNodes)
6769 Children = children
@@ -109,22 +111,22 @@ let buildTrie (nodes : Node[]) : TrieNode =
109111
110112 root
111113
112- let rec search ( trie : TrieNode ) ( path : LongIdent ) : TrieNode option =
114+ let rec searchInTrie ( trie : TrieNode ) ( path : LongIdent ) : TrieNode option =
113115 let mutable node = trie
114116 match path with
115117 | [] -> Some trie
116118 | segment :: rest ->
117119 match trie.Children.TryGetValue( segment.idText) with
118120 | true , child ->
119- search child rest
121+ searchInTrie child rest
120122 | false , _ ->
121123 None
122124
123- let algorithm ( nodes : FileAST list ) : Graph =
125+ let detectFileDependencies ( nodes : FileAST list ) : Graph =
124126 // Create ASTs, extract module refs
125127 let nodes =
126128 nodes
127- |> List.map ( fun ( name , ast ) ->
129+ |> List.mapi ( fun i ( name , ast ) ->
128130 let typeAndModuleRefs = visit ast
129131 let top = topModuleOrNamespace ast
130132 let moduleRefs = extractModuleSegments typeAndModuleRefs
@@ -133,6 +135,7 @@ let algorithm (nodes : FileAST list) : Graph =
133135 AST = ast
134136 Top = top
135137 ModuleRefs = moduleRefs
138+ Idx = i
136139 }
137140 )
138141 |> List.toArray
@@ -149,7 +152,6 @@ let algorithm (nodes : FileAST list) : Graph =
149152
150153 let markVisited ( node : TrieNode ) =
151154 if not node.Visited then
152- printfn $" New node visited"
153155 node.Visited <- true
154156 visited.Add( node)
155157
@@ -158,13 +160,12 @@ let algorithm (nodes : FileAST list) : Graph =
158160
159161 let markReachable ( node : TrieNode ) =
160162 if not node.Reachable then
161- printfn $" New node reachable"
162163 node.Reachable <- true
163164 reachable.Add( node)
165+ markVisited node
164166
165167 // Mark root (no prefix) as reachable and visited
166168 markReachable trie
167- markVisited trie
168169
169170 let rec extend ( id : LongIdent ) ( node : TrieNode ) =
170171 let rec extend ( node : TrieNode ) ( id : LongIdent ) =
@@ -193,7 +194,8 @@ let algorithm (nodes : FileAST list) : Graph =
193194 // extend a reachable node by 'id', but without creating new nodes, mark all seen nodes as visited and the final one as reachable
194195 |> Seq.choose ( extend id)
195196 |> Seq.toArray
196- reachable.AddRange( newReachables)
197+ newReachables
198+ |> Array.iter markReachable
197199
198200 // Add top-level module/namespace as the first reference (possibly not necessary as maybe already in the list)
199201 let moduleRefs =
@@ -210,32 +212,79 @@ let algorithm (nodes : FileAST list) : Graph =
210212 |> Seq.toArray
211213
212214 // Return the node and its dependencies
213- node, reachableItems
215+ let deps =
216+ reachableItems
217+ // We know a file can't depend on a file further down in the project definition (or on itself)
218+ |> Seq.filter ( fun n -> n.Idx < node.Idx)
219+ |> Seq.map ( fun n -> n.Name)
220+ |> Seq.toArray
221+ node.Name, deps
214222 )
215223
216224[<Test>]
217- let Foo () =
218-
225+ let TestDepsResolver () =
226+
219227 let A =
220228 """
221229module A
222- open B
223- let x = B.x
224- """
230+ let a = 3
231+ type X = int
232+ """
225233 let B =
226234 """
227- module B
228- let x = 3
235+ namespace B
236+ let b = 3
237+ """
238+ let C =
239+ """
240+ module C.X
241+ let c = 3
242+ """
243+ let D =
244+ """
245+ module D
246+ let d : A.X = 3
247+ """
248+ let E =
249+ """
250+ module E
251+ let e = C.X.x
252+ open A
253+ let x = a
254+ """
255+ let F =
256+ """
257+ module F
258+ open C
259+ let x = X.c
260+ """
261+ let G =
262+ """
263+ namespace GH
264+ type A = int
265+ """
266+ let H =
267+ """
268+ namespace GH
269+ type B = int
229270"""
230271
231272 let files = [
232- " A" , A
233- " B" , B
273+ " A.fs" , A
274+ " B.fs" , B
275+ " C.fs" , C
276+ " D.fs" , D
277+ " E.fs" , E
278+ " F.fs" , F
279+ " G.fs" , G
280+ " H.fs" , H
234281 ]
235282 let nodes =
236283 files
237284 |> List.map ( fun ( name , code ) -> name, getParseResults code)
238285
239- let graph = algorithm nodes
240-
241- printfn $" %+A {graph}"
286+ let graph = detectFileDependencies nodes
287+
288+ printfn " Detected file dependencies:"
289+ graph
290+ |> Array.iter ( fun ( file , deps ) -> printfn $" {file} -> %+A {deps}" )
0 commit comments