lib: organise JournalReader a bit

This commit is contained in:
Simon Michael 2016-04-22 17:43:16 -07:00
parent 50aeb90596
commit 9946e7df88

View File

@ -1,6 +1,9 @@
-- {-# OPTIONS_GHC -F -pgmF htfpp #-} -- * doc
{-# LANGUAGE CPP, RecordWildCards, NoMonoLocalBinds, ScopedTypeVariables #-} -- lines beginning "-- *" are collapsible orgstruct nodes. Emacs users:
{-# LANGUAGE FlexibleContexts #-} -- (add-hook 'haskell-mode-hook
-- (lambda () (set-variable 'orgstruct-heading-prefix-regexp "-- " t))
-- 'orgstruct-mode)
{-| {-|
A reader for hledger's journal file format A reader for hledger's journal file format
@ -17,12 +20,19 @@ reader should handle many ledger files as well. Example:
-} -}
-- * module
-- {-# OPTIONS_GHC -F -pgmF htfpp #-}
{-# LANGUAGE CPP, RecordWildCards, NoMonoLocalBinds, ScopedTypeVariables, FlexibleContexts #-}
module Hledger.Read.JournalReader ( module Hledger.Read.JournalReader (
-- * Reader -- * Reader
reader, reader,
-- * Parsers used elsewhere
parseAndFinaliseJournal, -- * Parsing utils
genericSourcePos, genericSourcePos,
parseAndFinaliseJournal,
-- * Parsers used elsewhere
getParentAccount, getParentAccount,
journalp, journalp,
directivep, directivep,
@ -51,6 +61,7 @@ module Hledger.Read.JournalReader (
#endif #endif
) )
where where
-- * imports
import Prelude () import Prelude ()
import Prelude.Compat hiding (readFile) import Prelude.Compat hiding (readFile)
import qualified Control.Exception as C import qualified Control.Exception as C
@ -77,7 +88,7 @@ import Hledger.Data
import Hledger.Utils import Hledger.Utils
-- standard reader exports -- * reader
reader :: Reader reader :: Reader
reader = Reader format detect parse reader = Reader format detect parse
@ -96,7 +107,7 @@ detect f s
parse :: Maybe FilePath -> Bool -> FilePath -> String -> ExceptT String IO Journal parse :: Maybe FilePath -> Bool -> FilePath -> String -> ExceptT String IO Journal
parse _ = parseAndFinaliseJournal journalp parse _ = parseAndFinaliseJournal journalp
-- parsing utils -- * parsing utils
genericSourcePos :: SourcePos -> GenericSourcePos genericSourcePos :: SourcePos -> GenericSourcePos
genericSourcePos p = GenericSourcePos (sourceName p) (sourceLine p) (sourceColumn p) genericSourcePos p = GenericSourcePos (sourceName p) (sourceLine p) (sourceColumn p)
@ -110,7 +121,7 @@ combineJournalUpdates us = foldl' (flip (.)) id <$> sequence us
-- cf http://neilmitchell.blogspot.co.uk/2015/09/detecting-space-leaks.html -- cf http://neilmitchell.blogspot.co.uk/2015/09/detecting-space-leaks.html
-- $ ./devprof +RTS -K576K -xc -- $ ./devprof +RTS -K576K -xc
-- *** Exception (reporting due to +RTS -xc): (THUNK_STATIC), stack trace: -- Exception (reporting due to +RTS -xc): (THUNK_STATIC), stack trace:
-- Hledger.Read.JournalReader.combineJournalUpdates.\, -- Hledger.Read.JournalReader.combineJournalUpdates.\,
-- called from Hledger.Read.JournalReader.combineJournalUpdates, -- called from Hledger.Read.JournalReader.combineJournalUpdates,
-- called from Hledger.Read.JournalReader.fixedlotprice, -- called from Hledger.Read.JournalReader.fixedlotprice,
@ -222,7 +233,8 @@ getIndex = liftM ctxTransactionIndex getState
setIndex :: Stream [Char] m Char => Integer -> ParsecT [Char] JournalContext m () setIndex :: Stream [Char] m Char => Integer -> ParsecT [Char] JournalContext m ()
setIndex i = modifyState (\ctx -> ctx{ctxTransactionIndex=i}) setIndex i = modifyState (\ctx -> ctx{ctxTransactionIndex=i})
-- parsers -- * parsers
-- ** journal
-- | Top-level journal parser. Returns a single composite, I/O performing, -- | Top-level journal parser. Returns a single composite, I/O performing,
-- error-raising "JournalUpdate" (and final "JournalContext") which can be -- error-raising "JournalUpdate" (and final "JournalContext") which can be
@ -246,6 +258,8 @@ journalp = do
, multilinecommentp >> return (return id) , multilinecommentp >> return (return id)
] <?> "journal transaction or directive" ] <?> "journal transaction or directive"
-- ** directives
-- cf http://ledger-cli.org/3.0/doc/ledger3.html#Command-Directives -- cf http://ledger-cli.org/3.0/doc/ledger3.html#Command-Directives
directivep :: ParsecT [Char] JournalContext (ExceptT String IO) JournalUpdate directivep :: ParsecT [Char] JournalContext (ExceptT String IO) JournalUpdate
directivep = do directivep = do
@ -428,6 +442,8 @@ commodityconversiondirectivep = do
restofline restofline
return $ return id return $ return id
-- ** transactions
modifiertransactionp :: ParsecT [Char] JournalContext (ExceptT String IO) ModifierTransaction modifiertransactionp :: ParsecT [Char] JournalContext (ExceptT String IO) ModifierTransaction
modifiertransactionp = do modifiertransactionp = do
char '=' <?> "modifier transaction" char '=' <?> "modifier transaction"
@ -462,8 +478,6 @@ transactionp = do
setIndex i' setIndex i'
return $ txnTieKnot $ Transaction i' sourcepos date edate status code description comment tags postings "" return $ txnTieKnot $ Transaction i' sourcepos date edate status code description comment tags postings ""
descriptionp = many (noneOf ";\n")
#ifdef TESTS #ifdef TESTS
test_transactionp = do test_transactionp = do
let s `gives` t = do let s `gives` t = do
@ -557,6 +571,22 @@ test_transactionp = do
assertEqual 2 (let Right t = p in length $ tpostings t) assertEqual 2 (let Right t = p in length $ tpostings t)
#endif #endif
statusp :: Stream [Char] m Char => ParsecT [Char] JournalContext m ClearedStatus
statusp =
choice'
[ many spacenonewline >> char '*' >> return Cleared
, many spacenonewline >> char '!' >> return Pending
, return Uncleared
]
<?> "cleared status"
codep :: Stream [Char] m Char => ParsecT [Char] JournalContext m String
codep = try (do { many1 spacenonewline; char '(' <?> "codep"; code <- anyChar `manyTill` char ')'; return code } ) <|> return ""
descriptionp = many (noneOf ";\n")
-- ** dates
-- | Parse a date in YYYY/MM/DD format. -- | Parse a date in YYYY/MM/DD format.
-- Hyphen (-) and period (.) are also allowed as separators. -- Hyphen (-) and period (.) are also allowed as separators.
-- The year may be omitted if a default year has been set. -- The year may be omitted if a default year has been set.
@ -632,17 +662,7 @@ secondarydatep primarydate = do
edate <- withDefaultYear primarydate datep edate <- withDefaultYear primarydate datep
return edate return edate
statusp :: Stream [Char] m Char => ParsecT [Char] JournalContext m ClearedStatus -- ** postings
statusp =
choice'
[ many spacenonewline >> char '*' >> return Cleared
, many spacenonewline >> char '!' >> return Pending
, return Uncleared
]
<?> "cleared status"
codep :: Stream [Char] m Char => ParsecT [Char] JournalContext m String
codep = try (do { many1 spacenonewline; char '(' <?> "codep"; code <- anyChar `manyTill` char ')'; return code } ) <|> return ""
-- Parse the following whitespace-beginning lines as postings, posting tags, and/or comments. -- Parse the following whitespace-beginning lines as postings, posting tags, and/or comments.
postingsp :: Stream [Char] m Char => ParsecT [Char] JournalContext m [Posting] postingsp :: Stream [Char] m Char => ParsecT [Char] JournalContext m [Posting]
@ -669,7 +689,7 @@ postingp = do
ctx <- getState ctx <- getState
comment <- try followingcommentp <|> (newline >> return "") comment <- try followingcommentp <|> (newline >> return "")
let tags = tagsInComment comment let tags = tagsInComment comment
-- oh boy -- parse any dates specified with tags here for good parse errors
date <- case dateValueFromTags tags of date <- case dateValueFromTags tags of
Nothing -> return Nothing Nothing -> return Nothing
Just v -> case runParser (datep <* eof) ctx "" v of Just v -> case runParser (datep <* eof) ctx "" v of
@ -739,6 +759,8 @@ test_postingp = do
-- assertEqual (Just nullmixedamt) (pbalanceassertion p) -- assertEqual (Just nullmixedamt) (pbalanceassertion p)
#endif #endif
-- ** account names
-- | Parse an account name, then apply any parent account prefix and/or account aliases currently in effect. -- | Parse an account name, then apply any parent account prefix and/or account aliases currently in effect.
modifiedaccountnamep :: Stream [Char] m Char => ParsecT [Char] JournalContext m AccountName modifiedaccountnamep :: Stream [Char] m Char => ParsecT [Char] JournalContext m AccountName
modifiedaccountnamep = do modifiedaccountnamep = do
@ -773,6 +795,8 @@ accountnamep = do
-- accountnamechar = notFollowedBy (oneOf "()[]") >> nonspace -- accountnamechar = notFollowedBy (oneOf "()[]") >> nonspace
-- <?> "account name character (non-bracket, non-parenthesis, non-whitespace)" -- <?> "account name character (non-bracket, non-parenthesis, non-whitespace)"
-- ** amounts
-- | Parse whitespace then an amount, with an optional left or right -- | Parse whitespace then an amount, with an optional left or right
-- currency symbol and optional price, or return the special -- currency symbol and optional price, or return the special
-- "missing" marker amount. -- "missing" marker amount.
@ -1016,7 +1040,7 @@ numberp = do
-- assertFails ".1," -- assertFails ".1,"
-- assertFails ",1." -- assertFails ",1."
-- comment parsers -- ** comments
multilinecommentp :: Stream [Char] m Char => ParsecT [Char] JournalContext m () multilinecommentp :: Stream [Char] m Char => ParsecT [Char] JournalContext m ()
multilinecommentp = do multilinecommentp = do
@ -1057,6 +1081,8 @@ commentStartingWithp cs = do
optional newline optional newline
return l return l
-- ** tags
tagsInComment :: String -> [Tag] tagsInComment :: String -> [Tag]
tagsInComment c = concatMap tagsInCommentLine $ lines c' tagsInComment c = concatMap tagsInCommentLine $ lines c'
where where
@ -1116,6 +1142,8 @@ dateValueFromTags ts = maybe Nothing (Just . snd) $ find ((=="date") . fst) ts
date2ValueFromTags ts = maybe Nothing (Just . snd) $ find ((=="date2") . fst) ts date2ValueFromTags ts = maybe Nothing (Just . snd) $ find ((=="date2") . fst) ts
-- * tests
tests_Hledger_Read_JournalReader = TestList $ concat [ tests_Hledger_Read_JournalReader = TestList $ concat [
-- test_numberp -- test_numberp
] ]
@ -1213,4 +1241,3 @@ tests_Hledger_Read_JournalReader = TestList $ concat [
]] ]]
-} -}