Play

Check-in [7d904176c1]
Login
Overview
Comment:Add function that goes through a parser AST and figures out which modules the AST depends on being present before qualification.
Timelines: family | ancestors | descendants | both | module-definition
Files: files | file ages | folders
SHA3-256: 7d904176c154bf4408ff3bc79bb3759f38e63588cc184011f688b815e1163a78
User & Date: robin.hansen on 2021-05-03 13:50:24
Other Links: branch diff | manifest | tags
Context
2021-05-05
08:18
PackageLoader now parses each module first, then uses new dependency information for finding new mod... check-in: 73872525cb user: robin.hansen tags: module-definition
2021-05-03
13:50
Add function that goes through a parser AST and figures out which modules the AST depends on being p... check-in: 7d904176c1 user: robin.hansen tags: module-definition
2021-05-01
11:49
Removed entry: true syntax from function definition. Fixes [48cf587779]. check-in: 52304dc684 user: robin.hansen tags: module-definition
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Modified src/Play/Qualifier.elm from [9fd8ef35a0] to [ba63605abc].

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
...
676
677
678
679
680
681
682















































































































        ( typeErrors, qualifiedTypes ) =
            Dict.foldl (\_ val acc -> qualifyType config val acc) ( [], Dict.empty ) config.ast.types
                |> Tuple.mapSecond (\qt -> Dict.map (\_ v -> resolveUnionInTypeDefs qt v) qt)

        ( wordErrors, externalWords, qualifiedWords ) =
            Dict.foldl (\_ val acc -> qualifyDefinition config qualifiedTypes val acc) ( [], Set.empty, Dict.empty ) config.ast.words

        requiredModules =
            Set.toList externalWords
                |> List.map Tuple.first
                |> Set.fromList

        wordsToCheck =
            Set.toList externalWords
                |> List.map (\( path, name ) -> path ++ "/" ++ name)
................................................................................
                |> Set.fromList
    in
    case ( typeErrors, wordErrors ) of
        ( [], [] ) ->
            Ok
                { types = qualifiedTypes
                , words = qualifiedWords
                , additionalModulesRequired = requiredModules
                , checkForExistingTypes = Set.empty
                , checkForExistingWords = wordsToCheck
                }

        _ ->
            Err <| typeErrors ++ wordErrors

................................................................................
    else
        String.concat
            [ "/"
            , config.packageName
            , "/"
            , path
            ]






















































































































|







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
...
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
        ( typeErrors, qualifiedTypes ) =
            Dict.foldl (\_ val acc -> qualifyType config val acc) ( [], Dict.empty ) config.ast.types
                |> Tuple.mapSecond (\qt -> Dict.map (\_ v -> resolveUnionInTypeDefs qt v) qt)

        ( wordErrors, externalWords, qualifiedWords ) =
            Dict.foldl (\_ val acc -> qualifyDefinition config qualifiedTypes val acc) ( [], Set.empty, Dict.empty ) config.ast.words

        additionalRequiredModules =
            Set.toList externalWords
                |> List.map Tuple.first
                |> Set.fromList

        wordsToCheck =
            Set.toList externalWords
                |> List.map (\( path, name ) -> path ++ "/" ++ name)
................................................................................
                |> Set.fromList
    in
    case ( typeErrors, wordErrors ) of
        ( [], [] ) ->
            Ok
                { types = qualifiedTypes
                , words = qualifiedWords
                , additionalModulesRequired = additionalRequiredModules
                , checkForExistingTypes = Set.empty
                , checkForExistingWords = wordsToCheck
                }

        _ ->
            Err <| typeErrors ++ wordErrors

................................................................................
    else
        String.concat
            [ "/"
            , config.packageName
            , "/"
            , path
            ]



-- Dependant modules


requiredModules : RunConfig -> Set String
requiredModules config =
    let
        topLevelAliases =
            config.ast.moduleDefinition.aliases

        topLevelAliasTargets =
            topLevelAliases
                |> Dict.values
                |> Set.fromList

        topLevelImports =
            config.ast.moduleDefinition.imports
                |> Dict.keys
                |> Set.fromList

        wordRequirements =
            config.ast.words
                |> Dict.foldl
                    (\_ w acc -> Set.union (requiredModulesOfWord topLevelAliases w) acc)
                    Set.empty

        fullyQualify mod acc =
            if String.startsWith "/" mod then
                case Dict.get mod config.externalModules of
                    Just package ->
                        Set.insert
                            (String.concat
                                [ "/"
                                , package
                                , mod
                                ]
                            )
                            acc

                    Nothing ->
                        acc

            else
                Set.insert (qualifyPackageModule config mod) acc
    in
    topLevelAliasTargets
        |> Set.union topLevelImports
        |> Set.union wordRequirements
        |> Set.foldl fullyQualify Set.empty


requiredModulesOfWord : Dict String String -> Parser.WordDefinition -> Set String
requiredModulesOfWord topLevelAliases word =
    let
        wordAliases =
            word.metadata.aliases
                |> Dict.values
                |> Set.fromList

        wordImports =
            word.metadata.imports
                |> Dict.keys
                |> Set.fromList

        impls =
            case word.implementation of
                Parser.SoloImpl impl ->
                    [ impl ]

                Parser.MultiImpl branches impl ->
                    impl :: List.map Tuple.second branches

        wordReferences =
            impls
                |> List.concat
                |> List.filterMap (extractModuleReferenceFromNode topLevelAliases word.metadata)
                |> Set.fromList
    in
    wordAliases
        |> Set.union wordImports
        |> Set.union wordReferences


extractModuleReferenceFromNode : Dict String String -> Metadata -> Parser.AstNode -> Maybe String
extractModuleReferenceFromNode topLevelAliases meta node =
    case node of
        Parser.PackageWord _ [ potentialAlias ] _ ->
            case
                ( Dict.get potentialAlias topLevelAliases
                , Dict.get potentialAlias meta.aliases
                )
            of
                ( Just _, _ ) ->
                    Nothing

                ( _, Just _ ) ->
                    Nothing

                ( Nothing, Nothing ) ->
                    Just potentialAlias

        Parser.PackageWord _ path _ ->
            Just (String.join "/" path)

        Parser.ExternalWord _ path _ ->
            Just ("/" ++ String.join "/" path)

        _ ->
            Nothing

Modified tests/Test/Qualifier.elm from [a1f256716f] to [4bae61eb94].

1271
1272
1273
1274
1275
1276
1277






















1278














































                    case result of
                        Err err ->
                            Expect.fail <| "Did not expect qualification to fail with error: " ++ Debug.toString err

                        Ok actualAst ->
                            Expect.equal expectedAst actualAst
            ]






















        ]





















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
                    case result of
                        Err err ->
                            Expect.fail <| "Did not expect qualification to fail with error: " ++ Debug.toString err

                        Ok actualAst ->
                            Expect.equal expectedAst actualAst
            ]
        , test "Retrieve dependant modules" <|
            \_ ->
                let
                    unqualifiedAst =
                        { moduleDefinition =
                            { aliases =
                                Dict.fromList
                                    [ ( "html", "/external/html" ) ]
                            , imports =
                                Dict.fromList
                                    [ ( "/external/module", [] ) ]
                            , exposes = Set.fromList []
                            }
                        , types = Dict.empty
                        , words =
                            Dict.fromListBy .name
                                [ { name = "call-external"
                                  , metadata = Metadata.default
                                  , implementation =
                                        AST.MultiImpl
                                            [ ( AST.TypeMatch emptyRange Type.Int [ ( "value", AST.LiteralInt 1 ) ]
                                              , [ AST.PackageWord emptyRange [ "package", "module" ] "when-one"
                                                ]
                                              )
                                            ]
                                            [ AST.PackageWord emptyRange [ "package", "module" ] "when-other-one" ]
                                  }
                                , { name = "main"
                                  , metadata =
                                        Metadata.default
                                            |> Metadata.withImport "/list/of/names" [ "one" ]
                                            |> Metadata.withAlias "ali" "internal/alias"
                                  , implementation =
                                        AST.SoloImpl
                                            [ AST.PackageWord emptyRange [ "html" ] "div"
                                            , AST.Word emptyRange "call-external"
                                            , AST.ExternalWord emptyRange [ "some", "ext" ] "word"
                                            , AST.PackageWord emptyRange [ "ali" ] "word1"
                                            ]
                                  }
                                ]
                        }

                    expectedRequiredModules =
                        Set.fromList
                            [ "/robheghan/dummy/list/of/names"
                            , "/robheghan/dummy/some/ext"
                            , "/robheghan/html/external/html"
                            , "/robheghan/html/external/module"
                            , "/package/test/internal/alias"
                            , "/package/test/package/module"
                            ]

                    actualRequiredModules =
                        requiredModules
                            { packageName = "package/test"
                            , modulePath = "core"
                            , ast = unqualifiedAst
                            , externalModules =
                                Dict.fromList
                                    [ ( "/list/of/names", "robheghan/dummy" )
                                    , ( "/some/ext", "robheghan/dummy" )
                                    , ( "/external/html", "robheghan/html" )
                                    , ( "/external/module", "robheghan/html" )
                                    ]
                            }
                in
                Expect.equal expectedRequiredModules actualRequiredModules
        ]