Skip to content

Commit

Permalink
Only process modules that are reachable from exposed ones (#40)
Browse files Browse the repository at this point in the history
* Added missing module declarations. #37

* Process only those modules that are reachable from exposed ones. Remove package path from module names. #21
  • Loading branch information
AttilaMihaly authored Mar 27, 2020
1 parent 1522465 commit 8490534
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 29 deletions.
6 changes: 3 additions & 3 deletions morphir.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "morphir",
"name": "Morphir",
"sourceDirectory": "src",
"exposedModules": [
"Morphir.IR.Name",
"Morphir.IR.Path"
"IR.Advanced.Type",
"IR.Advanced.Value"
]
}
70 changes: 58 additions & 12 deletions src/Morphir/Elm/Frontend.elm
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import Elm.Syntax.Node as Node exposing (Node(..))
import Elm.Syntax.TypeAnnotation exposing (TypeAnnotation(..))
import Json.Decode as Decode
import Json.Encode as Encode
import Morphir.DAG as DAG exposing (DAG)
import Morphir.Elm.Frontend.Resolve as Resolve exposing (ModuleResolver, PackageResolver)
import Morphir.IR.AccessControlled as AccessControlled exposing (AccessControlled, private, public)
import Morphir.Graph as Graph exposing (Graph)
import Morphir.IR.AccessControlled exposing (AccessControlled, private, public)
import Morphir.IR.Advanced.Module as Module
import Morphir.IR.Advanced.Package as Package
import Morphir.IR.Advanced.Type as Type exposing (Type)
Expand Down Expand Up @@ -124,7 +124,7 @@ type alias Errors =

type Error
= ParseError String (List Parser.DeadEnd)
| CyclicModules (DAG (List String))
| CyclicModules (Graph (List String))
| ResolveError SourceLocation Resolve.Error


Expand Down Expand Up @@ -180,6 +180,41 @@ packageDefinitionFromSource packageInfo sourceFiles =
)
|> ResultList.toResult

exposedModuleNames : Set ModuleName
exposedModuleNames =
packageInfo.exposedModules
|> Set.map
(\modulePath ->
(packageInfo.name |> Path.toList)
++ (modulePath |> Path.toList)
|> List.map Name.toTitleCase
)

treeShakeModules : List ( ModuleName, ParsedFile ) -> List ( ModuleName, ParsedFile )
treeShakeModules allModules =
let
allUsedModules : Set ModuleName
allUsedModules =
allModules
|> List.map
(\( moduleName, parsedFile ) ->
( moduleName
, parsedFile.rawFile
|> RawFile.imports
|> List.map (.moduleName >> Node.value)
|> Set.fromList
)
)
|> Dict.fromList
|> Graph.fromDict
|> Graph.reachableNodes exposedModuleNames
in
allModules
|> List.filter
(\( moduleName, _ ) ->
allUsedModules |> Set.member moduleName
)

sortModules : List ( ModuleName, ParsedFile ) -> Result Errors (List ModuleName)
sortModules modules =
let
Expand All @@ -195,10 +230,10 @@ packageDefinitionFromSource packageInfo sourceFiles =
)
)
|> Dict.fromList
|> DAG.fromDict
|> DAG.topologicalSort
|> Graph.fromDict
|> Graph.topologicalSort
in
if DAG.isEmpty cycles then
if Graph.isEmpty cycles then
Ok sortedModules

else
Expand All @@ -212,22 +247,33 @@ packageDefinitionFromSource packageInfo sourceFiles =
parsedFiles
|> Dict.fromList
in
sortModules parsedFiles
parsedFiles
|> treeShakeModules
|> sortModules
|> Result.andThen (mapParsedFiles packageInfo.name parsedFilesByModuleName)
)
|> Result.map
(\moduleDefs ->
{ dependencies = Dict.empty
, modules =
moduleDefs
|> Dict.map
(\modulePath m ->
if packageInfo.exposedModules |> Set.member modulePath then
public m
|> Dict.toList
|> List.map
(\( modulePath, m ) ->
let
packageLessModulePath =
modulePath
|> Path.toList
|> List.drop (packageInfo.name |> Path.toList |> List.length)
|> Path.fromList
in
if packageInfo.exposedModules |> Set.member packageLessModulePath then
( packageLessModulePath, public m )

else
private m
( packageLessModulePath, private m )
)
|> Dict.fromList
}
)

Expand Down
2 changes: 2 additions & 0 deletions src/Morphir/Elm/Frontend/Resolve.elm
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,12 @@ defaultImports =
)
in
[ importExplicit [ "Morphir", "SDK", "Bool" ] Nothing [ TypeOrAliasExpose "Bool" ]
, importExplicit [ "Morphir", "SDK", "Char" ] Nothing [ TypeOrAliasExpose "Char" ]
, importExplicit [ "Morphir", "SDK", "Int" ] Nothing [ TypeOrAliasExpose "Int" ]
, importExplicit [ "Morphir", "SDK", "Float" ] Nothing [ TypeOrAliasExpose "Float" ]
, importExplicit [ "Morphir", "SDK", "String" ] Nothing [ TypeOrAliasExpose "String" ]
, importExplicit [ "Morphir", "SDK", "Maybe" ] Nothing [ TypeOrAliasExpose "Maybe" ]
, importExplicit [ "Morphir", "SDK", "Result" ] Nothing [ TypeOrAliasExpose "Result" ]
, importExplicit [ "Morphir", "SDK", "List" ] Nothing [ TypeOrAliasExpose "List" ]
]

Expand Down
69 changes: 59 additions & 10 deletions src/Morphir/DAG.elm → src/Morphir/Graph.elm
Original file line number Diff line number Diff line change
@@ -1,25 +1,38 @@
module Morphir.DAG exposing (DAG, fromDict, isEmpty, topologicalSort)
module Morphir.Graph exposing (Graph, empty, fromDict, fromList, isEmpty, reachableNodes, topologicalSort)

import Dict exposing (Dict)
import Set exposing (Set)


type DAG comparable
= DAG (Dict comparable (Set comparable))
type Graph comparable
= Graph (Dict comparable (Set comparable))


fromDict : Dict comparable (Set comparable) -> DAG comparable
fromDict : Dict comparable (Set comparable) -> Graph comparable
fromDict =
DAG
Graph


isEmpty : DAG comparable -> Bool
isEmpty (DAG edges) =
fromList : List ( comparable, List comparable ) -> Graph comparable
fromList list =
list
|> List.map (\( from, tos ) -> ( from, Set.fromList tos ))
|> Dict.fromList
|> Graph


empty : Graph comparable
empty =
Graph Dict.empty


isEmpty : Graph comparable -> Bool
isEmpty (Graph edges) =
Dict.isEmpty edges


topologicalSort : DAG comparable -> ( List comparable, DAG comparable )
topologicalSort (DAG edges) =
topologicalSort : Graph comparable -> ( List comparable, Graph comparable )
topologicalSort (Graph edges) =
let
normalize graphEdges =
let
Expand Down Expand Up @@ -74,6 +87,42 @@ topologicalSort (DAG edges) =
step newGraphEdges (startNode :: sorting)

Nothing ->
( List.reverse sorting, DAG graphEdges )
( List.reverse sorting, Graph graphEdges )
in
step (normalize edges) []


reachableNodes : Set comparable -> Graph comparable -> Set comparable
reachableNodes startNodes (Graph edges) =
let
directlyReachable : Set comparable -> Set comparable
directlyReachable fromNodes =
edges
|> Dict.toList
|> List.filterMap
(\( fromNode, toNodes ) ->
if fromNodes |> Set.member fromNode then
Just toNodes

else
Nothing
)
|> List.foldl Set.union Set.empty

transitivelyReachable : Set comparable -> Set comparable
transitivelyReachable fromNodes =
if Set.isEmpty fromNodes then
Set.empty

else
let
reachables =
Set.union (directlyReachable fromNodes) fromNodes
in
if reachables == fromNodes then
fromNodes

else
Set.union fromNodes (transitivelyReachable reachables)
in
transitivelyReachable startNodes
4 changes: 4 additions & 0 deletions src/Morphir/IR/SDK.elm
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ module Morphir.IR.SDK exposing (..)
import Dict
import Morphir.IR.Advanced.Package as Package
import Morphir.IR.SDK.Bool as Bool
import Morphir.IR.SDK.Char as Char
import Morphir.IR.SDK.Float as Float
import Morphir.IR.SDK.Int as Int
import Morphir.IR.SDK.List as List
import Morphir.IR.SDK.Maybe as Maybe
import Morphir.IR.SDK.Result as Result
import Morphir.IR.SDK.String as String


Expand All @@ -15,10 +17,12 @@ packageDeclaration =
{ modules =
Dict.fromList
[ ( [ [ "bool" ] ], Bool.moduleDeclaration )
, ( [ [ "char" ] ], Char.moduleDeclaration )
, ( [ [ "int" ] ], Int.moduleDeclaration )
, ( [ [ "float" ] ], Float.moduleDeclaration )
, ( [ [ "string" ] ], String.moduleDeclaration )
, ( [ [ "maybe" ] ], Maybe.moduleDeclaration )
, ( [ [ "result" ] ], Result.moduleDeclaration )
, ( [ [ "list" ] ], List.moduleDeclaration )
]
}
39 changes: 39 additions & 0 deletions src/Morphir/IR/SDK/Char.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module Morphir.IR.SDK.Char exposing (..)

import Dict
import Morphir.IR.Advanced.Module as Module
import Morphir.IR.Advanced.Type exposing (Declaration(..), Type(..))
import Morphir.IR.FQName as FQName exposing (FQName)
import Morphir.IR.Name as Name
import Morphir.IR.Path exposing (Path)
import Morphir.IR.QName as QName
import Morphir.IR.SDK.Common exposing (packageName)


moduleName : Path
moduleName =
[ [ "char" ] ]


moduleDeclaration : Module.Declaration ()
moduleDeclaration =
{ types =
Dict.fromList
[ ( [ "char" ], OpaqueTypeDeclaration [] )
]
, values =
Dict.empty
}


fromLocalName : String -> FQName
fromLocalName name =
name
|> Name.fromString
|> QName.fromName moduleName
|> FQName.fromQName packageName


charType : extra -> Type extra
charType extra =
Reference (fromLocalName "char") [] extra
44 changes: 44 additions & 0 deletions src/Morphir/IR/SDK/Result.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module Morphir.IR.SDK.Result exposing (..)

import Dict
import Morphir.IR.Advanced.Module as Module
import Morphir.IR.Advanced.Type as Type exposing (Declaration(..), Type(..))
import Morphir.IR.FQName as FQName exposing (FQName)
import Morphir.IR.Name as Name
import Morphir.IR.Path exposing (Path)
import Morphir.IR.QName as QName
import Morphir.IR.SDK.Common exposing (packageName)


moduleName : Path
moduleName =
[ [ "result" ] ]


moduleDeclaration : Module.Declaration ()
moduleDeclaration =
{ types =
Dict.fromList
[ ( [ "result" ]
, CustomTypeDeclaration [ [ "e" ], [ "a" ] ]
[ ( [ "ok" ], [ ( [ "value" ], Type.Variable [ "a" ] () ) ] )
, ( [ "err" ], [ ( [ "error" ], Type.Variable [ "e" ] () ) ] )
]
)
]
, values =
Dict.empty
}


fromLocalName : String -> FQName
fromLocalName name =
name
|> Name.fromString
|> QName.fromName moduleName
|> FQName.fromQName packageName


resultType : Type extra -> extra -> Type extra
resultType itemType extra =
Reference (fromLocalName "result") [ itemType ] extra
18 changes: 14 additions & 4 deletions tests/Morphir/Elm/FrontendTests.elm
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,24 @@ type Bee = Bee
"""
}

sourceC =
{ path = "My/Package/C.elm"
, content =
unindent """
module My.Package.C exposing (..)
type Cee = Cee
"""
}

packageName =
Path.fromString "my/package"
Path.fromString "My.Package"

moduleA =
Path.fromString "My.Package.A"
Path.fromString "A"

moduleB =
Path.fromString "My.Package.B"
Path.fromString "B"

packageInfo =
{ name =
Expand Down Expand Up @@ -152,7 +162,7 @@ type Bee = Bee
in
test "first" <|
\_ ->
Frontend.packageDefinitionFromSource packageInfo [ sourceA, sourceB ]
Frontend.packageDefinitionFromSource packageInfo [ sourceA, sourceB, sourceC ]
|> Result.map Package.eraseDefinitionExtra
|> Expect.equal (Ok expected)

Expand Down
Loading

0 comments on commit 8490534

Please sign in to comment.