Play

Check-in [0f02eed1b4]
Login
Overview
Comment:Perform additional testing on module references to catch invalid module paths.
Timelines: family | ancestors | descendants | both | modules
Files: files | file ages | folders
SHA3-256: 0f02eed1b49e1c842286df32a740a39b0cabe640e2a74d54b20b48dcd4f79c9d
User & Date: robin.hansen on 2021-02-03 12:46:11
Other Links: branch diff | manifest | tags
Context
2021-02-05
11:33
Prepare for name mangling in qualifier step. check-in: 7b1a6816a6 user: robin.hansen tags: modules
2021-02-03
12:46
Perform additional testing on module references to catch invalid module paths. check-in: 0f02eed1b4 user: robin.hansen tags: modules
09:10
Parser now supports relative and absolut module references. check-in: f477fd7e39 user: robin.hansen tags: modules
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Modified src/Play/Parser.elm from [d6fa451fc6] to [8b0faf8562].

182
183
184
185
186
187
188
189












190
191
192
193









194
195
196
197
198
199



200
201
202
203
204
205
206
207
208
209
210
211
212

213
214
215
216
217
218
219
        |. noiseParser
        |> Parser.backtrackable


symbolImplParser2 : Parser (SourceLocationRange -> AstNode)
symbolImplParser2 =
    let
        externalBuilder firstSymbol ( path, reference ) =












            \loc ->
                ExternalWord loc (firstSymbol :: path) reference

        internalBuilder firstSymbol (( path, reference ) as modulePathResult) =









            \loc ->
                if modulePathResult == ( [], "" ) then
                    Word loc firstSymbol

                else
                    PackageWord loc (firstSymbol :: path) reference



    in
    Parser.oneOf
        [ Parser.succeed externalBuilder
            |. Parser.symbol (Token "/" NotMetadata)
            |= symbolImplParser
            |= Parser.loop [] modulePathParser
        , Parser.succeed internalBuilder
            |= symbolImplParser
            |= Parser.oneOf
                [ Parser.loop [] modulePathParser
                , Parser.succeed ( [], "" )
                ]
        ]



modulePathParser : List String -> Parser (Parser.Step (List String) ( List String, String ))
modulePathParser symbols =
    Parser.oneOf
        [ Parser.succeed (\name -> Parser.Loop (name :: symbols))
            |. Parser.symbol (Token "/" NotMetadata)







|
>
>
>
>
>
>
>
>
>
>
>
>
|
|

|
>
>
>
>
>
>
>
>
>
|
|
|

|
|
>
>
>













>







182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
        |. noiseParser
        |> Parser.backtrackable


symbolImplParser2 : Parser (SourceLocationRange -> AstNode)
symbolImplParser2 =
    let
        externalBuilder firstSymbol (( partialPath, reference ) as modulePathResult) =
            let
                path =
                    firstSymbol :: partialPath
            in
            if checkForUpperCaseLetterInPath path then
                Parser.problem <| InvalidModulePath <| "/" ++ String.join "/" path

            else if modulePathResult == ( [], "" ) then
                Parser.problem <| InvalidModulePath <| "/" ++ firstSymbol

            else
                Parser.succeed <|
                    \loc ->
                        ExternalWord loc path reference

        internalBuilder firstSymbol (( partialPath, reference ) as modulePathResult) =
            let
                path =
                    firstSymbol :: partialPath
            in
            if checkForUpperCaseLetterInPath path && partialPath /= [] then
                Parser.problem <| InvalidModulePath <| String.join "/" path

            else
                Parser.succeed <|
                    \loc ->
                        if modulePathResult == ( [], "" ) then
                            Word loc firstSymbol

                        else
                            PackageWord loc path reference

        checkForUpperCaseLetterInPath path =
            List.any (String.any Char.isUpper) path
    in
    Parser.oneOf
        [ Parser.succeed externalBuilder
            |. Parser.symbol (Token "/" NotMetadata)
            |= symbolImplParser
            |= Parser.loop [] modulePathParser
        , Parser.succeed internalBuilder
            |= symbolImplParser
            |= Parser.oneOf
                [ Parser.loop [] modulePathParser
                , Parser.succeed ( [], "" )
                ]
        ]
        |> Parser.andThen identity


modulePathParser : List String -> Parser (Parser.Step (List String) ( List String, String ))
modulePathParser symbols =
    Parser.oneOf
        [ Parser.succeed (\name -> Parser.Loop (name :: symbols))
            |. Parser.symbol (Token "/" NotMetadata)

Modified src/Play/Parser/Problem.elm from [1260a0c31a] to [7563961c4b].

19
20
21
22
23
24
25

26
27
28
29
30
31
32
..
91
92
93
94
95
96
97



    | ExpectedEnd
    | ExpectedTypeSeperator
    | ExpectedLeftBracket
    | ExpectedRightBracket
    | WordAlreadyDefined String (Maybe SourceLocationRange) (Maybe SourceLocationRange)
    | TypeAlreadyDefined String SourceLocationRange SourceLocationRange
    | UnknownMetadata String



toString : String -> Problem -> String
toString source problem =
    case problem of
        NotInt ->
            "this is not an integer"
................................................................................
                ++ ": You're trying to define a new type called '"
                ++ typeName
                ++ "', but this type has already been defined here:\n\n"
                ++ SourceLocation.extractFromString source previousDefinitionRange

        UnknownMetadata meta ->
            meta ++ " is not a known metadata label."










>







 







>
>
>
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
..
92
93
94
95
96
97
98
99
100
101
    | ExpectedEnd
    | ExpectedTypeSeperator
    | ExpectedLeftBracket
    | ExpectedRightBracket
    | WordAlreadyDefined String (Maybe SourceLocationRange) (Maybe SourceLocationRange)
    | TypeAlreadyDefined String SourceLocationRange SourceLocationRange
    | UnknownMetadata String
    | InvalidModulePath String


toString : String -> Problem -> String
toString source problem =
    case problem of
        NotInt ->
            "this is not an integer"
................................................................................
                ++ ": You're trying to define a new type called '"
                ++ typeName
                ++ "', but this type has already been defined here:\n\n"
                ++ SourceLocation.extractFromString source previousDefinitionRange

        UnknownMetadata meta ->
            meta ++ " is not a known metadata label."

        InvalidModulePath path ->
            "'" ++ path ++ "' is not a valid module path. Note: Upper case characters are not allowed."

Modified tests/Test/Parser/Error.elm from [b45ca2f7fa] to [297a7bb4eb].

113
114
115
116
117
118
119














































120
121
122
123
124
125
126
        , test "Only compiler can create functions which names begins with an upper case letter" <|
            \_ ->
                checkForError ((==) NotSymbol) <|
                    """
                    def: Person
                    : 1
                    """














































        ]


checkForError : (Problem -> Bool) -> String -> Expectation
checkForError fn source =
    case compile source of
        Err errors ->







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







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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
        , test "Only compiler can create functions which names begins with an upper case letter" <|
            \_ ->
                checkForError ((==) NotSymbol) <|
                    """
                    def: Person
                    : 1
                    """
        , describe "Module path elements" <|
            let
                invalidModulePathError err =
                    case err of
                        InvalidModulePath _ ->
                            True

                        _ ->
                            False
            in
            [ test "Starting with upper case" <|
                \_ ->
                    checkForError invalidModulePathError <|
                        """
                        def: sample
                        : some/Other/module
                        """
            , test "Contains upper case" <|
                \_ ->
                    checkForError invalidModulePathError <|
                        """
                        def: sample
                        : some/otHer/module
                        """
            , test "Starting with upper case (external)" <|
                \_ ->
                    checkForError invalidModulePathError <|
                        """
                        def: sample
                        : /some/Other/module
                        """
            , test "Contains upper case (external)" <|
                \_ ->
                    checkForError invalidModulePathError <|
                        """
                        def: sample
                        : /some/otHer/module
                        """
            , test "External reference must contain two parts" <|
                \_ ->
                    checkForError invalidModulePathError <|
                        """
                        def: sample
                        : /some
                        """
            ]
        ]


checkForError : (Problem -> Bool) -> String -> Expectation
checkForError fn source =
    case compile source of
        Err errors ->