numbers: Double Parser
This commit is contained in:
parent
f0e7a7fc43
commit
3b01fbca46
1 changed files with 111 additions and 0 deletions
|
@ -93,6 +93,63 @@ integerBase10 : Parser Integer
|
||||||
integerBase10 = integer base10
|
integerBase10 = integer base10
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Double
|
||||||
|
|
||||||
|
```idris
|
||||||
|
export
|
||||||
|
double : Base -> Parser Double
|
||||||
|
double b = do
|
||||||
|
starting_state <- save
|
||||||
|
integer <- integer
|
||||||
|
fraction <- tryMaybe fraction
|
||||||
|
exponent <- tryMaybe exponent
|
||||||
|
let str = case (fraction, exponent) of
|
||||||
|
(Nothing, Nothing) =>
|
||||||
|
integer
|
||||||
|
(Nothing, (Just exponent)) =>
|
||||||
|
"\{integer}e\{exponent}"
|
||||||
|
((Just fraction), Nothing) =>
|
||||||
|
"\{integer}.\{fraction}"
|
||||||
|
((Just fraction), (Just exponent)) =>
|
||||||
|
"\{integer}.\{fraction}e\{exponent}"
|
||||||
|
Just out <- pure $ parseDouble str
|
||||||
|
| _ =>
|
||||||
|
throw $ MkParseError starting_state "Std failed to parse as double: \{str}"
|
||||||
|
pure out
|
||||||
|
where
|
||||||
|
parseDigit : Parser Char
|
||||||
|
parseDigit = do
|
||||||
|
GotChar char <- parseChar (hasDigit b) id
|
||||||
|
| GotError e => throwParseError "\{show e} is not a digit"
|
||||||
|
| EndOfInput => throwParseError "End Of Input"
|
||||||
|
pure char
|
||||||
|
integer : Parser String
|
||||||
|
integer = do
|
||||||
|
sign <- tryMaybe $ parseExactChar '-'
|
||||||
|
error <- replaceError "Expected digit"
|
||||||
|
digits <- map forget $ atLeastOne error parseDigit
|
||||||
|
case sign of
|
||||||
|
Nothing => pure $ pack digits
|
||||||
|
Just x => pure $ pack (x :: digits)
|
||||||
|
fraction : Parser String
|
||||||
|
fraction = do
|
||||||
|
decimal <- parseExactChar '.'
|
||||||
|
error <- replaceError "Expected digit"
|
||||||
|
digits <- map forget $ atLeastOne error parseDigit
|
||||||
|
pure $ pack digits
|
||||||
|
exponent : Parser String
|
||||||
|
exponent = do
|
||||||
|
e <- parseTheseChars ['e', 'E']
|
||||||
|
sign <- parseTheseChars ['+', '-']
|
||||||
|
error <- replaceError "Expected digit"
|
||||||
|
digits <- map forget $ atLeastOne error parseDigit
|
||||||
|
pure . pack $ sign :: digits
|
||||||
|
|
||||||
|
export
|
||||||
|
doubleBase10 : Parser Double
|
||||||
|
doubleBase10 = double base10
|
||||||
|
```
|
||||||
|
|
||||||
## Unit tests
|
## Unit tests
|
||||||
|
|
||||||
Test roundtripping a value through the provided parser
|
Test roundtripping a value through the provided parser
|
||||||
|
@ -147,3 +204,57 @@ integerRoundTrip = pure $
|
||||||
&& !(roundtrip (-1234567890000) integerBase10)
|
&& !(roundtrip (-1234567890000) integerBase10)
|
||||||
&& !(roundtrip (-12345678901234567890) integerBase10)
|
&& !(roundtrip (-12345678901234567890) integerBase10)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Compare our parsing of a double to the standard library's
|
||||||
|
|
||||||
|
```idris
|
||||||
|
compareDouble : String -> IO Bool
|
||||||
|
compareDouble string = do
|
||||||
|
Just state <- newInternalIO string
|
||||||
|
| _ => do
|
||||||
|
putStrLn "Failed to produce parser for \{string}"
|
||||||
|
pure False
|
||||||
|
Right result <-
|
||||||
|
runEff (rundownFirst doubleBase10) [handleParserStateIO state] {m = IO}
|
||||||
|
| Left err => do
|
||||||
|
printLn err
|
||||||
|
pure False
|
||||||
|
putStrLn "Input: \{string} Output: \{show result}"
|
||||||
|
Just double' <- pure $ parseDouble string
|
||||||
|
| _ => do
|
||||||
|
printLn "Std failed to parse as double: \{string}"
|
||||||
|
pure False
|
||||||
|
pure $ result == double'
|
||||||
|
```
|
||||||
|
|
||||||
|
```idris
|
||||||
|
-- @@test Double Std Comparison
|
||||||
|
doubleRoundTrip : IO Bool
|
||||||
|
doubleRoundTrip = pure $
|
||||||
|
!(compareDouble "0")
|
||||||
|
&& !(compareDouble "1")
|
||||||
|
&& !(compareDouble "100")
|
||||||
|
&& !(compareDouble "1234")
|
||||||
|
&& !(compareDouble "1234567890")
|
||||||
|
&& !(compareDouble "1234567890000")
|
||||||
|
&& !(compareDouble "12345678901234567890")
|
||||||
|
&& !(compareDouble "-1")
|
||||||
|
&& !(compareDouble "-100")
|
||||||
|
&& !(compareDouble "-1234")
|
||||||
|
&& !(compareDouble "-1234567890")
|
||||||
|
&& !(compareDouble "-1234567890000")
|
||||||
|
&& !(compareDouble "-12345678901234567890")
|
||||||
|
&& !(compareDouble "0.0")
|
||||||
|
&& !(compareDouble "1.0")
|
||||||
|
&& !(compareDouble "-1.0")
|
||||||
|
&& !(compareDouble "-0.0")
|
||||||
|
&& !(compareDouble "-0.0")
|
||||||
|
&& !(compareDouble "0.1234")
|
||||||
|
&& !(compareDouble "0.01234")
|
||||||
|
&& !(compareDouble "-0.1234")
|
||||||
|
&& !(compareDouble "-0.01234")
|
||||||
|
&& !(compareDouble "1.234e+5")
|
||||||
|
&& !(compareDouble "1.234e-5")
|
||||||
|
&& !(compareDouble "-1.234e+5")
|
||||||
|
&& !(compareDouble "-1.234e-5")
|
||||||
|
```
|
||||||
|
|
Loading…
Add table
Reference in a new issue