on 4e34693 help sign in
624 lines 21 kB history raw
1{-# LANGUAGE CPP #-}
2-- |
3-- Module : Streamly.Internal.Unicode.Parser
4-- Copyright : (c) 2021 Composewell Technologies
5-- License : BSD-3-Clause
6-- Maintainer : streamly@composewell.com
7-- Stability : experimental
8-- Portability : GHC
9--
10-- To parse a text input, use the decode routines from
11-- "Streamly.Unicode.Stream" module to convert an input byte stream to a
12-- Unicode Char stream and then use these parsers on the Char stream.
14module Streamly.Internal.Unicode.Parser
15 (
16 -- * Setup
17 -- | To execute the code examples provided in this module in ghci, please
18 -- run the following commands first.
19 --
20 -- $setup
22 -- * Generic
23 char
24 , charIgnoreCase
26 -- * Sequences
27 , string
28 , stringIgnoreCase
29 , dropSpace
30 , dropSpace1
32 -- * Classes
33 , alpha
34 , alphaNum
35 , letter
36 , ascii
37 , asciiLower
38 , asciiUpper
39 , latin1
40 , lower
41 , upper
42 , mark
43 , printable
44 , punctuation
45 , separator
46 , space
47 , symbol
49 -- digits
50 , digit
51 , octDigit
52 , hexDigit
53 , numeric
55 -- * Numeric
56 , signed
57 , number
58 , doubleParser
59 , double
60 , decimal
61 , hexadecimal
63 -- * Utilities
64 , mkDouble
65 )
66where
68import Control.Applicative (Alternative(..))
69import Data.Bits (Bits, (.|.), shiftL, (.&.))
70import Data.Char (ord)
71import Data.Ratio ((%))
72import Fusion.Plugin.Types (Fuse(..))
73import Streamly.Internal.Data.Parser (Parser(..), Initial(..), Step(..))
75import qualified Data.Char as Char
76import qualified Streamly.Data.Fold as Fold
77import qualified Streamly.Internal.Data.Parser as Parser
78 (
79 lmap
80 , satisfy
81 , listEq
82 , takeWhile1
83 , dropWhile
84 )
86#include "DocTestUnicodeParser.hs"
88--------------------------------------------------------------------------------
89-- Character classification
90--------------------------------------------------------------------------------
92-- XXX It may be possible to implement faster predicates for ASCII byte stream.
93-- We can measure if there is a signficant difference and if so we can add such
94-- predicates to Streamly.Unicode.Parser.Latin1.
95--
96#define CHAR_PARSER_SIG(NAME) NAME :: Monad m => Parser Char m Char
97-- XXX Need to use the predicates from Unicode.Char module/unicode-data package
98#define CHAR_PARSER(NAME, PREDICATE) NAME = Parser.satisfy Char.PREDICATE
99#define CHAR_PARSER_DOC(PREDICATE) -- | Match any character that satisfies 'Char.PREDICATE'
100#define CHAR_PARSER_INLINE(NAME) {-# INLINE NAME #-}
102CHAR_PARSER_DOC(isSpace)
103CHAR_PARSER_INLINE(space)
104CHAR_PARSER_SIG(space)
105CHAR_PARSER(space,isSpace)
107CHAR_PARSER_DOC(isLower)
108CHAR_PARSER_INLINE(lower)
109CHAR_PARSER_SIG(lower)
110CHAR_PARSER(lower,isLower)
112CHAR_PARSER_DOC(isUpper)
113CHAR_PARSER_INLINE(upper)
114CHAR_PARSER_SIG(upper)
115CHAR_PARSER(upper,isUpper)
117CHAR_PARSER_DOC(isAlpha)
118CHAR_PARSER_INLINE(alpha)
119CHAR_PARSER_SIG(alpha)
120CHAR_PARSER(alpha,isAlpha)
122CHAR_PARSER_DOC(isAlphaNum)
123CHAR_PARSER_INLINE(alphaNum)
124CHAR_PARSER_SIG(alphaNum)
125CHAR_PARSER(alphaNum,isAlphaNum)
127CHAR_PARSER_DOC(isPrint)
128CHAR_PARSER_INLINE(printable)
129CHAR_PARSER_SIG(printable)
130CHAR_PARSER(printable,isPrint)
132CHAR_PARSER_DOC(isDigit)
133CHAR_PARSER_INLINE(digit)
134CHAR_PARSER_SIG(digit)
135CHAR_PARSER(digit,isDigit)
137CHAR_PARSER_DOC(isOctDigit)
138CHAR_PARSER_INLINE(octDigit)
139CHAR_PARSER_SIG(octDigit)
140CHAR_PARSER(octDigit,isOctDigit)
142CHAR_PARSER_DOC(isHexDigit)
143CHAR_PARSER_INLINE(hexDigit)
144CHAR_PARSER_SIG(hexDigit)
145CHAR_PARSER(hexDigit,isHexDigit)
147CHAR_PARSER_DOC(isLetter)
148CHAR_PARSER_INLINE(letter)
149CHAR_PARSER_SIG(letter)
150CHAR_PARSER(letter,isLetter)
152CHAR_PARSER_DOC(isMark)
153CHAR_PARSER_INLINE(mark)
154CHAR_PARSER_SIG(mark)
155CHAR_PARSER(mark,isMark)
157CHAR_PARSER_DOC(isNumber)
158CHAR_PARSER_INLINE(numeric)
159CHAR_PARSER_SIG(numeric)
160CHAR_PARSER(numeric,isNumber)
162CHAR_PARSER_DOC(isPunctuation)
163CHAR_PARSER_INLINE(punctuation)
164CHAR_PARSER_SIG(punctuation)
165CHAR_PARSER(punctuation,isPunctuation)
167CHAR_PARSER_DOC(isSymbol)
168CHAR_PARSER_INLINE(symbol)
169CHAR_PARSER_SIG(symbol)
170CHAR_PARSER(symbol,isSymbol)
172CHAR_PARSER_DOC(isSeparator)
173CHAR_PARSER_INLINE(separator)
174CHAR_PARSER_SIG(separator)
175CHAR_PARSER(separator,isSeparator)
177CHAR_PARSER_DOC(isAscii)
178CHAR_PARSER_INLINE(ascii)
179CHAR_PARSER_SIG(ascii)
180CHAR_PARSER(ascii,isAscii)
182CHAR_PARSER_DOC(isLatin1)
183CHAR_PARSER_INLINE(latin1)
184CHAR_PARSER_SIG(latin1)
185CHAR_PARSER(latin1,isLatin1)
187CHAR_PARSER_DOC(isAsciiUpper)
188CHAR_PARSER_INLINE(asciiUpper)
189CHAR_PARSER_SIG(asciiUpper)
190CHAR_PARSER(asciiUpper,isAsciiUpper)
192CHAR_PARSER_DOC(isAsciiLower)
193CHAR_PARSER_INLINE(asciiLower)
194CHAR_PARSER_SIG(asciiLower)
195CHAR_PARSER(asciiLower,isAsciiLower)
197--------------------------------------------------------------------------------
198-- Character parsers
199--------------------------------------------------------------------------------
201-- | Match a specific character.
202{-# INLINE char #-}
203char :: Monad m => Char -> Parser Char m Char
204char c = Parser.satisfy (== c)
206-- XXX Case conversion may lead to change in number of chars
207-- | Match a specific character ignoring case.
208{-# INLINE charIgnoreCase #-}
209charIgnoreCase :: Monad m => Char -> Parser Char m Char
210charIgnoreCase c = Parser.lmap Char.toLower (Parser.satisfy (== Char.toLower c))
212--------------------------------------------------------------------------------
213-- Character sequences
214--------------------------------------------------------------------------------
216-- | Match the input with the supplied string and return it if successful.
217string :: Monad m => String -> Parser Char m String
218string = Parser.listEq
220-- XXX Not accurate unicode case conversion
221-- | Match the input with the supplied string and return it if successful.
222stringIgnoreCase :: Monad m => String -> Parser Char m String
223stringIgnoreCase s =
224 Parser.lmap Char.toLower (Parser.listEq (map Char.toLower s))
226-- | Drop /zero/ or more white space characters.
227dropSpace :: Monad m => Parser Char m ()
228dropSpace = Parser.dropWhile Char.isSpace
230-- | Drop /one/ or more white space characters.
231dropSpace1 :: Monad m => Parser Char m ()
232dropSpace1 = Parser.takeWhile1 Char.isSpace Fold.drain
234--------------------------------------------------------------------------------
235-- Numeric parsers
236--------------------------------------------------------------------------------
238-- XXX It should fail if the number is larger than the size of the type.
239--
240-- | Parse and decode an unsigned integral decimal number.
241{-# INLINE decimal #-}
242decimal :: (Monad m, Integral a) => Parser Char m a
243decimal = Parser.takeWhile1 Char.isDigit (Fold.foldl' step 0)
245 where
247 step a c = a * 10 + fromIntegral (ord c - 48)
249-- | Parse and decode an unsigned integral hexadecimal number. The hex digits
250-- @\'a\'@ through @\'f\'@ may be upper or lower case.
251--
252-- Note: This parser does not accept a leading @\"0x\"@ string.
253{-# INLINE hexadecimal #-}
254hexadecimal :: (Monad m, Integral a, Bits a) => Parser Char m a
255hexadecimal = Parser.takeWhile1 isHexDigit (Fold.foldl' step 0)
257 where
259 isHexDigit c =
260 (c >= '0' && c <= '9')
261 || (c >= 'a' && c <= 'f')
262 || (c >= 'A' && c <= 'F')
264 step a c
265 | w >= 48 && w <= 57 =
266 (a `shiftL` 4) .|. fromIntegral (w - 48)
267 | w >= 97 =
268 (a `shiftL` 4) .|. fromIntegral (w - 87)
269 | otherwise =
270 (a `shiftL` 4) .|. fromIntegral (w - 55)
272 where
274 w = ord c
276-- | Allow an optional leading @\'+\'@ or @\'-\'@ sign character before any
277-- parser.
278{-# INLINE signed #-}
279signed :: (Num a, Monad m) => Parser Char m a -> Parser Char m a
280signed p = (negate <$> (char '-' *> p)) <|> (char '+' *> p) <|> p
282-- XXX Change Multiplier to Sign
283type Multiplier = Int
285-- XXX We can use Int instead of Integer to make it twice as fast. But then we
286-- will have to truncate the significant digits before overflow occurs.
287type Number = Integer
288type DecimalPlaces = Int
289type PowerMultiplier = Int
290type Power = Int
292{-# ANN type ScientificParseState Fuse #-}
293data ScientificParseState
294 = SPInitial
295 | SPSign !Multiplier
296 | SPAfterSign !Multiplier !Number
297 | SPDot !Multiplier !Number
298 | SPAfterDot !Multiplier !Number !DecimalPlaces
299 | SPExponent !Multiplier !Number !DecimalPlaces
300 | SPExponentWithSign !Multiplier !Number !DecimalPlaces !PowerMultiplier
301 | SPAfterExponent !Multiplier !Number !DecimalPlaces !PowerMultiplier !Power
303-- | A generic parser for scientific notation of numbers. Returns (mantissa,
304-- exponent) tuple. The result can be mapped to 'Double' or any other number
305-- representation e.g. @Scientific@.
306--
307-- For example, using the @scientific@ package:
308-- >> parserScientific = uncurry Data.Scientific.scientific <$> 'number'
309{-# INLINE number #-}
310number :: Monad m => Parser Char m (Integer, Int)
311number = Parser (\s a -> return $ step s a) initial (return . extract)
313 where
315 intToInteger :: Int -> Integer
316 intToInteger = fromIntegral
318 combineNum buf num = buf * 10 + num
320 {-# INLINE initial #-}
321 initial = pure $ IPartial SPInitial
323 exitSPInitial msg =
324 "number: expecting sign or decimal digit, got " ++ msg
325 exitSPSign msg =
326 "number: expecting decimal digit, got " ++ msg
327 exitSPAfterSign multiplier num = (intToInteger multiplier * num, 0)
328 exitSPAfterDot multiplier num decimalPlaces =
329 ( intToInteger multiplier * num
330 , -decimalPlaces
331 )
332 exitSPAfterExponent mult num decimalPlaces powerMult powerNum =
333 let e = powerMult * powerNum - decimalPlaces
334 in (intToInteger mult * num, e)
336 {-# INLINE step #-}
337 step SPInitial val =
338 case val of
339 '+' -> Continue 0 (SPSign 1)
340 '-' -> Continue 0 $ (SPSign (-1))
341 _ -> do
342 let num = ord val - 48
343 if num >= 0 && num <= 9
344 then Partial 0 $ SPAfterSign 1 (intToInteger num)
345 else Error $ exitSPInitial $ show val
346 step (SPSign multiplier) val =
347 let num = ord val - 48
348 in if num >= 0 && num <= 9
349 then Partial 0 $ SPAfterSign multiplier (intToInteger num)
350 else Error $ exitSPSign $ show val
351 step (SPAfterSign multiplier buf) val =
352 case val of
353 '.' -> Continue 0 $ SPDot multiplier buf
354 'e' -> Continue 0 $ SPExponent multiplier buf 0
355 'E' -> Continue 0 $ SPExponent multiplier buf 0
356 _ ->
357 let num = ord val - 48
358 in if num >= 0 && num <= 9
359 then
360 Partial 0
361 $ SPAfterSign multiplier (combineNum buf (intToInteger num))
362 else Done 1 $ exitSPAfterSign multiplier buf
363 step (SPDot multiplier buf) val =
364 let num = ord val - 48
365 in if num >= 0 && num <= 9
366 then Partial 0 $ SPAfterDot multiplier (combineNum buf (intToInteger num)) 1
367 else Done 2 $ exitSPAfterSign multiplier buf
368 step (SPAfterDot multiplier buf decimalPlaces) val =
369 case val of
370 'e' -> Continue 0 $ SPExponent multiplier buf decimalPlaces
371 'E' -> Continue 0 $ SPExponent multiplier buf decimalPlaces
372 _ ->
373 let num = ord val - 48
374 in if num >= 0 && num <= 9
375 then
376 Partial 0
377 $ SPAfterDot
378 multiplier
379 (combineNum buf (intToInteger num))
380 (decimalPlaces + 1)
381 else Done 1 $ exitSPAfterDot multiplier buf decimalPlaces
382 step (SPExponent multiplier buf decimalPlaces) val =
383 case val of
384 '+' -> Continue 0 (SPExponentWithSign multiplier buf decimalPlaces 1)
385 '-' -> Continue 0 (SPExponentWithSign multiplier buf decimalPlaces (-1))
386 _ -> do
387 let num = ord val - 48
388 if num >= 0 && num <= 9
389 then Partial 0 $ SPAfterExponent multiplier buf decimalPlaces 1 num
390 else Done 2 $ exitSPAfterDot multiplier buf decimalPlaces
391 step (SPExponentWithSign mult buf decimalPlaces powerMult) val =
392 let num = ord val - 48
393 in if num >= 0 && num <= 9
394 then Partial 0 $ SPAfterExponent mult buf decimalPlaces powerMult num
395 else Done 3 $ exitSPAfterDot mult buf decimalPlaces
396 step (SPAfterExponent mult num decimalPlaces powerMult buf) val =
397 let n = ord val - 48
398 in if n >= 0 && n <= 9
399 then
400 Partial 0
401 $ SPAfterExponent
402 mult num decimalPlaces powerMult (combineNum buf n)
403 else
404 Done 1
405 $ exitSPAfterExponent mult num decimalPlaces powerMult buf
407 {-# INLINE extract #-}
408 extract SPInitial = Error $ exitSPInitial "end of input"
409 extract (SPSign _) = Error $ exitSPSign "end of input"
410 extract (SPAfterSign mult num) = Done 0 $ exitSPAfterSign mult num
411 extract (SPDot mult num) = Done 1 $ exitSPAfterSign mult num
412 extract (SPAfterDot mult num decimalPlaces) =
413 Done 0 $ exitSPAfterDot mult num decimalPlaces
414 extract (SPExponent mult num decimalPlaces) =
415 Done 1 $ exitSPAfterDot mult num decimalPlaces
416 extract (SPExponentWithSign mult num decimalPlaces _) =
417 Done 2 $ exitSPAfterDot mult num decimalPlaces
418 extract (SPAfterExponent mult num decimalPlaces powerMult powerNum) =
419 Done 0 $ exitSPAfterExponent mult num decimalPlaces powerMult powerNum
421type MantissaInt = Int
422type OverflowPower = Int
424{-# ANN type DoubleParseState Fuse #-}
425data DoubleParseState
426 = DPInitial
427 | DPSign !Multiplier
428 | DPAfterSign !Multiplier !MantissaInt !OverflowPower
429 | DPDot !Multiplier !MantissaInt !OverflowPower
430 | DPAfterDot !Multiplier !MantissaInt !OverflowPower
431 | DPExponent !Multiplier !MantissaInt !OverflowPower
432 | DPExponentWithSign !Multiplier !MantissaInt !OverflowPower !PowerMultiplier
433 | DPAfterExponent !Multiplier !MantissaInt !OverflowPower !PowerMultiplier !Power
435-- | A fast, custom parser for double precision flaoting point numbers. Returns
436-- (mantissa, exponent) tuple. This is much faster than 'number' because it
437-- assumes the number will fit in a 'Double' type and uses 'Int' representation
438-- to store mantissa.
439--
440-- Number larger than 'Double' may overflow. Int overflow is not checked in the
441-- exponent.
442--
443{-# INLINE doubleParser #-}
444doubleParser :: Monad m => Parser Char m (Int, Int)
445doubleParser = Parser (\s a -> return $ step s a) initial (return . extract)
447 where
449 -- XXX Assuming Int = Int64
451 -- Up to 58 bits Int won't overflow
452 -- ghci> (2^59-1)*10+9 :: Int
453 -- 5764607523034234879
454 mask :: Word
455 mask = 0x7c00000000000000 -- 58 bits, ignore the sign bit
457 {-# INLINE combineNum #-}
458 combineNum :: Int -> Int -> Int -> (Int, Int)
459 combineNum mantissa power num =
460 if fromIntegral mantissa .&. mask == 0
461 then (mantissa * 10 + num, power)
462 else (mantissa, power + 1)
464 {-# INLINE initial #-}
465 initial = pure $ IPartial DPInitial
467 exitDPInitial msg =
468 "number: expecting sign or decimal digit, got " ++ msg
469 exitDPSign msg =
470 "number: expecting decimal digit, got " ++ msg
471 exitDPAfterSign multiplier num opower = (fromIntegral multiplier * num, opower)
472 exitDPAfterDot multiplier num opow =
473 (fromIntegral multiplier * num , opow)
474 exitDPAfterExponent mult num opow powerMult powerNum =
475 (fromIntegral mult * num, opow + powerMult * powerNum)
477 {-# INLINE step #-}
478 step DPInitial val =
479 case val of
480 '+' -> Continue 0 (DPSign 1)
481 '-' -> Continue 0 $ (DPSign (-1))
482 _ -> do
483 let num = ord val - 48
484 if num >= 0 && num <= 9
485 then Partial 0 $ DPAfterSign 1 num 0
486 else Error $ exitDPInitial $ show val
487 step (DPSign multiplier) val =
488 let num = ord val - 48
489 in if num >= 0 && num <= 9
490 then Partial 0 $ DPAfterSign multiplier num 0
491 else Error $ exitDPSign $ show val
492 step (DPAfterSign multiplier buf opower) val =
493 case val of
494 '.' -> Continue 0 $ DPDot multiplier buf opower
495 'e' -> Continue 0 $ DPExponent multiplier buf opower
496 'E' -> Continue 0 $ DPExponent multiplier buf opower
497 _ ->
498 let num = ord val - 48
499 in if num >= 0 && num <= 9
500 then
501 let (buf1, power1) = combineNum buf opower num
502 in Partial 0
503 $ DPAfterSign multiplier buf1 power1
504 else Done 1 $ exitDPAfterSign multiplier buf opower
505 step (DPDot multiplier buf opower) val =
506 let num = ord val - 48
507 in if num >= 0 && num <= 9
508 then
509 let (buf1, power1) = combineNum buf opower num
510 in Partial 0 $ DPAfterDot multiplier buf1 (power1 - 1)
511 else Done 2 $ exitDPAfterSign multiplier buf opower
512 step (DPAfterDot multiplier buf opower) val =
513 case val of
514 'e' -> Continue 0 $ DPExponent multiplier buf opower
515 'E' -> Continue 0 $ DPExponent multiplier buf opower
516 _ ->
517 let num = ord val - 48
518 in if num >= 0 && num <= 9
519 then
520 let (buf1, power1) = combineNum buf opower num
521 in Partial 0 $ DPAfterDot multiplier buf1 (power1 - 1)
522 else Done 1 $ exitDPAfterDot multiplier buf opower
523 step (DPExponent multiplier buf opower) val =
524 case val of
525 '+' -> Continue 0 (DPExponentWithSign multiplier buf opower 1)
526 '-' -> Continue 0 (DPExponentWithSign multiplier buf opower (-1))
527 _ -> do
528 let num = ord val - 48
529 if num >= 0 && num <= 9
530 then Partial 0 $ DPAfterExponent multiplier buf opower 1 num
531 else Done 2 $ exitDPAfterDot multiplier buf opower
532 step (DPExponentWithSign mult buf opower powerMult) val =
533 let num = ord val - 48
534 in if num >= 0 && num <= 9
535 then Partial 0 $ DPAfterExponent mult buf opower powerMult num
536 else Done 3 $ exitDPAfterDot mult buf opower
537 step (DPAfterExponent mult num opower powerMult buf) val =
538 let n = ord val - 48
539 in if n >= 0 && n <= 9
540 then
541 Partial 0
542 $ DPAfterExponent mult num opower powerMult (buf * 10 + n)
543 else Done 1 $ exitDPAfterExponent mult num opower powerMult buf
545 {-# INLINE extract #-}
546 extract DPInitial = Error $ exitDPInitial "end of input"
547 extract (DPSign _) = Error $ exitDPSign "end of input"
548 extract (DPAfterSign mult num opow) = Done 0 $ exitDPAfterSign mult num opow
549 extract (DPDot mult num opow) = Done 1 $ exitDPAfterSign mult num opow
550 extract (DPAfterDot mult num opow) =
551 Done 0 $ exitDPAfterDot mult num opow
552 extract (DPExponent mult num opow) =
553 Done 1 $ exitDPAfterDot mult num opow
554 extract (DPExponentWithSign mult num opow _) =
555 Done 2 $ exitDPAfterDot mult num opow
556 extract (DPAfterExponent mult num opow powerMult powerNum) =
557 Done 0 $ exitDPAfterExponent mult num opow powerMult powerNum
559-- XXX We can have a `realFloat` parser instead to parse any RealFloat value.
560-- And a integral parser to read any integral value.
562-- XXX This is very expensive, takes much more time than the rest of the
563-- parsing. Need to look into fromRational.
565-- | @mkDouble mantissa exponent@ converts a mantissa and exponent to a
566-- 'Double' value equivalent to @mantissa * 10^exponent@. It does not check for
567-- overflow, powers more than 308 will overflow.
568{-# INLINE mkDouble #-}
569mkDouble :: Integer -> Int -> Double
570mkDouble mantissa power =
571 if power > 0
572 then fromRational ((mantissa * 10 ^ power) % 1)
573 else fromRational (mantissa % 10 ^ (-power))
575-- | Parse a decimal 'Double' value. This parser accepts an optional sign (+ or
576-- -) followed by at least one decimal digit. Decimal digits are optionally
577-- followed by a decimal point and at least one decimal digit after the point.
578-- This parser accepts the maximal valid input as long as it gives a valid
579-- number. Specifcally a trailing decimal point is allowed but not consumed.
580-- This function does not accept \"NaN\" or \"Infinity\" string representations
581-- of double values.
582--
583-- Definition:
584--
585-- >>> double = uncurry Unicode.mkDouble <$> Unicode.number
586--
587-- Examples:
588--
589-- >>> p = Stream.parse Unicode.double . Stream.fromList
590--
591-- >>> p "-1.23e-123"
592-- Right (-1.23e-123)
593--
594-- Trailing input examples:
595--
596-- >>> p "1."
597-- Right 1.0
598--
599-- >>> p "1.2.3"
600-- Right 1.2
601--
602-- >>> p "1e"
603-- Right 1.0
604--
605-- >>> p "1e2.3"
606-- Right 100.0
607--
608-- >>> p "1+2"
609-- Right 1.0
610--
611-- Error cases:
612--
613-- >>> p ""
614-- Left (ParseError "number: expecting sign or decimal digit, got end of input")
615--
616-- >>> p ".1"
617-- Left (ParseError "number: expecting sign or decimal digit, got '.'")
618--
619-- >>> p "+"
620-- Left (ParseError "number: expecting decimal digit, got end of input")
621--
622{-# INLINE double #-}
623double :: Monad m => Parser Char m Double
624double = fmap (\(m,e) -> mkDouble (fromIntegral m) e) doubleParser