Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
safesparrow committed Oct 16, 2022
1 parent 8229cf6 commit 7bc03cc
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 42 deletions.
40 changes: 40 additions & 0 deletions tests/FSharp.Compiler.Service.Tests2/Big.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module FSharp.Compiler.Service.Tests.Big

module A1 = let a = 3
module A2 = let a = 3
module A3 = let a = 3
module A4 =

type AAttribute(name : string) =
inherit System.Attribute()

let a = 3
module A1 =
let a = 3
type X = int * int
type Y = Y of int

module B =
open A2
let b = [|
A1.a
A2.a
A3.a
|]
let c : A4.X = 2,2
[<A4.A("name")>]
let d : A4.Y = A4.Y 2
type Z =
{
X : A4.X
Y : A4.Y
}

let c = A4.a
let d = A4.A1.a
open A4
let e = A1.a
open A1
let f = a

//module X = B
175 changes: 175 additions & 0 deletions tests/FSharp.Compiler.Service.Tests2/DepResolving.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
module FSharp.Compiler.Service.Tests.DepResolving

open FSharp.Compiler.Service.Tests2.SyntaxTreeTests.TypeTests
open FSharp.Compiler.Syntax
open NUnit.Framework

/// File * AST
type FileAST = string * ParsedInput

type List<'a> = System.Collections.Generic.List<'a>

type Node =
{
Name : string
AST : ParsedInput
Top : LongIdent
ModuleRefs : LongIdent[]
}

/// Filenames with dependencies
type Graph = (Node * List<Node>)[]

let extractModuleSegments (stuff : Stuff) : LongIdent[] =
stuff
|> Seq.choose (fun x ->
match x.Kind with
| ModuleOrNamespace -> x.Ident |> Some
| Type ->
match x.Ident.Length with
| 0
| 1 -> None
| n -> x.Ident.GetSlice(Some 0, n - 1 |> Some) |> Some
)
|> Seq.toArray

type ModuleSegment = string

type TrieNode =
{
// parent?
// TODO Use ValueTuples if not already
Children : System.Collections.Generic.IDictionary<ModuleSegment, TrieNode>
mutable Reachable : bool
/// Files/graph nodes represented by this TrieNode
/// All files whose top-level module/namespace are same as this TrieNode's 'path'
GraphNodes : System.Collections.Generic.List<Node>
}

let emptyList<'a> () =
System.Collections.Generic.List<'a>()

let cloneTrie (trie : TrieNode) : TrieNode =
failwith unsupported // TODO

let emptyTrie () : TrieNode =
{
TrieNode.Children = dict([])
Reachable = false
GraphNodes = emptyList()
}

/// Build initial Trie from files
let buildTrie (nodes : Node[]) : TrieNode =
let root = emptyTrie()

// Add every file
let addItem (node : Node) =
let ident = node.Top

let mutable trieNode = root
// Go through module segments, possibly extending the Trie with new nodes
for segment in ident do
let child =
match trieNode.Children.TryGetValue segment.idText with
// Child exists
| true, child ->
child
// Child doesn't exist
| false, _ ->
let child = emptyTrie()
trieNode.Children[segment.idText] <- child
child
trieNode <- child

// Add the node to the found leaf's list
trieNode.GraphNodes.Add(node)

// Add all files to the Trie
nodes
|> Array.iter addItem

root

let search (trie : TrieNode) (path : LongIdent) =
trie

let algorithm (nodes : FileAST list) : Graph =
// Create ASTs, extract module refs
let nodes =
nodes
|> List.map (fun (name, ast) ->
let typeAndModuleRefs = visit ast
let top = topModuleOrNamespace ast
let moduleRefs = extractModuleSegments typeAndModuleRefs
{
Name = name
AST = ast
Top = top
ModuleRefs = moduleRefs
}
)
|> List.toArray

let trie = buildTrie nodes

// Find dependencies for all files (can be in parallel)
nodes
|> Array.map (fun node ->
let trie = cloneTrie trie

// Keep a list of reachable nodes
let reachable = emptyList<TrieNode>()

let markReachable (node : TrieNode) =
if not node.Reachable then
printfn $"New node reachable"
node.Reachable <- true
reachable.Add(node)

// Mark two nodes as reachable:
// - root (no prefix)
// - top-level module/namespace
markReachable trie
let topNode = search trie node.Top
markReachable topNode

// Process module refs in order, marking more and more TrieNodes as reachable
let processRef (id : LongIdent) =
()
node.ModuleRefs
|> Array.iter processRef

// Collect files from all reachable TrieNodes
let reachableItems =
reachable
|> Seq.collect (fun node -> node.GraphNodes)
node, List<Node>(reachableItems)
)

[<Test>]
let Foo() =

let A =
"""
module A
open B
let x = B.x
"""
let B =
"""
module B
let x = 3
"""

let files = [
"A", A
"B", B
]
let nodes =
files
|> List.map (fun (name, code) -> name, getParseResults code)

let graph = algorithm nodes

printfn $"%+A{graph}"
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@
<Link>Common.fs</Link>
</Compile>
<Compile Include="TypeTests.fs" />
<Compile Include="Test.fs" />
<Compile Include="DepResolving.fs" />
<Compile Include="..\service\Program.fs">
<Link>Program.fs</Link>
</Compile>
<None Include="Big.fs">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 0 additions & 2 deletions tests/FSharp.Compiler.Service.Tests2/Test.fs

This file was deleted.

45 changes: 6 additions & 39 deletions tests/FSharp.Compiler.Service.Tests2/TypeTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1087,8 +1087,6 @@ let f = a
printfn $"%+A{stuff}"
()

let depends ()

[<Test>]
let ``Test two`` () =

Expand All @@ -1112,41 +1110,10 @@ let x = 3
printfn $"A refs: %+A{visitedA}"
()

module A1 = let a = 3
module A2 = let a = 3
module A3 = let a = 3
module A4 =

type AAttribute(name : string) =
inherit System.Attribute()

let a = 3
module A1 =
let a = 3
type X = int * int
type Y = Y of int

module B =
open A2
let b = [|
A1.a
A2.a
A3.a
|]
let c : A4.X = 2,2
[<A4.A("name")>]
let d : A4.Y = A4.Y 2
type Z =
{
X : A4.X
Y : A4.Y
}

let c = A4.a
let d = A4.A1.a
open A4
let e = A1.a
open A1
let f = a

module X = B
[<Test>]
let ``Test big`` () =
let code = System.IO.File.ReadAllText("Big.fs")
let parsedA = getParseResults code
let visitedA = visit parsedA
printfn $"A refs: %+A{visitedA}"

0 comments on commit 7bc03cc

Please sign in to comment.