{-| Simple module to provide functions that read Fortran literals -} module Language.Fortran.Parser.Utils (readReal, readInteger) where import Data.Char import Numeric breakAtDot :: String -> (String, String) replaceDwithE :: Char -> Char readsToMaybe :: [(a, b)] -> Maybe a fixAtDot :: (String, String) -> (String, String) fixAtDot' :: (String, String) -> (String, String) combineAtDot :: (String, String) -> String -- | Convert a Fortran literal Real into a Haskell Double. readReal :: String -> Maybe Double readReal = readsToMaybe . reads . filter (/= '+') . combineAtDot . fixAtDot . breakAtDot . map replaceDwithE . takeWhile (/= '_') -- | Convert a Fortran literal Integer into a Haskell Integer. readInteger :: String -> Maybe Integer readInteger s = readsToMaybe $ case s' of 'b':_ -> readInt 2 (`elem` "01") digitToInt (drop 2 s') 'o':_ -> readInt 8 (`elem` ['0'..'7']) digitToInt (drop 2 s') 'z':_ -> readInt 16 (`elem` (['0'..'9'] ++ ['A'..'F'] ++ ['a'..'f'])) digitToInt (drop 2 s') _ -> readSigned readDec s' where s' = filter (/= '+') . takeWhile (/= '_') $ s fixAtDot' ("", r) = ("0", r) fixAtDot' ("-", r) = ("-0", r) fixAtDot' (l, "") = (l, "0") fixAtDot' (l, r0:r) | not (isDigit r0) = (l, '0':r0:r) fixAtDot' x = x combineAtDot (a, b) = a ++ "." ++ b fixAtDot x | x == x' = x | otherwise = fixAtDot x' where x' = fixAtDot' x breakAtDot = fmap (drop 1) . break (=='.') replaceDwithE 'd' = 'e' replaceDwithE c = c readsToMaybe r = case r of (x, _):_ -> Just x _ -> Nothing