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
9 import Control.Applicative ((<$>), (<*))
10 import Control.Monad (Monad(..), guard, void)
13 import Data.Decimal (DecimalRaw(..))
14 import qualified Data.List as List
15 import Data.Maybe (Maybe(..))
16 import Data.Monoid (Monoid(..))
17 import Data.Ord (Ord(..))
18 import Data.String (String)
19 import qualified Data.Text as Text
20 import Data.Typeable ()
21 import Prelude (($), (.), fromIntegral, Num(..), id)
22 import qualified Text.Parsec as R hiding
34 import Text.Parsec (Stream, ParsecT, (<|>), (<?>))
36 import Hcompta.Filter.Amount
37 import qualified Hcompta.Lib.Parsec as R
38 import qualified Hcompta.Unit as Unit
42 quantity :: Stream s m Char => ParsecT s u m Quantity
45 (integral, fractional) <-
47 [ try_quantity '_' ',' '_' <* (R.notFollowedBy $ R.oneOf ",._")
48 , try_quantity '_' '.' '_' <* (R.notFollowedBy $ R.oneOf ",._")
49 , try_quantity ',' '.' '_' <* (R.notFollowedBy $ R.oneOf ",._")
50 , try_quantity '.' ',' '_' <* (R.notFollowedBy $ R.oneOf ",._")
52 let int = List.concat integral
53 let frac = List.concat fractional
54 let precision = List.length frac
55 guard (precision <= 255)
56 let mantissa = R.integer_of_digits 10 $ int `mappend` frac
59 (fromIntegral precision)
62 try_quantity int_group_sep frac_sep frac_group_sep = do
68 t <- R.many $ R.char int_group_sep >> R.many1 R.digit
73 _ -> R.option []) $ do
74 void $ R.char frac_sep
76 t <- R.many $ R.char frac_group_sep >> R.many1 R.digit
78 return ((integral::[String]), (fractional::[String]))
80 unit :: Stream s m Char => ParsecT s u m Unit
82 (quoted <|> unquoted) <?> "unit"
84 unquoted :: Stream s m Char => ParsecT s u m Unit
86 Unit . Text.pack <$> do
89 case Data.Char.generalCategory c of
90 Data.Char.CurrencySymbol -> True
91 Data.Char.LowercaseLetter -> True
92 Data.Char.ModifierLetter -> True
93 Data.Char.OtherLetter -> True
94 Data.Char.TitlecaseLetter -> True
95 Data.Char.UppercaseLetter -> True
97 quoted :: Stream s m Char => ParsecT s u m Unit
99 Unit . Text.pack <$> do
100 R.between (R.char '"') (R.char '"') $
104 -- | Parse either '-' into 'negate', or '+' or '' into 'id'.
105 sign :: (Stream s m Char, Num i) => ParsecT s u m (i -> i)
107 (R.char '-' >> return negate)
108 <|> (R.char '+' >> return id)
111 amount :: Stream s m Char => ParsecT s u m Amount
115 R.option Nothing $ do
117 R.skipMany R.space_horizontal
119 quantity_ <- quantity
124 R.option (Unit.unit_empty) $ R.try $ do
125 R.skipMany R.space_horizontal
129 { amount_quantity = left_signing quantity_
130 , amount_unit = unit_