-- |

-- Module:      Data.Geo.Jord.Parser

-- Copyright:   (c) 2020 Cedric Liegeois

-- License:     BSD3

-- Maintainer:  Cedric Liegeois <ofmooseandmen@yahoo.fr>

-- Stability:   experimental

-- Portability: portable

--

-- internal 'ReadP' parsers.

module Data.Geo.Jord.Parser
    ( digits
    , double
    , integer
    , natural
    , number
    ) where

import Control.Applicative ((<|>))
import Data.Char (isDigit)
import Text.ParserCombinators.ReadP (ReadP, char, count, munch1, option, satisfy)

-- | Parses the given number of digits and returns the read 'Int'.

digits :: Int -> ReadP Int
digits :: Int -> ReadP Int
digits Int
n = (String -> Int) -> ReadP String -> ReadP Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> Int
forall a. Read a => String -> a
read (Int -> ReadP Char -> ReadP String
forall a. Int -> ReadP a -> ReadP [a]
count Int
n ReadP Char
digit)

-- | Parses optionally a @-@ followed by a 'natural'.'natural' and returns the read 'Double'.

double :: ReadP Double
double :: ReadP Double
double = do
    Double
s <- Double -> ReadP Double -> ReadP Double
forall a. a -> ReadP a -> ReadP a
option Double
1.0 ((Char -> Double) -> ReadP Char -> ReadP Double
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Char
_ -> -Double
1.0) (Char -> ReadP Char
char Char
'-'))
    Int
i <- ReadP Int
natural
    String
f <- Char -> ReadP Char
char Char
'.' ReadP Char -> ReadP String -> ReadP String
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (Char -> Bool) -> ReadP String
munch1 Char -> Bool
isDigit
    Double -> ReadP Double
forall (m :: * -> *) a. Monad m => a -> m a
return (Double
s Double -> Double -> Double
forall a. Num a => a -> a -> a
* (String -> Double
forall a. Read a => String -> a
read (Int -> String
forall a. Show a => a -> String
show Int
i String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"." String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
f) :: Double))

-- | Parses optionally a @-@ followed by a 'natural' and returns the read 'Int'.

integer :: ReadP Int
integer :: ReadP Int
integer = do
    Int
s <- Int -> ReadP Int -> ReadP Int
forall a. a -> ReadP a -> ReadP a
option Int
1 ((Char -> Int) -> ReadP Char -> ReadP Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Char
_ -> -Int
1) (Char -> ReadP Char
char Char
'-'))
    Int
p <- ReadP Int
natural
    Int -> ReadP Int
forall (m :: * -> *) a. Monad m => a -> m a
return (Int
s Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
p)

-- | Parses 1 or more 'digit's and returns the read 'Int'.

natural :: ReadP Int
natural :: ReadP Int
natural = (String -> Int) -> ReadP String -> ReadP Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> Int
forall a. Read a => String -> a
read ((Char -> Bool) -> ReadP String
munch1 Char -> Bool
isDigit)

-- | Parses an 'integer' or 'double' and returns the read 'Double'.

number :: ReadP Double
number :: ReadP Double
number = ReadP Double
double ReadP Double -> ReadP Double -> ReadP Double
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Int -> Double) -> ReadP Int -> ReadP Double
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral ReadP Int
integer

-- | Parses and returns a digit.

digit :: ReadP Char
digit :: ReadP Char
digit = (Char -> Bool) -> ReadP Char
satisfy Char -> Bool
isDigit