You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// Find dependencies for all files (can be in parallel)
218
+
// Find dependencies for all files
219
219
letgraph=
220
220
nodes
221
221
|> Array.Parallel.map (fun node ->
222
-
match node.ContainsModuleAbbreviations with
223
-
|true-> node.Idx, allIndices
224
-
|false->
225
-
lettrie= cloneTrie trie
226
-
227
-
// Keep a list of visited nodes (ie. all reachable nodes and all their ancestors)
228
-
letvisited= emptyList<TrieNode>()
229
-
230
-
letmarkVisited(node :TrieNode)=
231
-
ifnot node.Reachable then
232
-
node.Reachable <-true
233
-
visited.Add(node)
234
-
235
-
// Keep a list of reachable nodes (ie. ones that can be prefixes for later module/type references)
236
-
letreachable= emptyList<TrieNode>()
237
-
238
-
letmarkReachable(node :TrieNode)=
239
-
ifnot node.PotentialPrefix then
240
-
node.PotentialPrefix <-true
241
-
reachable.Add(node)
242
-
markVisited node
243
-
244
-
// Mark root (no prefix) as reachable and visited
245
-
markReachable trie
246
-
247
-
let recextend(id :LongIdent)(node :TrieNode)=
248
-
let recextend(node :TrieNode)(id :LongIdent)=
249
-
match id with
250
-
// Reached end of the identifier - new reachable node
251
-
|[]->
252
-
Some node
253
-
// More segments exist
254
-
| segment :: rest ->
255
-
// Visit (not 'reach') the TrieNode
256
-
markVisited node
257
-
match node.Children.TryGetValue(segment.idText)with
258
-
// A child for the segment exists - continue there
259
-
|true, child ->
260
-
extend child rest
261
-
// A child for the segment doesn't exist - stop, since we don't care about the non-existent part of the Trie
262
-
|false,_->
263
-
None
264
-
extend node id
265
-
266
-
// Process module refs in order, marking more and more TrieNodes as reachable
267
-
letprocessRef(id :LongIdent)=
268
-
letnewReachables=
269
-
// Start at every reachable node,
270
-
reachable
271
-
// extend a reachable node by 'id', but without creating new nodes, mark all seen nodes as visited and the final one as reachable
272
-
|> Seq.choose (extend id)
273
-
|> Seq.toArray
274
-
newReachables
275
-
|> Array.iter markReachable
276
-
277
-
// Add top-level module/namespaces as the first reference (possibly not necessary as maybe already in the list)
278
-
// TODO When multiple top-level namespaces exist, we should check that it's OK to add all of them at the start (out of order).
279
-
// Later on we might want to preserve the order by returning the top-level namespaces during AST visiting
280
-
letmoduleRefs=
281
-
Array.append node.Tops node.ModuleRefs
282
-
283
-
// Process all refs
284
-
moduleRefs
285
-
|> Array.iter processRef
286
-
287
-
// Collect files from all visited TrieNodes
288
-
letreachableItems=
289
-
visited
290
-
|> Seq.collect (fun node -> node.GraphNodes)
291
-
|> Seq.toArray
292
-
293
-
// Return the node and its dependencies
294
222
letdeps=
295
-
reachableItems
223
+
// Assume that a file with module abbreviations can depend on anything
224
+
match node.ContainsModuleAbbreviations with
225
+
|true-> allIndices
226
+
|false->
227
+
// Clone the original Trie as we're going to mutate the copy
228
+
lettrie= cloneTrie trie
229
+
230
+
// Keep a list of reachable nodes (ie. potential prefixes and their ancestors)
231
+
letreachable= emptyList<TrieNode>()
232
+
letmarkReachable(node :TrieNode)=
233
+
ifnot node.Reachable then
234
+
node.Reachable <-true
235
+
reachable.Add(node)
236
+
237
+
// Keep a list of potential prefixes
238
+
letpotentialPrefixes= emptyList<TrieNode>()
239
+
letmarkPotentialPrefix(node :TrieNode)=
240
+
ifnot node.PotentialPrefix then
241
+
node.PotentialPrefix <-true
242
+
potentialPrefixes.Add(node)
243
+
// Every potential prefix is reachable
244
+
markReachable node
245
+
246
+
// Mark root (empty prefix) as a potential prefix
247
+
markPotentialPrefix trie
248
+
249
+
/// <summary>
250
+
/// Walk down from 'node' using 'id' as the path.
251
+
/// Mark all visited nodes as reachable, and the final node as a potential prefix.
252
+
/// Short-circuit when a leaf is reached.
253
+
/// </summary>
254
+
/// <remarks>
255
+
/// When the path leads outside the Trie, the Trie is not extended and no node is marked as a potential prefix.
256
+
/// This is just a performance optimisation - all the files are linked to already existing nodes, so there is no need to create and visit deeper nodes.
257
+
/// </remarks>
258
+
let recwalkDownAndMark(id :LongIdent)(node :TrieNode)=
259
+
match id with
260
+
// Reached end of the identifier - new reachable node
261
+
|[]->
262
+
markPotentialPrefix node
263
+
// More segments exist
264
+
| segment :: rest ->
265
+
// Visit (not 'reach') the TrieNode
266
+
markReachable node
267
+
match node.Children.TryGetValue(segment.idText)with
268
+
// A child for the segment exists - continue there
269
+
|true, child ->
270
+
walkDownAndMark rest child
271
+
// A child for the segment doesn't exist - stop, since we don't care about the non-existent part of the Trie
272
+
|false,_->
273
+
()
274
+
275
+
letprocessRef(id :LongIdent)=
276
+
// Start at every potential prefix,
277
+
List<_>(potentialPrefixes)// Copy the list for iteration as the original is going to be extended.
278
+
// Extend potential prefixes with this 'id'
279
+
|> Seq.iter (walkDownAndMark id)
280
+
281
+
// Add top-level module/namespaces as the first reference (possibly not necessary as maybe already in the list)
282
+
// TODO When multiple top-level namespaces exist, we should check that it's OK to add all of them at the start (out of order).
283
+
// Later on we might want to preserve the order by returning the top-level namespaces interleaved with module refs
284
+
letmoduleRefs=
285
+
Array.append node.Tops node.ModuleRefs
286
+
287
+
// Process module refs in order, marking more and more TrieNodes as reachable and potential prefixes
288
+
moduleRefs
289
+
|> Array.iter processRef
290
+
291
+
// Collect files from all reachable TrieNodes
292
+
letdeps=
293
+
reachable
294
+
|> Seq.collect (fun node -> node.GraphNodes)
295
+
|> Seq.map (fun n -> n.Idx)
296
+
// Assume that this file depends on all files that have any module abbreviations
297
+
// TODO Handle module abbreviations in a better way
298
+
|> Seq.append filesWithModuleAbbreviations
299
+
|> Seq.toArray
300
+
301
+
deps
296
302
// We know a file can't depend on a file further down in the project definition (or on itself)
0 commit comments