1 {-# LANGUAGE DeriveDataTypeable #-}
2 {-# LANGUAGE FlexibleContexts #-}
3 {-# LANGUAGE FlexibleInstances #-}
4 {-# LANGUAGE StandaloneDeriving #-}
5 {-# LANGUAGE TypeFamilies #-}
6 {-# OPTIONS_GHC -fno-warn-orphans #-}
7 module Hcompta.Filter.Amount.Read where
8 import Control.Applicative ((<$>), (<*))
9 import Control.Monad (Monad(..), guard, void)
12 import Data.Decimal (DecimalRaw(..))
13 import qualified Data.List as List
14 import Data.Maybe (Maybe(..))
15 import Data.Monoid (Monoid(..))
16 import Data.Ord (Ord(..))
17 import Data.String (String)
18 import qualified Data.Text as Text
19 import Data.Typeable ()
20 import Prelude (($), (.), fromIntegral, Num(..), id)
21 import qualified Text.Parsec as R hiding
33 import Text.Parsec (Stream, ParsecT, (<|>), (<?>))
35 import Hcompta.Filter.Amount
36 import qualified Hcompta.Lib.Parsec as R
37 import qualified Hcompta.Unit as Unit
41 quantity :: Stream s m Char => ParsecT s u m Quantity
44 (integral, fractional) <-
46 [ try_quantity '_' ',' '_' <* (R.notFollowedBy $ R.oneOf ",._")
47 , try_quantity '_' '.' '_' <* (R.notFollowedBy $ R.oneOf ",._")
48 , try_quantity ',' '.' '_' <* (R.notFollowedBy $ R.oneOf ",._")
49 , try_quantity '.' ',' '_' <* (R.notFollowedBy $ R.oneOf ",._")
51 let int = List.concat integral
52 let frac = List.concat fractional
53 let precision = List.length frac
54 guard (precision <= 255)
55 let mantissa = R.integer_of_digits 10 $ int `mappend` frac
58 (fromIntegral precision)
61 try_quantity int_group_sep frac_sep frac_group_sep = do
67 t <- R.many $ R.char int_group_sep >> R.many1 R.digit
72 _ -> R.option []) $ do
73 void $ R.char frac_sep
75 t <- R.many $ R.char frac_group_sep >> R.many1 R.digit
77 return ((integral::[String]), (fractional::[String]))
79 unit :: Stream s m Char => ParsecT s u m Unit
81 (quoted <|> unquoted) <?> "unit"
83 unquoted :: Stream s m Char => ParsecT s u m Unit
85 Unit . Text.pack <$> do
88 case Data.Char.generalCategory c of
89 Data.Char.CurrencySymbol -> True
90 Data.Char.LowercaseLetter -> True
91 Data.Char.ModifierLetter -> True
92 Data.Char.OtherLetter -> True
93 Data.Char.TitlecaseLetter -> True
94 Data.Char.UppercaseLetter -> True
96 quoted :: Stream s m Char => ParsecT s u m Unit
98 Unit . Text.pack <$> do
99 R.between (R.char '"') (R.char '"') $
103 -- | Parse either '-' into 'negate', or '+' or '' into 'id'.
104 sign :: (Stream s m Char, Num i) => ParsecT s u m (i -> i)
106 (R.char '-' >> return negate)
107 <|> (R.char '+' >> return id)
110 amount :: Stream s m Char => ParsecT s u m Amount
114 R.option Nothing $ do
116 R.skipMany R.space_horizontal
118 quantity_ <- quantity
123 R.option (Unit.unit_empty) $ R.try $ do
124 R.skipMany R.space_horizontal
128 { amount_quantity = left_signing quantity_
129 , amount_unit = unit_