Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 50 additions & 8 deletions src/Compiler/Parse/Number.gren
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import Compiler.Parse.Context exposing (Context)
-}
type Outcome
= Integer Int
| FloatingPoint Float
| FloatingPoint { val : Float, text : String }
| Hex Int


Expand Down Expand Up @@ -70,8 +70,8 @@ parser =
Integer int ->
Integer (negate int)

FloatingPoint float ->
FloatingPoint (negate float)
FloatingPoint record ->
FloatingPoint { record | val = negate record.val, text = "-" ++ record.text }

Hex hex ->
Hex (negate hex)
Expand Down Expand Up @@ -104,6 +104,7 @@ zeroOrHigher =
|> Parser.map Hex
, Parser.chompChar '.' NotANumber
|> Parser.andThen (\_ -> fractalParser "0")
, exponentParser "0"
, Parser.chompIf Char.isDigit NotANumber
|> Parser.andThen (\_ -> Parser.problem LeadingZero)
, Parser.succeed (Integer 0)
Expand All @@ -122,6 +123,7 @@ zeroOrHigher =
Parser.oneOf
[ Parser.chompChar '.' NotANumber
|> Parser.andThen (\_ -> fractalParser str)
, exponentParser str
, Parser.succeed (Integer num)
]
)
Expand All @@ -135,12 +137,52 @@ fractalParser str =
|> Parser.getChompedString
|> Parser.andThen
(\postDot ->
when String.toFloat (str ++ "." ++ postDot) is
Nothing ->
Parser.problem NotANumber
let
base = str ++ "." ++ postDot
in
Parser.oneOf
[ exponentParser base
, when String.toFloat base is
Nothing ->
Parser.problem NotANumber

Just float ->
Parser.succeed (FloatingPoint { val = float, text = base })
]
)

Just float ->
Parser.succeed (FloatingPoint float)

exponentParser : String -> Parser Context Error Outcome
exponentParser base =
Parser.chompIf (\c -> c == 'e' || c == 'E') NotANumber
|> Parser.getChompedString
|> Parser.andThen
(\eChar ->
Parser.oneOf
[ Parser.chompChar '+' NotANumber
|> Parser.getChompedString
, Parser.chompChar '-' NotANumber
|> Parser.getChompedString
, Parser.succeed ""
]
|> Parser.andThen
(\sign ->
Parser.chompIf Char.isDigit ExpectedInt
|> Parser.skip (Parser.chompWhile Char.isDigit)
|> Parser.getChompedString
|> Parser.andThen
(\expDigits ->
let
fullText = base ++ eChar ++ sign ++ expDigits
in
when String.toFloat fullText is
Nothing ->
Parser.problem NotANumber

Just float ->
Parser.succeed (FloatingPoint { val = float, text = fullText })
)
)
)

{-| A parser that only parses hex-encoded integers, like `0xAB`.
Expand Down
2 changes: 1 addition & 1 deletion tests/src/Test/Compiler/Parse/Expression.gren
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ tests =
)
, test "Float" <| \_ ->
Parser.run PE.parser Context.empty "3.14"
|> expectExpression (AST.NumberLiteral (Number.FloatingPoint 3.14))
|> expectExpression (AST.NumberLiteral (Number.FloatingPoint { val = 3.14, text = "3.14" }))
, test "Hex" <| \_ ->
Parser.run PE.parser Context.empty "0xDE"
|> expectExpression (AST.NumberLiteral (Number.Hex 0xDE))
Expand Down
35 changes: 32 additions & 3 deletions tests/src/Test/Compiler/Parse/Number.gren
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,49 @@ tests =
|> Result.map
(\outcome ->
when outcome is
PN.Integer value ->
PN.FloatingPoint (toFloat value)
PN.Integer value ->
PN.FloatingPoint { val = toFloat value, text = String.fromInt value }

_ ->
outcome
)
|> Expect.equal (Ok (PN.FloatingPoint float))
|> Expect.equal (Ok (PN.FloatingPoint { val = float, text = String.fromFloat float }))
, test "Requires a number after ." <| \{} ->
run "0."
|> expectErr PN.ExpectedInt
, test "when followed by letter, it fails" <| \{} ->
run "0.15a"
|> expectErr PN.NotANumber
]
, describe "Scientific notation"
[ test "integer with exponent" <| \{} ->
run "1e5"
|> Expect.equal (Ok (PN.FloatingPoint { val = 1.0e5, text = "1e5" }))
, test "zero with exponent" <| \{} ->
run "0e3"
|> Expect.equal (Ok (PN.FloatingPoint { val = 0.0e3, text = "0e3" }))
, test "decimal with exponent" <| \{} ->
run "1.5e3"
|> Expect.equal (Ok (PN.FloatingPoint { val = 1.5e3, text = "1.5e3" }))
, test "uppercase E" <| \{} ->
run "1.5E3"
|> Expect.equal (Ok (PN.FloatingPoint { val = 1.5e3, text = "1.5E3" }))
, test "explicit positive exponent" <| \{} ->
run "1.5e+3"
|> Expect.equal (Ok (PN.FloatingPoint { val = 1.5e3, text = "1.5e+3" }))
, test "negative exponent" <| \{} ->
run "1.5e-3"
|> Expect.equal (Ok (PN.FloatingPoint { val = 1.5e-3, text = "1.5e-3" }))
, test "negative number with exponent" <| \{} ->
run "-1.5e3"
|> Expect.equal (Ok (PN.FloatingPoint { val = -1.5e3, text = "-1.5e3" }))
, test "requires digits after e" <| \{} ->
run "1e"
|> expectErr PN.ExpectedInt
, test "requires digits after e sign" <| \{} ->
run "1e+"
|> expectErr PN.ExpectedInt
]
, describe "Hex"
[ test "Can parse hex" <| \{} ->
run "0xAFFE"
Expand Down
Loading