Stabel

Check-in [317c5ea0b3]
Login
Overview
Comment:Bit-encoded integer literals.
Timelines: family | ancestors | descendants | both | integer-syntax-improvements
Files: files | file ages | folders
SHA3-256: 317c5ea0b3d0646375f2f5674b2c1b8cc5d079f69e00cc618817d84c8562595c
User & Date: robin.hansen on 2021-09-16 14:28:46
Other Links: branch diff | manifest | tags
Context
2021-09-16
14:30
Improved integer syntax. [55a5b57c3b]. check-in: 946bd10827 user: robin.hansen tags: trunk
14:28
Bit-encoded integer literals. Closed-Leaf check-in: 317c5ea0b3 user: robin.hansen tags: integer-syntax-improvements
14:02
Hex-encoded integer literals. check-in: 0e154d19e7 user: robin.hansen tags: integer-syntax-improvements
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Modified src/Stabel/Parser.elm from [00441a56f7] to [e30ba16980].

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
173
174
175
176
177
178
179








180
181
182
183
184












185


186



187
188



















189
190
191
192
193
194
195
{-| The builtin int parser has a bug where it commits when it comes across an 'e'
-}
intParser : Parser Int
intParser =
    Parser.inContext Problem.IntegerLiteral
        (Parser.oneOf
            [ Parser.succeed identity










                |. Parser.symbol (Token "0x" UnknownError)
                |= Parser.variable
                    { start = isHexDigit
                    , inner = isHexDigit
                    , reserved = Set.empty
                    , expecting = ExpectedHexInt
                    }
                |. Parser.oneOf
                    [ Parser.chompIf (\c -> Set.member c whitespaceChars) ExpectedWhitespace
                    , Parser.succeed ()
                        |. Parser.end ExpectedEndOfFile
                    ]
                |> Parser.andThen intHexParserHelper
            , Parser.succeed Tuple.pair
                |= Parser.variable
                    { start = Char.isDigit
                    , inner = \c -> Char.isDigit c || c == '_'
                    , reserved = Set.empty
                    , expecting = ExpectedInt
                    }
                |= Parser.oneOf
                    [ Parser.succeed True
                        |. Parser.symbol (Token "-" UnknownError)
                    , Parser.succeed False
                    ]








                |. Parser.oneOf
                    [ Parser.chompIf (\c -> Set.member c whitespaceChars) ExpectedWhitespace
                    , Parser.succeed ()
                        |. Parser.end ExpectedEndOfFile
                    ]












                |> Parser.andThen intParserHelper


            ]



        )






















-- Hex integers


isHexDigit : Char -> Bool
isHexDigit char =







>
>
>
>
>
>
>
>
>
>







|
<
<
<
<













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

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







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




173
174
175
176
177
178
179
180
181
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
245
{-| The builtin int parser has a bug where it commits when it comes across an 'e'
-}
intParser : Parser Int
intParser =
    Parser.inContext Problem.IntegerLiteral
        (Parser.oneOf
            [ Parser.succeed identity
                |. Parser.symbol (Token "0b" UnknownError)
                |= Parser.variable
                    { start = isBit
                    , inner = isBit
                    , reserved = Set.empty
                    , expecting = ExpectedBitInt
                    }
                |. whiteSpaceOrEnd
                |> Parser.andThen intBitParserHelper
            , Parser.succeed identity
                |. Parser.symbol (Token "0x" UnknownError)
                |= Parser.variable
                    { start = isHexDigit
                    , inner = isHexDigit
                    , reserved = Set.empty
                    , expecting = ExpectedHexInt
                    }
                |. whiteSpaceOrEnd




                |> Parser.andThen intHexParserHelper
            , Parser.succeed Tuple.pair
                |= Parser.variable
                    { start = Char.isDigit
                    , inner = \c -> Char.isDigit c || c == '_'
                    , reserved = Set.empty
                    , expecting = ExpectedInt
                    }
                |= Parser.oneOf
                    [ Parser.succeed True
                        |. Parser.symbol (Token "-" UnknownError)
                    , Parser.succeed False
                    ]
                |. whiteSpaceOrEnd
                |> Parser.andThen intParserHelper
            ]
        )


whiteSpaceOrEnd : Parser ()
whiteSpaceOrEnd =
    Parser.oneOf
        [ Parser.chompIf (\c -> Set.member c whitespaceChars) ExpectedWhitespace
        , Parser.succeed ()
            |. Parser.end ExpectedEndOfFile
        ]



-- Bit integers


isBit : Char -> Bool
isBit char =
    char == '0' || char == '1'


intBitParserHelper : String -> Parser Int
intBitParserHelper text =
    if String.length text > 32 then
        Parser.problem IntegerBitOutOfBounds

    else
        String.foldl bitCharFolder 0 text
            |> Parser.succeed


bitCharFolder : Char -> Int -> Int
bitCharFolder char num =
    num
        |> Bitwise.shiftLeftBy 1
        |> Bitwise.or (bitCharToNum char)


bitCharToNum : Char -> Int
bitCharToNum char =
    case char of
        '1' ->
            1

        '0' ->
            0

        _ ->
            -1



-- Hex integers


isHexDigit : Char -> Bool
isHexDigit char =

Modified src/Stabel/Parser/Problem.elm from [6a8b426c68] to [6449cf85de].

31
32
33
34
35
36
37

38
39
40
41
42
43
44
..
59
60
61
62
63
64
65

66
67
68
69
70
71
72
...
206
207
208
209
210
211
212



213
214
215
216
217
218
219
...
312
313
314
315
316
317
318



    | ArrayLiteral
    | StringLiteral


type Problem
    = ExpectedInt
    | ExpectedHexInt

    | ExpectedSymbol
    | ExpectedMetadata
    | ExpectedGeneric
    | ExpectedType
    | UnknownError
    | ExpectedForwardSlash
    | ExpectedWhitespace
................................................................................
    | BadDefinition String
    | UnknownEscapeSequence String
    | StringNotTerminated
    | IntegerBadLeadingZero
    | IntegerTrailingUnderscore
    | IntegerOutOfBounds
    | IntegerHexOutOfBounds



toString : String -> String -> DeadEnd Context Problem -> String
toString sourceRef source deadEnd =
    let
        contextExplination =
            contextStackExplination deadEnd.contextStack
................................................................................
    case problem of
        ExpectedInt ->
            "Expected to find an integer"

        ExpectedHexInt ->
            "Expected to find an hex-encoded integer"




        ExpectedSymbol ->
            "Expected to find a symbol"

        ExpectedMetadata ->
            "Expected to find a keyword"

        ExpectedGeneric ->
................................................................................
            "Integers cannot end with an underscore."

        IntegerOutOfBounds ->
            "Integers must fit within a signed 32-bit number."

        IntegerHexOutOfBounds ->
            "Hex-encoded integers can contain at most 8 characters (4 bytes, 32-bits)."










>







 







>







 







>
>
>







 







>
>
>
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
..
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
...
317
318
319
320
321
322
323
324
325
326
    | ArrayLiteral
    | StringLiteral


type Problem
    = ExpectedInt
    | ExpectedHexInt
    | ExpectedBitInt
    | ExpectedSymbol
    | ExpectedMetadata
    | ExpectedGeneric
    | ExpectedType
    | UnknownError
    | ExpectedForwardSlash
    | ExpectedWhitespace
................................................................................
    | BadDefinition String
    | UnknownEscapeSequence String
    | StringNotTerminated
    | IntegerBadLeadingZero
    | IntegerTrailingUnderscore
    | IntegerOutOfBounds
    | IntegerHexOutOfBounds
    | IntegerBitOutOfBounds


toString : String -> String -> DeadEnd Context Problem -> String
toString sourceRef source deadEnd =
    let
        contextExplination =
            contextStackExplination deadEnd.contextStack
................................................................................
    case problem of
        ExpectedInt ->
            "Expected to find an integer"

        ExpectedHexInt ->
            "Expected to find an hex-encoded integer"

        ExpectedBitInt ->
            "Expected to find an bit-encoded integer"

        ExpectedSymbol ->
            "Expected to find a symbol"

        ExpectedMetadata ->
            "Expected to find a keyword"

        ExpectedGeneric ->
................................................................................
            "Integers cannot end with an underscore."

        IntegerOutOfBounds ->
            "Integers must fit within a signed 32-bit number."

        IntegerHexOutOfBounds ->
            "Hex-encoded integers can contain at most 8 characters (4 bytes, 32-bits)."

        IntegerBitOutOfBounds ->
            "Bit-encoded integers can contain at most 32 characters (32-bits)."

Modified tests/Test/Parser.elm from [66acdf25a7] to [e8a011aa46].

1535
1536
1537
1538
1539
1540
1541

1542
1543

1544






1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
            , fuzz negativeIntFuzzer "Negative ints" <|
                \num ->
                    expectParseInt (String.fromInt (num * -1) ++ "-") num
            , test "can contain underscores as seperators" <|
                \_ ->
                    expectParseInt "10_000" 10000
            , test "can be in Hex format" <|

                \_ -> expectParseInt "0xFA0" 0x0FA0
            , test "can be in Hex format (second example)" <|

                \_ -> expectParseInt "0xe3cc" 0xE3CC






            ]
        ]


positiveIntFuzzer : Fuzzer Int
positiveIntFuzzer =
    Fuzz.intRange 0 Random.maxInt


negativeIntFuzzer : Fuzzer Int
negativeIntFuzzer =
    Fuzz.intRange Random.minInt -1







>
|

>
|
>
>
>
>
>
>












1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
            , fuzz negativeIntFuzzer "Negative ints" <|
                \num ->
                    expectParseInt (String.fromInt (num * -1) ++ "-") num
            , test "can contain underscores as seperators" <|
                \_ ->
                    expectParseInt "10_000" 10000
            , test "can be in Hex format" <|
                \_ ->
                    expectParseInt "0xFA0" 0x0FA0
            , test "can be in Hex format (second example)" <|
                \_ ->
                    expectParseInt "0xe3cc" 0xE3CC
            , test "can be in bit format" <|
                \_ ->
                    expectParseInt "0b101" 5
            , test "can be in bit format (second example)" <|
                \_ ->
                    expectParseInt "0b111001" 57
            ]
        ]


positiveIntFuzzer : Fuzzer Int
positiveIntFuzzer =
    Fuzz.intRange 0 Random.maxInt


negativeIntFuzzer : Fuzzer Int
negativeIntFuzzer =
    Fuzz.intRange Random.minInt -1

Modified tests/Test/Parser/Errors.elm from [5a3cb2c60e] to [9aaaba3e40].

407
408
409
410
411
412
413








































414
415
416
417
418
419
420
                        source =
                            """
                            def: src
                            : 0xAABBCCDDE
                            """
                    in
                    checkForError ((==) IntegerHexOutOfBounds) source








































            ]
        ]


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







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







407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
                        source =
                            """
                            def: src
                            : 0xAABBCCDDE
                            """
                    in
                    checkForError ((==) IntegerHexOutOfBounds) source
            , test "Bit numbers cannot be negative" <|
                \_ ->
                    let
                        source =
                            """
                            def: src
                            : 0b0101-
                            """
                    in
                    checkForError ((==) ExpectedWhitespace) source
            , test "Bit numbers cannot use underscores" <|
                \_ ->
                    let
                        source =
                            """
                            def: src
                            : 0b11_00
                            """
                    in
                    checkForError ((==) ExpectedWhitespace) source
            , test "Bit numbers must contain at least one member" <|
                \_ ->
                    let
                        source =
                            """
                            def: src
                            : 0b
                            """
                    in
                    checkForError ((==) ExpectedBitInt) source
            , test "Bit numbers cannot contain more than 32 characters (32 bits)" <|
                \_ ->
                    let
                        source =
                            """
                            def: src
                            : 0b010101010101010101010101010101011
                            """
                    in
                    checkForError ((==) IntegerBitOutOfBounds) source
            ]
        ]


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