Stabel

Check-in [74d477ef73]
Login
Overview
Comment:Add default import on standard_library/core module.
Timelines: family | ancestors | descendants | both | module-definition
Files: files | file ages | folders
SHA3-256: 74d477ef730e1caaf5063f97e5e7930fb90fbb2da7ab184e9409d9d4d0fb1d6a
User & Date: robin.hansen on 2021-06-01 10:34:18
Other Links: branch diff | manifest | tags
Context
2021-06-02
09:23
, is now a valid function name. check-in: 8e8bc32982 user: robin.hansen tags: module-definition
2021-06-01
10:34
Add default import on standard_library/core module. check-in: 74d477ef73 user: robin.hansen tags: module-definition
2021-05-31
10:36
Add module definitions to all standard library modules. check-in: cfb0ec9059 user: robin.hansen tags: module-definition
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Modified src/Play/Parser.elm from [7fd0d74408] to [2e78bf7501].

1
2
3
4

5
6
7
8
9
10
11
module Play.Parser exposing
    ( AST
    , AstNode(..)
    , ModuleDefinition(..)

    , PossiblyQualifiedType(..)
    , TypeDefinition(..)
    , TypeMatch(..)
    , TypeMatchValue(..)
    , TypeSignature(..)
    , WordDefinition
    , WordImplementation(..)




>







1
2
3
4
5
6
7
8
9
10
11
12
module Play.Parser exposing
    ( AST
    , AstNode(..)
    , ModuleDefinition(..)
    , ModuleDefinitionRec
    , PossiblyQualifiedType(..)
    , TypeDefinition(..)
    , TypeMatch(..)
    , TypeMatchValue(..)
    , TypeSignature(..)
    , WordDefinition
    , WordImplementation(..)

Modified src/Play/Qualifier.elm from [b1f6a34b92] to [0a582ab702].

109
110
111
112
113
114
115































116
117
118
119
120
121
122
...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

185
186
187
188
189
190
191
192
193
194
195
196
...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472

473
474
475
476
477
478
479
480
481
482
...
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558

559
560
561
562
563
564
565
566
567
568
...
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
....
1098
1099
1100
1101
1102
1103
1104

1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115


1116

1117
1118
1119
1120
1121
1122
1123
....
1181
1182
1183
1184
1185
1186
1187



1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
                { types = qualifiedTypes
                , words = qualifiedWords
                }

        _ ->
            Err <| typeErrors ++ wordErrors

































resolveUnionInTypeDefs : Dict String TypeDefinition -> TypeDefinition -> TypeDefinition
resolveUnionInTypeDefs qt td =
    case td of
        CustomTypeDef exposed name range generics members ->
            CustomTypeDef exposed name range generics (List.map (Tuple.mapSecond (resolveUnion qt)) members)

................................................................................
qualifyType :
    RunConfig
    -> Parser.TypeDefinition
    -> ( List Problem, Dict String TypeDefinition )
    -> ( List Problem, Dict String TypeDefinition )
qualifyType config typeDef ( errors, acc ) =
    let
        ( modRefs, exposes ) =
            case config.ast.moduleDefinition of
                Parser.Undefined ->
                    ( { aliases = Dict.empty
                      , imports = Dict.empty
                      }
                    , Set.empty
                    )

                Parser.Defined mod ->

                    ( { aliases = mod.aliases
                      , imports = mod.imports
                      }
                    , mod.exposes
                    )
    in
    case typeDef of
        Parser.CustomTypeDef range name generics members ->
            let
                qualifiedName =
                    qualifyName config name

................................................................................
            case unqualifiedWord.implementation of
                Parser.SoloImpl defImpl ->
                    ( [], defImpl )

                Parser.MultiImpl whenImpl defImpl ->
                    ( whenImpl, defImpl )

        moduleReferences =
            case config.ast.moduleDefinition of
                Parser.Defined def ->
                    { aliases = Dict.union unqualifiedWord.aliases def.aliases
                    , imports = Dict.union unqualifiedWord.imports def.imports
                    }

                Parser.Undefined ->

                    { aliases = unqualifiedWord.aliases
                    , imports = unqualifiedWord.imports
                    }

        ( newWordsAfterWhens, qualifiedWhensResult ) =
            whens
                |> List.foldr
                    (qualifyWhen
                        config
                        qualifiedTypes
................................................................................

                Parser.UserProvided wt ->
                    List.length wt.input

                Parser.Verified wt ->
                    List.length wt.input

        modRefs =
            case config.ast.moduleDefinition of
                Parser.Undefined ->
                    { aliases = word.aliases
                    , imports = word.imports
                    }

                Parser.Defined mod ->

                    { aliases = Dict.union mod.aliases word.aliases
                    , imports = Dict.union mod.imports word.imports
                    }
    in
    Parser.typeSignatureToMaybe word.typeSignature
        |> Maybe.map (\ts -> ts.input ++ ts.output)
        |> Maybe.withDefault []
        |> List.map (qualifyMemberType config modRefs wordRange)
        |> Result.combine
        |> Result.map
................................................................................

                            Just mod ->
                                if String.startsWith "/" mod then
                                    let
                                        path =
                                            mod
                                                |> String.split "/"
                                                |> List.drop 1
                                    in
                                    qualifyNode
                                        config
                                        currentDefName
                                        modRefs
                                        (Parser.ExternalWord loc path value)
                                        acc
................................................................................
resolveImportedWord config modRefs name =
    let
        explicitImports =
            modRefs.imports
                |> Dict.toList
                |> List.find (\( _, v ) -> List.member name v)
                |> Maybe.map Tuple.first


        potentialCandidates =
            modRefs.imports
                |> Dict.filter (\_ v -> List.isEmpty v)
                |> Dict.keys
                |> List.filterMap resolveMod
                |> List.map (\mod -> ( mod, mod ++ "/" ++ name ))

        resolveMod mod =
            if String.startsWith "/" mod then
                Dict.get mod config.externalModules


                    |> Maybe.map (\package -> qualifyPackageModule package mod)


            else
                Just <| qualifyPackageModule config.packageName mod
    in
    case explicitImports of
        Just _ ->
            explicitImports
................................................................................
    , externalModules : Dict String String
    }


requiredModules : RequiredModulesConfig -> Set String
requiredModules config =
    let



        topLevelAliases =
            case config.ast.moduleDefinition of
                Parser.Defined def ->
                    def.aliases

                Parser.Undefined ->
                    Dict.empty

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

        topLevelImports =
            case config.ast.moduleDefinition of
                Parser.Defined def ->
                    def.imports
                        |> Dict.keys
                        |> Set.fromList

                Parser.Undefined ->
                    Set.empty

        typeRequirements =
            config.ast.types
                |> Dict.foldl
                    (\_ t acc -> Set.union (requiredModulesOfType t) acc)
                    Set.empty








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
|
<
<
<
|
<
<
<
<
>
|
|
|
|
|







 







|
|
<
<
<
|
<
<
>
|
|
|







 







|
|
<
<
<
|
<
<
>
|
|
|







 







|







 







>











>
>
|
>







 







>
>
>

<
<
|
<
<
<







<
<
|
|
|
<
<
<







109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
...
199
200
201
202
203
204
205
206
207



208




209
210
211
212
213
214
215
216
217
218
219
220
221
...
483
484
485
486
487
488
489
490
491



492


493
494
495
496
497
498
499
500
501
502
503
...
565
566
567
568
569
570
571
572
573



574


575
576
577
578
579
580
581
582
583
584
585
...
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
....
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
....
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212


1213



1214
1215
1216
1217
1218
1219
1220


1221
1222
1223



1224
1225
1226
1227
1228
1229
1230
                { types = qualifiedTypes
                , words = qualifiedWords
                }

        _ ->
            Err <| typeErrors ++ wordErrors


type alias ModuleDefinitionConfig a =
    { a
        | ast : Parser.AST
        , externalModules : Dict String String
    }


moduleDefinition : ModuleDefinitionConfig a -> Parser.ModuleDefinitionRec
moduleDefinition config =
    let
        defaultImports =
            if Dict.get "/core" config.externalModules == Just "play/standard_library" then
                Dict.fromList [ ( "/core", [] ) ]

            else
                Dict.empty
    in
    case config.ast.moduleDefinition of
        Parser.Undefined ->
            { imports = defaultImports
            , aliases = Dict.empty
            , exposes = Set.empty
            }

        Parser.Defined def ->
            { imports = Dict.union def.imports defaultImports
            , aliases = def.aliases
            , exposes = def.exposes
            }


resolveUnionInTypeDefs : Dict String TypeDefinition -> TypeDefinition -> TypeDefinition
resolveUnionInTypeDefs qt td =
    case td of
        CustomTypeDef exposed name range generics members ->
            CustomTypeDef exposed name range generics (List.map (Tuple.mapSecond (resolveUnion qt)) members)

................................................................................
qualifyType :
    RunConfig
    -> Parser.TypeDefinition
    -> ( List Problem, Dict String TypeDefinition )
    -> ( List Problem, Dict String TypeDefinition )
qualifyType config typeDef ( errors, acc ) =
    let
        modDef =
            moduleDefinition config








        ( modRefs, exposes ) =
            ( { aliases = modDef.aliases
              , imports = modDef.imports
              }
            , modDef.exposes
            )
    in
    case typeDef of
        Parser.CustomTypeDef range name generics members ->
            let
                qualifiedName =
                    qualifyName config name

................................................................................
            case unqualifiedWord.implementation of
                Parser.SoloImpl defImpl ->
                    ( [], defImpl )

                Parser.MultiImpl whenImpl defImpl ->
                    ( whenImpl, defImpl )

        modDef =
            moduleDefinition config






        moduleReferences =
            { aliases = Dict.union unqualifiedWord.aliases modDef.aliases
            , imports = Dict.union unqualifiedWord.imports modDef.imports
            }

        ( newWordsAfterWhens, qualifiedWhensResult ) =
            whens
                |> List.foldr
                    (qualifyWhen
                        config
                        qualifiedTypes
................................................................................

                Parser.UserProvided wt ->
                    List.length wt.input

                Parser.Verified wt ->
                    List.length wt.input

        modDef =
            moduleDefinition config






        modRefs =
            { aliases = Dict.union modDef.aliases word.aliases
            , imports = Dict.union modDef.imports word.imports
            }
    in
    Parser.typeSignatureToMaybe word.typeSignature
        |> Maybe.map (\ts -> ts.input ++ ts.output)
        |> Maybe.withDefault []
        |> List.map (qualifyMemberType config modRefs wordRange)
        |> Result.combine
        |> Result.map
................................................................................

                            Just mod ->
                                if String.startsWith "/" mod then
                                    let
                                        path =
                                            mod
                                                |> String.split "/"
                                                |> List.drop 3
                                    in
                                    qualifyNode
                                        config
                                        currentDefName
                                        modRefs
                                        (Parser.ExternalWord loc path value)
                                        acc
................................................................................
resolveImportedWord config modRefs name =
    let
        explicitImports =
            modRefs.imports
                |> Dict.toList
                |> List.find (\( _, v ) -> List.member name v)
                |> Maybe.map Tuple.first
                |> Maybe.andThen resolveMod

        potentialCandidates =
            modRefs.imports
                |> Dict.filter (\_ v -> List.isEmpty v)
                |> Dict.keys
                |> List.filterMap resolveMod
                |> List.map (\mod -> ( mod, mod ++ "/" ++ name ))

        resolveMod mod =
            if String.startsWith "/" mod then
                Dict.get mod config.externalModules
                    |> Maybe.map
                        (\package ->
                            qualifyPackageModule package (String.dropLeft 1 mod)
                        )

            else
                Just <| qualifyPackageModule config.packageName mod
    in
    case explicitImports of
        Just _ ->
            explicitImports
................................................................................
    , externalModules : Dict String String
    }


requiredModules : RequiredModulesConfig -> Set String
requiredModules config =
    let
        modDef =
            moduleDefinition config

        topLevelAliases =


            modDef.aliases




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

        topLevelImports =


            modDef.imports
                |> Dict.keys
                |> Set.fromList




        typeRequirements =
            config.ast.types
                |> Dict.foldl
                    (\_ t acc -> Set.union (requiredModulesOfType t) acc)
                    Set.empty

Modified tests/Test/Qualifier.elm from [1c4662c71d] to [a69b471d1a].

1158
1159
1160
1161
1162
1163
1164

1165
1166
1167
1168
1169
1170
1171
....
1172
1173
1174
1175
1176
1177
1178

1179
1180


































1181
1182
1183
1184
1185
1186
1187
....
2930
2931
2932
2933
2934
2935
2936
2937
2938
















2939

2940














































































                            , "/robheghan/html/external/module"
                            , "/robheghan/html/external/types"
                            , "/robheghan/html/external/double"
                            , "/package/test/internal/alias"
                            , "/package/test/internal/types"
                            , "/package/test/internal/match"
                            , "/package/test/package/module"

                            ]

                    actualRequiredModules =
                        requiredModules
                            { packageName = "package/test"
                            , ast = unqualifiedAst
                            , externalModules =
................................................................................
                                Dict.fromList
                                    [ ( "/list/of/names", "robheghan/dummy" )
                                    , ( "/some/ext", "robheghan/dummy" )
                                    , ( "/external/html", "robheghan/html" )
                                    , ( "/external/module", "robheghan/html" )
                                    , ( "/external/types", "robheghan/html" )
                                    , ( "/external/double", "robheghan/html" )

                                    ]
                            }


































                in
                Expect.equal expectedRequiredModules actualRequiredModules
        , describe "Module resolution" <|
            let
                dummyWord name =
                    dummyWordImpl name True

................................................................................
                    case result of
                        Ok _ ->
                            Expect.fail "Expected qualification to fail because an unexposed type is referenced"

                        Err [ Problem.TypeNotExposed _ "mod/Tipe" ] ->
                            Expect.pass

                        Err errs ->
                            Expect.fail <| "Qualification failed with unexpected error: " ++ Debug.toString errs
















            ]

        ]





















































































>







 







>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
....
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
....
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
                            , "/robheghan/html/external/module"
                            , "/robheghan/html/external/types"
                            , "/robheghan/html/external/double"
                            , "/package/test/internal/alias"
                            , "/package/test/internal/types"
                            , "/package/test/internal/match"
                            , "/package/test/package/module"
                            , "/play/standard_library/core"
                            ]

                    actualRequiredModules =
                        requiredModules
                            { packageName = "package/test"
                            , ast = unqualifiedAst
                            , externalModules =
................................................................................
                                Dict.fromList
                                    [ ( "/list/of/names", "robheghan/dummy" )
                                    , ( "/some/ext", "robheghan/dummy" )
                                    , ( "/external/html", "robheghan/html" )
                                    , ( "/external/module", "robheghan/html" )
                                    , ( "/external/types", "robheghan/html" )
                                    , ( "/external/double", "robheghan/html" )
                                    , ( "/core", "play/standard_library" )
                                    ]
                            }
                in
                Expect.equal expectedRequiredModules actualRequiredModules
        , test "Reliance on standard_library/core only when standard_library is specified as externalModule" <|
            \_ ->
                let
                    unqualifiedAst =
                        { moduleDefinition = AST.Undefined
                        , types = Dict.empty
                        , words =
                            Dict.fromListBy .name
                                [ { name = "main"
                                  , typeSignature = AST.NotProvided
                                  , sourceLocationRange = Nothing
                                  , aliases = Dict.fromList [ ( "ali", "internal/alias" ) ]
                                  , imports = Dict.empty
                                  , implementation =
                                        AST.SoloImpl
                                            [ AST.PackageWord emptyRange [ "ali" ] "word1"
                                            ]
                                  }
                                ]
                        }

                    expectedRequiredModules =
                        Set.fromList
                            [ "/package/test/internal/alias"
                            ]

                    actualRequiredModules =
                        requiredModules
                            { packageName = "package/test"
                            , ast = unqualifiedAst
                            , externalModules = Dict.empty
                            }
                in
                Expect.equal expectedRequiredModules actualRequiredModules
        , describe "Module resolution" <|
            let
                dummyWord name =
                    dummyWordImpl name True

................................................................................
                    case result of
                        Ok _ ->
                            Expect.fail "Expected qualification to fail because an unexposed type is referenced"

                        Err [ Problem.TypeNotExposed _ "mod/Tipe" ] ->
                            Expect.pass

                        Err errs ->
                            Expect.fail <| "Qualification failed with unexpected error: " ++ Debug.toString errs
            , test "There's an implicit import on standard_library/core in anonymous modules" <|
                \_ ->
                    let
                        unqualifiedAst =
                            { moduleDefinition = AST.Undefined
                            , types = Dict.empty
                            , words =
                                Dict.fromListBy .name
                                    [ { name = "external-call"
                                      , typeSignature = AST.NotProvided
                                      , sourceLocationRange = Nothing
                                      , aliases = Dict.empty
                                      , imports = Dict.empty
                                      , implementation =
                                            AST.SoloImpl
                                                [ AST.Word emptyRange "over"
                                                ]
                                      }
                                    ]
                            }

                        inProgressAst =
                            { types = Dict.empty
                            , words =
                                Dict.fromList
                                    [ dummyWord "/play/standard_library/core/over" ]
                            }

                        result =
                            run
                                { packageName = ""
                                , modulePath = ""
                                , ast = unqualifiedAst
                                , externalModules =
                                    Dict.fromList
                                        [ ( "/core", "play/standard_library" ) ]
                                , inProgressAST = inProgressAst
                                }
                    in
                    case result of
                        Ok _ ->
                            Expect.pass

                        Err errs ->
                            Expect.fail <| "Qualification failed with unexpected error: " ++ Debug.toString errs
            , test "There's an implicit import on standard_library/core in named modules" <|
                \_ ->
                    let
                        unqualifiedAst =
                            { moduleDefinition =
                                AST.Defined
                                    { imports = Dict.empty
                                    , aliases = Dict.empty
                                    , exposes = Set.empty
                                    }
                            , types = Dict.empty
                            , words =
                                Dict.fromListBy .name
                                    [ { name = "external-call"
                                      , typeSignature = AST.NotProvided
                                      , sourceLocationRange = Nothing
                                      , aliases = Dict.empty
                                      , imports = Dict.empty
                                      , implementation =
                                            AST.SoloImpl
                                                [ AST.Word emptyRange "over"
                                                ]
                                      }
                                    ]
                            }

                        inProgressAst =
                            { types = Dict.empty
                            , words =
                                Dict.fromList
                                    [ dummyWord "/play/standard_library/core/over" ]
                            }

                        result =
                            run
                                { packageName = ""
                                , modulePath = ""
                                , ast = unqualifiedAst
                                , externalModules =
                                    Dict.fromList
                                        [ ( "/core", "play/standard_library" ) ]
                                , inProgressAST = inProgressAst
                                }
                    in
                    case result of
                        Ok _ ->
                            Expect.pass

                        Err errs ->
                            Expect.fail <| "Qualification failed with unexpected error: " ++ Debug.toString errs
            ]
        ]