Skip to content

Commit caee542

Browse files
committed
WIP
1 parent 7bc03cc commit caee542

File tree

1 file changed

+84
-18
lines changed

1 file changed

+84
-18
lines changed

tests/FSharp.Compiler.Service.Tests2/DepResolving.fs

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module FSharp.Compiler.Service.Tests.DepResolving
22

3+
open System.Collections.Generic
34
open FSharp.Compiler.Service.Tests2.SyntaxTreeTests.TypeTests
45
open FSharp.Compiler.Syntax
56
open NUnit.Framework
@@ -18,7 +19,7 @@ type Node =
1819
}
1920

2021
/// Filenames with dependencies
21-
type Graph = (Node * List<Node>)[]
22+
type Graph = (Node * Node[])[]
2223

2324
let extractModuleSegments (stuff : Stuff) : LongIdent[] =
2425
stuff
@@ -29,7 +30,7 @@ let extractModuleSegments (stuff : Stuff) : LongIdent[] =
2930
match x.Ident.Length with
3031
| 0
3132
| 1 -> None
32-
| n -> x.Ident.GetSlice(Some 0, n - 1 |> Some) |> Some
33+
| n -> x.Ident.GetSlice(Some 0, n - 2 |> Some) |> Some
3334
)
3435
|> Seq.toArray
3536

@@ -41,6 +42,7 @@ type TrieNode =
4142
// TODO Use ValueTuples if not already
4243
Children : System.Collections.Generic.IDictionary<ModuleSegment, TrieNode>
4344
mutable Reachable : bool
45+
mutable Visited : bool
4446
/// Files/graph nodes represented by this TrieNode
4547
/// All files whose top-level module/namespace are same as this TrieNode's 'path'
4648
GraphNodes : System.Collections.Generic.List<Node>
@@ -49,13 +51,29 @@ type TrieNode =
4951
let emptyList<'a> () =
5052
System.Collections.Generic.List<'a>()
5153

52-
let cloneTrie (trie : TrieNode) : TrieNode =
53-
failwith unsupported // TODO
54+
let rec cloneTrie (trie : TrieNode) : TrieNode =
55+
let children =
56+
// TODO Perf
57+
let children =
58+
trie.Children
59+
|> Seq.map (fun (KeyValue(segment, child)) ->
60+
segment, cloneTrie child
61+
)
62+
|> dict
63+
// TODO Avoid tow dicts
64+
System.Collections.Generic.Dictionary<_,_>(children)
65+
{
66+
GraphNodes = List<_>(trie.GraphNodes)
67+
Children = children
68+
Reachable = trie.Reachable
69+
Visited = trie.Visited
70+
}
5471

5572
let emptyTrie () : TrieNode =
5673
{
57-
TrieNode.Children = dict([])
74+
TrieNode.Children = Dictionary([])
5875
Reachable = false
76+
Visited = false
5977
GraphNodes = emptyList()
6078
}
6179

@@ -91,8 +109,16 @@ let buildTrie (nodes : Node[]) : TrieNode =
91109

92110
root
93111

94-
let search (trie : TrieNode) (path : LongIdent) =
95-
trie
112+
let rec search (trie : TrieNode) (path : LongIdent) : TrieNode option =
113+
let mutable node = trie
114+
match path with
115+
| [] -> Some trie
116+
| segment :: rest ->
117+
match trie.Children.TryGetValue(segment.idText) with
118+
| true, child ->
119+
search child rest
120+
| false, _ ->
121+
None
96122

97123
let algorithm (nodes : FileAST list) : Graph =
98124
// Create ASTs, extract module refs
@@ -118,7 +144,16 @@ let algorithm (nodes : FileAST list) : Graph =
118144
|> Array.map (fun node ->
119145
let trie = cloneTrie trie
120146

121-
// Keep a list of reachable nodes
147+
// Keep a list of visited nodes (ie. all reachable nodes and all their ancestors)
148+
let visited = emptyList<TrieNode>()
149+
150+
let markVisited (node : TrieNode) =
151+
if not node.Visited then
152+
printfn $"New node visited"
153+
node.Visited <- true
154+
visited.Add(node)
155+
156+
// Keep a list of reachable nodes (ie. ones that can be prefixes for later module/type references)
122157
let reachable = emptyList<TrieNode>()
123158

124159
let markReachable (node : TrieNode) =
@@ -127,24 +162,55 @@ let algorithm (nodes : FileAST list) : Graph =
127162
node.Reachable <- true
128163
reachable.Add(node)
129164

130-
// Mark two nodes as reachable:
131-
// - root (no prefix)
132-
// - top-level module/namespace
165+
// Mark root (no prefix) as reachable and visited
133166
markReachable trie
134-
let topNode = search trie node.Top
135-
markReachable topNode
167+
markVisited trie
168+
169+
let rec extend (id : LongIdent) (node : TrieNode) =
170+
let rec extend (node : TrieNode) (id : LongIdent) =
171+
match id with
172+
// Reached end of the identifier - new reachable node
173+
| [] ->
174+
Some node
175+
// More segments exist
176+
| segment :: rest ->
177+
// Visit (not 'reach') the TrieNode
178+
markVisited node
179+
match node.Children.TryGetValue(segment.idText) with
180+
// A child for the segment exists - continue there
181+
| true, child ->
182+
extend child rest
183+
// A child for the segment doesn't exist - stop, since we don't care about the non-existent part of the Trie
184+
| false, _ ->
185+
None
186+
extend node id
136187

137188
// Process module refs in order, marking more and more TrieNodes as reachable
138189
let processRef (id : LongIdent) =
139-
()
140-
node.ModuleRefs
190+
let newReachables =
191+
// Start at every reachable node,
192+
reachable
193+
// extend a reachable node by 'id', but without creating new nodes, mark all seen nodes as visited and the final one as reachable
194+
|> Seq.choose (extend id)
195+
|> Seq.toArray
196+
reachable.AddRange(newReachables)
197+
198+
// Add top-level module/namespace as the first reference (possibly not necessary as maybe already in the list)
199+
let moduleRefs =
200+
Array.append [|node.Top|] node.ModuleRefs
201+
202+
// Process all refs
203+
moduleRefs
141204
|> Array.iter processRef
142205

143-
// Collect files from all reachable TrieNodes
206+
// Collect files from all visited TrieNodes
144207
let reachableItems =
145-
reachable
208+
visited
146209
|> Seq.collect (fun node -> node.GraphNodes)
147-
node, List<Node>(reachableItems)
210+
|> Seq.toArray
211+
212+
// Return the node and its dependencies
213+
node, reachableItems
148214
)
149215

150216
[<Test>]

0 commit comments

Comments
 (0)