From b377bff90aecd4f576bd8cc1e422dee1857f8f95 Mon Sep 17 00:00:00 2001 From: Mykola Orliuk Date: Fri, 9 Feb 2018 23:18:16 +0100 Subject: [PATCH] lib: support scientific number notation (#704, #706) closes simonmichael/hledger#704 --- hledger-lib/Hledger/Read/Common.hs | 18 +++++- tests/journal/scientific.test | 98 ++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 tests/journal/scientific.test diff --git a/hledger-lib/Hledger/Read/Common.hs b/hledger-lib/Hledger/Read/Common.hs index 89a85579a..aa9fc6edc 100644 --- a/hledger-lib/Hledger/Read/Common.hs +++ b/hledger-lib/Hledger/Read/Common.hs @@ -21,6 +21,7 @@ where --- * imports import Prelude () import Prelude.Compat hiding (readFile) +import Control.Arrow ((***)) import Control.Monad.Compat import Control.Monad.Except (ExceptT(..), runExceptT, throwError) --, catchError) import Control.Monad.State.Strict @@ -464,10 +465,12 @@ rightsymbolamountp = do m <- lift multiplierp sign <- lift signp rawnum <- lift $ rawnumberp + expMod <- lift . option id $ try exponentp commodityspaced <- lift $ skipMany' spacenonewline c <- lift commoditysymbolp suggestedStyle <- getAmountStyle c - let (q,prec,mdec,mgrps) = fromRawNumber suggestedStyle (sign == "-") rawnum + let (q0,prec0,mdec,mgrps) = fromRawNumber suggestedStyle (sign == "-") rawnum + (q, prec) = expMod (q0, prec0) p <- priceamountp let s = amountstyle{ascommodityside=R, ascommodityspaced=commodityspaced, asprecision=prec, asdecimalpoint=mdec, asdigitgroups=mgrps} return $ Amount c q p s m @@ -572,9 +575,20 @@ numberp suggestedStyle = do sign <- signp raw <- rawnumberp dbg8 "numberp parsed" raw `seq` return () - return $ dbg8 "numberp quantity,precision,mdecimalpoint,mgrps" (fromRawNumber suggestedStyle (sign == "-") raw) + let num@(q, prec, decSep, groups) = dbg8 "numberp quantity,precision,mdecimalpoint,mgrps" (fromRawNumber suggestedStyle (sign == "-") raw) + option num . try $ do + when (isJust groups) $ fail "groups and exponent are not mixable" + (q', prec') <- exponentp <*> pure (q, prec) + return (q', prec', decSep, groups) "numberp" +exponentp :: TextParser m ((Quantity, Int) -> (Quantity, Int)) +exponentp = do + char' 'e' + exp <- liftM read $ (++) <$> signp <*> some digitChar + return $ (* 10^^exp) *** (0 `max`) . (+ (-exp)) + "exponentp" + fromRawNumber :: Maybe AmountStyle -> Bool -> (Maybe Char, [String], Maybe (Char, String)) -> (Quantity, Int, Maybe Char, Maybe DigitGroupStyle) fromRawNumber suggestedStyle negated raw = (quantity, precision, mdecimalpoint, mgrps) where -- unpack with a hint if useful diff --git a/tests/journal/scientific.test b/tests/journal/scientific.test new file mode 100644 index 000000000..280dc6cff --- /dev/null +++ b/tests/journal/scientific.test @@ -0,0 +1,98 @@ +# just check +hledger -f - bal --no-total +<<< +D $1,000.00 + +2018/1/1 + (a) 2.3 +>>> + $2.30 a +>>>=0 + +# some basic cases with commodity +hledger -f - bal --no-total +<<< +commodity $1,000.00000000 + +2018/1/1 + a $1.05e2 + b $31415926e-7 + c $1E+3 + d +>>> + $105.00000000 a + $3.14159260 b + $1,000.00000000 c + $-1,108.14159260 d +>>>=0 + +# some basic cases with commodity +hledger -f - print --explicit +<<< +commodity $1,000.00000000 + +2018/1/1 + a $1.05e2 + b $31415926e-7 + c $1E+3 + d +>>> +2018/01/01 + a $105.00000000 + b $3.14159260 + c $1,000.00000000 + d $-1,108.14159260 + +>>>=0 +# +# some basic cases +hledger -f - bal --no-total +<<< +2018/1/1 + a 1.05e2 + b 31415926e-7 + c 1E+3 + d +>>> + 105.0000000 a + 3.1415926 b + 1000.0000000 c + -1108.1415926 d +>>>2 +>>>=0 + +# some strang effect of default +hledger -f - bal --no-total +<<< +D $1,000.00 + +2018/1/1 + a 1.050000e2 + b 31415926e-7 + c 1E+3 + d +>>> + $105.0000000 a + $3.1415926 b + $1,000.0000000 c + $-1,108.1415926 d +>>>2 +>>>=0 + +# we still should recognize commodities with e +hledger -f - bal --no-total +<<< +2018/1/1 + (a) 1.00005e + (a) 2.00003E +>>> + 2.00003E + 1.00005e a +>>>=0 + +hledger -f - reg +<<< +2018/1/1 + (a) 1,000.5e-1 +>>> +>>>=1