Skip to content

Commit dda9379

Browse files
committed
Refactor in preparation for hex numbers
1 parent 9d10098 commit dda9379

File tree

2 files changed

+86
-37
lines changed

2 files changed

+86
-37
lines changed

src/Parse/Number.gren

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
module Parse.Number exposing
2-
( Format (..)
3-
, Outcome (..)
2+
( Outcome (..)
43
, Error (..)
54
, parser
65
)
@@ -9,14 +8,10 @@ module Parse.Number exposing
98
import Parser.Advanced as Parser exposing (Parser)
109

1110

12-
type Format
13-
= Decimal
14-
| Hex
15-
16-
1711
type Outcome
18-
= Integer { format: Format, value : Int }
12+
= Integer Int
1913
| FloatingPoint Float
14+
| Hex Int
2015

2116

2217
type Error
@@ -27,41 +22,84 @@ type Error
2722

2823
parser : Parser c Error Outcome
2924
parser =
30-
Parser.chompIf (\c -> c == '-' || Char.isDigit c) NotANumber
31-
|> Parser.skip (Parser.chompWhile Char.isDigit)
32-
|> Parser.getChompedString
25+
Parser.oneOf
26+
[ Parser.succeed
27+
(\outcome ->
28+
when outcome is
29+
Integer int ->
30+
Integer (negate int)
31+
32+
FloatingPoint float ->
33+
FloatingPoint (negate float)
34+
35+
Hex hex ->
36+
Hex (negate hex)
37+
)
38+
|> Parser.skip (Parser.symbol negateSign)
39+
|> Parser.keep numParser
40+
, numParser
41+
]
3342
|> Parser.andThen
34-
(\str ->
35-
if String.count str > 1 && (String.startsWith "0" str || String.startsWith "-0" str) then
36-
Parser.problem LeadingZero
43+
(\successCase ->
44+
Parser.oneOf
45+
[ Parser.chompIf Char.isAlpha NotANumber
46+
|> Parser.andThen (\_ -> Parser.problem NotANumber)
47+
, Parser.succeed successCase
48+
]
49+
)
50+
3751

38-
else
52+
negateSign : Parser.Token Error
53+
negateSign =
54+
Parser.Token { str = "-", expecting = NotANumber }
55+
56+
57+
numParser : Parser c Error Outcome
58+
numParser =
59+
Parser.oneOf
60+
[ Parser.chompIf (\c -> c == '0') NotANumber
61+
|> Parser.andThen
62+
(\_ ->
63+
Parser.oneOf
64+
[ Parser.chompIf (\c -> c == 'x') NotANumber
65+
|> Parser.andThen (\_ -> Parser.succeed (Hex 0))
66+
, Parser.chompIf (\c -> c == '.') NotANumber
67+
|> Parser.andThen (\_ -> fractalParser "0")
68+
, Parser.chompIf Char.isDigit NotANumber
69+
|> Parser.andThen (\_ -> Parser.problem LeadingZero)
70+
, Parser.succeed (Integer 0)
71+
]
72+
)
73+
, Parser.chompIf Char.isDigit NotANumber
74+
|> Parser.skip (Parser.chompWhile Char.isDigit)
75+
|> Parser.getChompedString
76+
|> Parser.andThen
77+
(\str ->
3978
when String.toInt str is
4079
Nothing ->
4180
Parser.problem NotANumber
4281

4382
Just num ->
4483
Parser.oneOf
4584
[ Parser.chompIf (\c -> c == '.') NotANumber
46-
|> Parser.skip (Parser.chompWhile Char.isDigit)
47-
|> Parser.getChompedString
48-
|> Parser.andThen
49-
(\postDot ->
50-
if postDot == "." then
51-
Parser.problem TerminatingDot
52-
53-
else
54-
when String.toFloat (str ++ postDot) is
55-
Nothing ->
56-
Parser.problem NotANumber
57-
58-
Just float ->
59-
Parser.succeed (FloatingPoint float)
60-
)
61-
, Parser.succeed <|
62-
Integer
63-
{ format = Decimal
64-
, value = num
65-
}
85+
|> Parser.andThen (\_ -> fractalParser str)
86+
, Parser.succeed (Integer num)
6687
]
88+
)
89+
]
90+
91+
92+
fractalParser : String -> Parser c Error Outcome
93+
fractalParser str =
94+
Parser.chompIf Char.isDigit TerminatingDot
95+
|> Parser.skip (Parser.chompWhile Char.isDigit)
96+
|> Parser.getChompedString
97+
|> Parser.andThen
98+
(\postDot ->
99+
when String.toFloat (str ++ "." ++ postDot) is
100+
Nothing ->
101+
Parser.problem NotANumber
102+
103+
Just float ->
104+
Parser.succeed (FloatingPoint float)
67105
)

tests/src/Test/Parse/Number.gren

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ tests =
1313
[ describe "Integers"
1414
[ fuzz Fuzz.int "Can parse regular integers" <| \int ->
1515
run (String.fromInt int)
16-
|> Expect.equal (Ok (PN.Integer { format = PN.Decimal, value = int }))
16+
|> Expect.equal (Ok (PN.Integer int))
1717
, test "empty string fails" <| \{} ->
1818
run ""
1919
|> expectErr PN.NotANumber
@@ -23,14 +23,17 @@ tests =
2323
, test "leading negative 0 fails" <| \{} ->
2424
run "-012"
2525
|> expectErr PN.LeadingZero
26+
, test "when followed by letter, it fails" <| \{} ->
27+
run "123a"
28+
|> expectErr PN.NotANumber
2629
]
2730
, describe "Floats"
2831
[ fuzz (Fuzz.floatRange 0 32000) "Can parse regular floats" <| \float ->
2932
run (String.fromFloat float)
3033
|> Result.map
3134
(\outcome ->
3235
when outcome is
33-
PN.Integer { value } ->
36+
PN.Integer value ->
3437
PN.FloatingPoint (toFloat value)
3538

3639
_ ->
@@ -40,6 +43,14 @@ tests =
4043
, test "Requires a number after ." <| \{} ->
4144
run "0."
4245
|> expectErr PN.TerminatingDot
46+
, test "when followed by letter, it fails" <| \{} ->
47+
run "0.15a"
48+
|> expectErr PN.NotANumber
49+
]
50+
, describe "Hex"
51+
[ test "Can parse hex" <| \{} ->
52+
run "0xAFFE"
53+
|> Expect.equal (Ok (PN.Hex 45054))
4354
]
4455
]
4556

0 commit comments

Comments
 (0)