packages feed

bytestring-lexing-0.3.0: src/Data/ByteString/Lex/Lazy/Double.x

{
-- Turn off some common warnings about Alex-generated code.
-- {-# OPTIONS_GHC -Wall -fno-warn-tabs -fno-warn-missing-signatures #-}
----------------------------------------------------------------
--                                                    2012.01.25
-- |
-- Module      :  Data.ByteString.Lex.Lazy.Double
-- Copyright   :  Copyright (c) 2008--2011 Don Stewart
-- License     :  BSD2/MIT
-- Maintainer  :  wren@community.haskell.org
-- Stability   :  stable
-- Portability :  Haskell98
--
-- Efficiently parse floating point literals from a 'ByteString'.
----------------------------------------------------------------

module Data.ByteString.Lex.Lazy.Double (readDouble) where

import qualified Data.ByteString.Lazy as LB
import qualified Data.ByteString      as SB
import Data.ByteString.Lex.Internal (strtod)
----------------------------------------------------------------
}

%wrapper "basic-bytestring"

$space       = [\ \t\xa0]
$digit       = 0-9
$octit       = 0-7
$hexit       = [$digit A-F a-f]

@sign        = [\-\+]
@decimal     = $digit+
@octal       = $octit+
@hexadecimal = $hexit+
@exponent    = [eE] [\-\+]? @decimal

@number      = @decimal
             | @decimal \. @decimal @exponent?
             | @decimal @exponent
             | 0[oO] @octal
             | 0[xX] @hexadecimal

lex :-

@sign? @number { strtod . strict }

{

-- | Parse the initial portion of the ByteString as a Double precision
-- floating point value. The expected form of the numeric literal
-- is given by:
--
-- * An optional '+' or '-' sign  
--
-- * Decimal digits, OR
--
-- * 0 [oO] and a sequence of octal digits, OR
--
-- * 0 [xX] and a sequence of hexadecimal digits, OR
--
-- * An optional decimal point, followed by a sequence of decimal digits, 
--
-- * And an optional exponent
--
-- The result is returned as a pair of a double-precision floating
-- point value and the remaining input, or @Nothing@ should no parse
-- be found.
--
-- For example, to sum a file of floating point numbers, one per line, 
--
-- > import qualified Data.ByteString.Char8  as S
-- > import qualified Data.ByteString.Unsafe as S
-- > import Data.ByteString.Lex.Double
-- > 
-- > main = print . go 0 =<< S.getContents
-- >   where
-- >     go n s = case readDouble s of
-- >                     Nothing       -> n
-- >                     Just (k,rest) -> go (n+k) (S.tail rest)
--
readDouble :: LB.ByteString -> Maybe (Double, LB.ByteString)
readDouble str = case alexScan ('\n', str) 0 of
    AlexEOF            -> Nothing
    AlexError _        -> Nothing
    AlexToken (_, rest) n _ ->
       case strtod . strict . LB.take (fromIntegral n) $ str of
         d -> Just $! (d , rest)

strict = SB.concat . LB.toChunks
}