more general parser types enabling reuse outside of IO (#439)
This commit is contained in:
parent
31e4f538c0
commit
74502f7e50
@ -57,7 +57,7 @@ runJournalParser p t = runParserT p "" t
|
||||
rjp = runJournalParser
|
||||
|
||||
-- | Run an error-raising journal parser with a null journal-parsing state.
|
||||
runErroringJournalParser, rejp :: ErroringJournalParser a -> Text -> IO (Either String a)
|
||||
runErroringJournalParser, rejp :: Monad m => ErroringJournalParser m a -> Text -> m (Either String a)
|
||||
runErroringJournalParser p t =
|
||||
runExceptT $
|
||||
runJournalParser (evalStateT p mempty)
|
||||
@ -70,7 +70,8 @@ genericSourcePos p = GenericSourcePos (sourceName p) (fromIntegral . unPos $ sou
|
||||
|
||||
-- | Given a megaparsec ParsedJournal parser, balance assertion flag, file
|
||||
-- path and file content: parse and post-process a Journal, or give an error.
|
||||
parseAndFinaliseJournal :: ErroringJournalParser ParsedJournal -> Bool -> FilePath -> Text -> ExceptT String IO Journal
|
||||
parseAndFinaliseJournal :: ErroringJournalParser IO ParsedJournal -> Bool
|
||||
-> FilePath -> Text -> ExceptT String IO Journal
|
||||
parseAndFinaliseJournal parser assrt f txt = do
|
||||
t <- liftIO getClockTime
|
||||
y <- liftIO getCurrentYear
|
||||
@ -98,26 +99,26 @@ setYear y = modify' (\j -> j{jparsedefaultyear=Just y})
|
||||
getYear :: JournalStateParser m (Maybe Year)
|
||||
getYear = fmap jparsedefaultyear get
|
||||
|
||||
setDefaultCommodityAndStyle :: (CommoditySymbol,AmountStyle) -> ErroringJournalParser ()
|
||||
setDefaultCommodityAndStyle :: (CommoditySymbol,AmountStyle) -> JournalStateParser m ()
|
||||
setDefaultCommodityAndStyle cs = modify' (\j -> j{jparsedefaultcommodity=Just cs})
|
||||
|
||||
getDefaultCommodityAndStyle :: JournalStateParser m (Maybe (CommoditySymbol,AmountStyle))
|
||||
getDefaultCommodityAndStyle = jparsedefaultcommodity `fmap` get
|
||||
|
||||
pushAccount :: AccountName -> ErroringJournalParser ()
|
||||
pushAccount :: AccountName -> JournalStateParser m ()
|
||||
pushAccount acct = modify' (\j -> j{jaccounts = acct : jaccounts j})
|
||||
|
||||
pushParentAccount :: AccountName -> ErroringJournalParser ()
|
||||
pushParentAccount :: AccountName -> JournalStateParser m ()
|
||||
pushParentAccount acct = modify' (\j -> j{jparseparentaccounts = acct : jparseparentaccounts j})
|
||||
|
||||
popParentAccount :: ErroringJournalParser ()
|
||||
popParentAccount :: JournalStateParser m ()
|
||||
popParentAccount = do
|
||||
j <- get
|
||||
case jparseparentaccounts j of
|
||||
[] -> unexpected (Tokens ('E' :| "nd of apply account block with no beginning"))
|
||||
(_:rest) -> put j{jparseparentaccounts=rest}
|
||||
|
||||
getParentAccount :: ErroringJournalParser AccountName
|
||||
getParentAccount :: JournalStateParser m AccountName
|
||||
getParentAccount = fmap (concatAccountNames . reverse . jparseparentaccounts) get
|
||||
|
||||
addAccountAlias :: MonadState Journal m => AccountAlias -> m ()
|
||||
@ -155,7 +156,7 @@ journalAddFile f j@Journal{jfiles=fs} = j{jfiles=fs++[f]}
|
||||
|
||||
-- | Terminate parsing entirely, returning the given error message
|
||||
-- with the given parse position prepended.
|
||||
parserErrorAt :: SourcePos -> String -> ErroringJournalParser a
|
||||
parserErrorAt :: Monad m => SourcePos -> String -> ErroringJournalParser m a
|
||||
parserErrorAt pos s = throwError $ sourcePosPretty pos ++ ":\n" ++ s
|
||||
|
||||
--- * parsers
|
||||
@ -173,7 +174,7 @@ statusp =
|
||||
codep :: TextParser m String
|
||||
codep = try (do { some spacenonewline; char '(' <?> "codep"; anyChar `manyTill` char ')' } ) <|> return ""
|
||||
|
||||
descriptionp :: ErroringJournalParser String
|
||||
descriptionp :: JournalStateParser m String
|
||||
descriptionp = many (noneOf (";\n" :: [Char]))
|
||||
|
||||
--- ** dates
|
||||
@ -212,7 +213,7 @@ datep = do
|
||||
-- Seconds are optional.
|
||||
-- The timezone is optional and ignored (the time is always interpreted as a local time).
|
||||
-- Leading zeroes may be omitted (except in a timezone).
|
||||
datetimep :: ErroringJournalParser LocalTime
|
||||
datetimep :: JournalStateParser m LocalTime
|
||||
datetimep = do
|
||||
day <- datep
|
||||
lift $ some spacenonewline
|
||||
@ -240,7 +241,7 @@ datetimep = do
|
||||
-- return $ localTimeToUTC tz' $ LocalTime day $ TimeOfDay h' m' (fromIntegral s')
|
||||
return $ LocalTime day $ TimeOfDay h' m' (fromIntegral s')
|
||||
|
||||
secondarydatep :: Day -> ErroringJournalParser Day
|
||||
secondarydatep :: Day -> JournalStateParser m Day
|
||||
secondarydatep primarydate = do
|
||||
char '='
|
||||
-- kludgy way to use primary date for default year
|
||||
@ -266,7 +267,7 @@ secondarydatep primarydate = do
|
||||
--- ** account names
|
||||
|
||||
-- | Parse an account name, then apply any parent account prefix and/or account aliases currently in effect.
|
||||
modifiedaccountnamep :: ErroringJournalParser AccountName
|
||||
modifiedaccountnamep :: JournalStateParser m AccountName
|
||||
modifiedaccountnamep = do
|
||||
parent <- getParentAccount
|
||||
aliases <- getAccountAliases
|
||||
@ -305,7 +306,7 @@ accountnamep = do
|
||||
-- | Parse whitespace then an amount, with an optional left or right
|
||||
-- currency symbol and optional price, or return the special
|
||||
-- "missing" marker amount.
|
||||
spaceandamountormissingp :: ErroringJournalParser MixedAmount
|
||||
spaceandamountormissingp :: Monad m => JournalStateParser m MixedAmount
|
||||
spaceandamountormissingp =
|
||||
try (do
|
||||
lift $ some spacenonewline
|
||||
@ -426,7 +427,7 @@ priceamountp =
|
||||
return $ UnitPrice a))
|
||||
<|> return NoPrice
|
||||
|
||||
partialbalanceassertionp :: ErroringJournalParser (Maybe MixedAmount)
|
||||
partialbalanceassertionp :: Monad m => JournalStateParser m (Maybe MixedAmount)
|
||||
partialbalanceassertionp =
|
||||
try (do
|
||||
lift (many spacenonewline)
|
||||
@ -447,7 +448,7 @@ partialbalanceassertionp =
|
||||
-- <|> return Nothing
|
||||
|
||||
-- http://ledger-cli.org/3.0/doc/ledger3.html#Fixing-Lot-Prices
|
||||
fixedlotpricep :: ErroringJournalParser (Maybe Amount)
|
||||
fixedlotpricep :: Monad m => JournalStateParser m (Maybe Amount)
|
||||
fixedlotpricep =
|
||||
try (do
|
||||
lift (many spacenonewline)
|
||||
@ -547,7 +548,7 @@ numberp = do
|
||||
|
||||
--- ** comments
|
||||
|
||||
multilinecommentp :: ErroringJournalParser ()
|
||||
multilinecommentp :: JournalStateParser m ()
|
||||
multilinecommentp = do
|
||||
string "comment" >> lift (many spacenonewline) >> newline
|
||||
go
|
||||
@ -556,13 +557,13 @@ multilinecommentp = do
|
||||
<|> (anyLine >> go)
|
||||
anyLine = anyChar `manyTill` newline
|
||||
|
||||
emptyorcommentlinep :: ErroringJournalParser ()
|
||||
emptyorcommentlinep :: JournalStateParser m ()
|
||||
emptyorcommentlinep = do
|
||||
lift (many spacenonewline) >> (commentp <|> (lift (many spacenonewline) >> newline >> return ""))
|
||||
return ()
|
||||
|
||||
-- | Parse a possibly multi-line comment following a semicolon.
|
||||
followingcommentp :: ErroringJournalParser Text
|
||||
followingcommentp :: JournalStateParser m Text
|
||||
followingcommentp =
|
||||
-- ptrace "followingcommentp"
|
||||
do samelinecomment <- lift (many spacenonewline) >> (try semicoloncommentp <|> (newline >> return ""))
|
||||
@ -588,7 +589,8 @@ followingcommentp =
|
||||
-- >>> rejp (followingcommentandtagsp (Just $ fromGregorian 2000 1 2)) "; date:3/4=5/6"
|
||||
-- Right ("date:3/4=5/6\n",[("date","3/4=5/6")],Just 2000-03-04,Nothing)
|
||||
--
|
||||
followingcommentandtagsp :: Maybe Day -> ErroringJournalParser (Text, [Tag], Maybe Day, Maybe Day)
|
||||
followingcommentandtagsp :: MonadIO m => Maybe Day
|
||||
-> ErroringJournalParser m (Text, [Tag], Maybe Day, Maybe Day)
|
||||
followingcommentandtagsp mdefdate = do
|
||||
-- pdbg 0 "followingcommentandtagsp"
|
||||
|
||||
@ -623,16 +625,16 @@ followingcommentandtagsp mdefdate = do
|
||||
|
||||
return (comment, tags, mdate, mdate2)
|
||||
|
||||
commentp :: ErroringJournalParser Text
|
||||
commentp :: JournalStateParser m Text
|
||||
commentp = commentStartingWithp commentchars
|
||||
|
||||
commentchars :: [Char]
|
||||
commentchars = "#;*"
|
||||
|
||||
semicoloncommentp :: ErroringJournalParser Text
|
||||
semicoloncommentp :: JournalStateParser m Text
|
||||
semicoloncommentp = commentStartingWithp ";"
|
||||
|
||||
commentStartingWithp :: [Char] -> ErroringJournalParser Text
|
||||
commentStartingWithp :: [Char] -> JournalStateParser m Text
|
||||
commentStartingWithp cs = do
|
||||
-- ptrace "commentStartingWith"
|
||||
oneOf cs
|
||||
@ -714,7 +716,7 @@ tagvaluep = do
|
||||
-- are parsed fully to give useful errors. Missing years can be
|
||||
-- inferred only if a default date is provided.
|
||||
--
|
||||
postingdatesp :: Maybe Day -> ErroringJournalParser [(TagName,Day)]
|
||||
postingdatesp :: Monad m => Maybe Day -> ErroringJournalParser m [(TagName,Day)]
|
||||
postingdatesp mdefdate = do
|
||||
-- pdbg 0 $ "postingdatesp"
|
||||
let p = ((:[]) <$> datetagp mdefdate) <|> bracketeddatetagsp mdefdate
|
||||
@ -739,7 +741,7 @@ postingdatesp mdefdate = do
|
||||
-- >>> rejp (datetagp Nothing) "date: 3/4"
|
||||
-- Left ...1:9...partial date 3/4 found, but the current year is unknown...
|
||||
--
|
||||
datetagp :: Maybe Day -> ErroringJournalParser (TagName,Day)
|
||||
datetagp :: Monad m => Maybe Day -> ErroringJournalParser m (TagName,Day)
|
||||
datetagp mdefdate = do
|
||||
-- pdbg 0 "datetagp"
|
||||
string "date"
|
||||
@ -795,7 +797,7 @@ datetagp mdefdate = do
|
||||
-- >>> rejp (bracketeddatetagsp Nothing) "[0123456789/-.=/-.=]"
|
||||
-- Left ...1:15:...bad date, different separators...
|
||||
--
|
||||
bracketeddatetagsp :: Maybe Day -> ErroringJournalParser [(TagName, Day)]
|
||||
bracketeddatetagsp :: Monad m => Maybe Day -> ErroringJournalParser m [(TagName, Day)]
|
||||
bracketeddatetagsp mdefdate = do
|
||||
-- pdbg 0 "bracketeddatetagsp"
|
||||
char '['
|
||||
|
||||
@ -127,7 +127,7 @@ parse _ = parseAndFinaliseJournal journalp
|
||||
-- >>> rejp (journalp <* eof) "2015/1/1\n a 0\n"
|
||||
-- Right Journal with 1 transactions, 1 accounts
|
||||
--
|
||||
journalp :: ErroringJournalParser ParsedJournal
|
||||
journalp :: MonadIO m => ErroringJournalParser m ParsedJournal
|
||||
journalp = do
|
||||
many addJournalItemP
|
||||
eof
|
||||
@ -135,7 +135,7 @@ journalp = do
|
||||
|
||||
-- | A side-effecting parser; parses any kind of journal item
|
||||
-- and updates the parse state accordingly.
|
||||
addJournalItemP :: ErroringJournalParser ()
|
||||
addJournalItemP :: MonadIO m => ErroringJournalParser m ()
|
||||
addJournalItemP =
|
||||
-- all journal line types can be distinguished by the first
|
||||
-- character, can use choice without backtracking
|
||||
@ -154,7 +154,7 @@ addJournalItemP =
|
||||
-- | Parse any journal directive and update the parse state accordingly.
|
||||
-- Cf http://hledger.org/manual.html#directives,
|
||||
-- http://ledger-cli.org/3.0/doc/ledger3.html#Command-Directives
|
||||
directivep :: ErroringJournalParser ()
|
||||
directivep :: MonadIO m => ErroringJournalParser m ()
|
||||
directivep = (do
|
||||
optional $ char '!'
|
||||
choiceInState [
|
||||
@ -174,7 +174,7 @@ directivep = (do
|
||||
]
|
||||
) <?> "directive"
|
||||
|
||||
includedirectivep :: ErroringJournalParser ()
|
||||
includedirectivep :: MonadIO m => ErroringJournalParser m ()
|
||||
includedirectivep = do
|
||||
string "include"
|
||||
lift (some spacenonewline)
|
||||
@ -227,15 +227,17 @@ orRethrowIOError io msg =
|
||||
(Right <$> io)
|
||||
`C.catch` \(e::C.IOException) -> return $ Left $ printf "%s:\n%s" msg (show e)
|
||||
|
||||
accountdirectivep :: ErroringJournalParser ()
|
||||
accountdirectivep :: JournalStateParser m ()
|
||||
accountdirectivep = do
|
||||
string "account"
|
||||
lift (some spacenonewline)
|
||||
acct <- lift accountnamep
|
||||
newline
|
||||
_ <- many indentedlinep
|
||||
many indentedlinep
|
||||
modify' (\j -> j{jaccounts = acct : jaccounts j})
|
||||
|
||||
|
||||
indentedlinep :: JournalStateParser m String
|
||||
indentedlinep = lift (some spacenonewline) >> (rstrip <$> lift restofline)
|
||||
|
||||
-- | Parse a one-line or multi-line commodity directive.
|
||||
@ -244,14 +246,14 @@ indentedlinep = lift (some spacenonewline) >> (rstrip <$> lift restofline)
|
||||
-- >>> Right _ <- rejp commoditydirectivep "commodity $\n format $1.00"
|
||||
-- >>> Right _ <- rejp commoditydirectivep "commodity $\n\n" -- a commodity with no format
|
||||
-- >>> Right _ <- rejp commoditydirectivep "commodity $1.00\n format $1.00" -- both, what happens ?
|
||||
commoditydirectivep :: ErroringJournalParser ()
|
||||
commoditydirectivep :: Monad m => ErroringJournalParser m ()
|
||||
commoditydirectivep = try commoditydirectiveonelinep <|> commoditydirectivemultilinep
|
||||
|
||||
-- | Parse a one-line commodity directive.
|
||||
--
|
||||
-- >>> Right _ <- rejp commoditydirectiveonelinep "commodity $1.00"
|
||||
-- >>> Right _ <- rejp commoditydirectiveonelinep "commodity $1.00 ; blah\n"
|
||||
commoditydirectiveonelinep :: ErroringJournalParser ()
|
||||
commoditydirectiveonelinep :: Monad m => JournalStateParser m ()
|
||||
commoditydirectiveonelinep = do
|
||||
string "commodity"
|
||||
lift (some spacenonewline)
|
||||
@ -264,7 +266,7 @@ commoditydirectiveonelinep = do
|
||||
-- | Parse a multi-line commodity directive, containing 0 or more format subdirectives.
|
||||
--
|
||||
-- >>> Right _ <- rejp commoditydirectivemultilinep "commodity $ ; blah \n format $1.00 ; blah"
|
||||
commoditydirectivemultilinep :: ErroringJournalParser ()
|
||||
commoditydirectivemultilinep :: Monad m => ErroringJournalParser m ()
|
||||
commoditydirectivemultilinep = do
|
||||
string "commodity"
|
||||
lift (some spacenonewline)
|
||||
@ -278,7 +280,7 @@ commoditydirectivemultilinep = do
|
||||
|
||||
-- | Parse a format (sub)directive, throwing a parse error if its
|
||||
-- symbol does not match the one given.
|
||||
formatdirectivep :: CommoditySymbol -> ErroringJournalParser AmountStyle
|
||||
formatdirectivep :: Monad m => CommoditySymbol -> ErroringJournalParser m AmountStyle
|
||||
formatdirectivep expectedsym = do
|
||||
string "format"
|
||||
lift (some spacenonewline)
|
||||
@ -290,7 +292,7 @@ formatdirectivep expectedsym = do
|
||||
else parserErrorAt pos $
|
||||
printf "commodity directive symbol \"%s\" and format directive symbol \"%s\" should be the same" expectedsym acommodity
|
||||
|
||||
applyaccountdirectivep :: ErroringJournalParser ()
|
||||
applyaccountdirectivep :: JournalStateParser m ()
|
||||
applyaccountdirectivep = do
|
||||
string "apply" >> lift (some spacenonewline) >> string "account"
|
||||
lift (some spacenonewline)
|
||||
@ -298,12 +300,12 @@ applyaccountdirectivep = do
|
||||
newline
|
||||
pushParentAccount parent
|
||||
|
||||
endapplyaccountdirectivep :: ErroringJournalParser ()
|
||||
endapplyaccountdirectivep :: JournalStateParser m ()
|
||||
endapplyaccountdirectivep = do
|
||||
string "end" >> lift (some spacenonewline) >> string "apply" >> lift (some spacenonewline) >> string "account"
|
||||
popParentAccount
|
||||
|
||||
aliasdirectivep :: ErroringJournalParser ()
|
||||
aliasdirectivep :: JournalStateParser m ()
|
||||
aliasdirectivep = do
|
||||
string "alias"
|
||||
lift (some spacenonewline)
|
||||
@ -334,12 +336,12 @@ regexaliasp = do
|
||||
repl <- rstrip <$> anyChar `manyTill` eolof
|
||||
return $ RegexAlias re repl
|
||||
|
||||
endaliasesdirectivep :: ErroringJournalParser ()
|
||||
endaliasesdirectivep :: JournalStateParser m ()
|
||||
endaliasesdirectivep = do
|
||||
string "end aliases"
|
||||
clearAccountAliases
|
||||
|
||||
tagdirectivep :: ErroringJournalParser ()
|
||||
tagdirectivep :: JournalStateParser m ()
|
||||
tagdirectivep = do
|
||||
string "tag" <?> "tag directive"
|
||||
lift (some spacenonewline)
|
||||
@ -347,13 +349,13 @@ tagdirectivep = do
|
||||
lift restofline
|
||||
return ()
|
||||
|
||||
endtagdirectivep :: ErroringJournalParser ()
|
||||
endtagdirectivep :: JournalStateParser m ()
|
||||
endtagdirectivep = do
|
||||
(string "end tag" <|> string "pop") <?> "end tag or pop directive"
|
||||
lift restofline
|
||||
return ()
|
||||
|
||||
defaultyeardirectivep :: ErroringJournalParser ()
|
||||
defaultyeardirectivep :: JournalStateParser m ()
|
||||
defaultyeardirectivep = do
|
||||
char 'Y' <?> "default year"
|
||||
lift (many spacenonewline)
|
||||
@ -362,7 +364,7 @@ defaultyeardirectivep = do
|
||||
failIfInvalidYear y
|
||||
setYear y'
|
||||
|
||||
defaultcommoditydirectivep :: ErroringJournalParser ()
|
||||
defaultcommoditydirectivep :: Monad m => JournalStateParser m ()
|
||||
defaultcommoditydirectivep = do
|
||||
char 'D' <?> "default commodity"
|
||||
lift (some spacenonewline)
|
||||
@ -370,7 +372,7 @@ defaultcommoditydirectivep = do
|
||||
lift restofline
|
||||
setDefaultCommodityAndStyle (acommodity, astyle)
|
||||
|
||||
marketpricedirectivep :: ErroringJournalParser MarketPrice
|
||||
marketpricedirectivep :: Monad m => JournalStateParser m MarketPrice
|
||||
marketpricedirectivep = do
|
||||
char 'P' <?> "market price"
|
||||
lift (many spacenonewline)
|
||||
@ -382,7 +384,7 @@ marketpricedirectivep = do
|
||||
lift restofline
|
||||
return $ MarketPrice date symbol price
|
||||
|
||||
ignoredpricecommoditydirectivep :: ErroringJournalParser ()
|
||||
ignoredpricecommoditydirectivep :: JournalStateParser m ()
|
||||
ignoredpricecommoditydirectivep = do
|
||||
char 'N' <?> "ignored-price commodity"
|
||||
lift (some spacenonewline)
|
||||
@ -390,7 +392,7 @@ ignoredpricecommoditydirectivep = do
|
||||
lift restofline
|
||||
return ()
|
||||
|
||||
commodityconversiondirectivep :: ErroringJournalParser ()
|
||||
commodityconversiondirectivep :: Monad m => JournalStateParser m ()
|
||||
commodityconversiondirectivep = do
|
||||
char 'C' <?> "commodity conversion"
|
||||
lift (some spacenonewline)
|
||||
@ -404,7 +406,7 @@ commodityconversiondirectivep = do
|
||||
|
||||
--- ** transactions
|
||||
|
||||
modifiertransactionp :: ErroringJournalParser ModifierTransaction
|
||||
modifiertransactionp :: MonadIO m => ErroringJournalParser m ModifierTransaction
|
||||
modifiertransactionp = do
|
||||
char '=' <?> "modifier transaction"
|
||||
lift (many spacenonewline)
|
||||
@ -412,7 +414,7 @@ modifiertransactionp = do
|
||||
postings <- postingsp Nothing
|
||||
return $ ModifierTransaction valueexpr postings
|
||||
|
||||
periodictransactionp :: ErroringJournalParser PeriodicTransaction
|
||||
periodictransactionp :: MonadIO m => ErroringJournalParser m PeriodicTransaction
|
||||
periodictransactionp = do
|
||||
char '~' <?> "periodic transaction"
|
||||
lift (many spacenonewline)
|
||||
@ -421,7 +423,7 @@ periodictransactionp = do
|
||||
return $ PeriodicTransaction periodexpr postings
|
||||
|
||||
-- | Parse a (possibly unbalanced) transaction.
|
||||
transactionp :: ErroringJournalParser Transaction
|
||||
transactionp :: MonadIO m => ErroringJournalParser m Transaction
|
||||
transactionp = do
|
||||
-- ptrace "transactionp"
|
||||
sourcepos <- genericSourcePos <$> getPosition
|
||||
@ -533,7 +535,7 @@ test_transactionp = do
|
||||
|
||||
-- Parse the following whitespace-beginning lines as postings, posting
|
||||
-- tags, and/or comments (inferring year, if needed, from the given date).
|
||||
postingsp :: Maybe Day -> ErroringJournalParser [Posting]
|
||||
postingsp :: MonadIO m => Maybe Day -> ErroringJournalParser m [Posting]
|
||||
postingsp mdate = many (try $ postingp mdate) <?> "postings"
|
||||
|
||||
-- linebeginningwithspaces :: Monad m => JournalParser m String
|
||||
@ -543,7 +545,7 @@ postingsp mdate = many (try $ postingp mdate) <?> "postings"
|
||||
-- cs <- lift restofline
|
||||
-- return $ sp ++ (c:cs) ++ "\n"
|
||||
|
||||
postingp :: Maybe Day -> ErroringJournalParser Posting
|
||||
postingp :: MonadIO m => Maybe Day -> ErroringJournalParser m Posting
|
||||
postingp mtdate = do
|
||||
-- pdbg 0 "postingp"
|
||||
lift (some spacenonewline)
|
||||
|
||||
@ -82,7 +82,7 @@ reader = Reader
|
||||
parse :: Maybe FilePath -> Bool -> FilePath -> Text -> ExceptT String IO Journal
|
||||
parse _ = parseAndFinaliseJournal timeclockfilep
|
||||
|
||||
timeclockfilep :: ErroringJournalParser ParsedJournal
|
||||
timeclockfilep :: ErroringJournalParser IO ParsedJournal
|
||||
timeclockfilep = do many timeclockitemp
|
||||
eof
|
||||
j@Journal{jparsetimeclockentries=es} <- get
|
||||
@ -105,7 +105,7 @@ timeclockfilep = do many timeclockitemp
|
||||
] <?> "timeclock entry, or default year or historical price directive"
|
||||
|
||||
-- | Parse a timeclock entry.
|
||||
timeclockentryp :: ErroringJournalParser TimeclockEntry
|
||||
timeclockentryp :: JournalStateParser m TimeclockEntry
|
||||
timeclockentryp = do
|
||||
sourcepos <- genericSourcePos <$> lift getPosition
|
||||
code <- oneOf ("bhioO" :: [Char])
|
||||
|
||||
@ -51,6 +51,7 @@ import Hledger.Utils hiding (ptrace)
|
||||
-- easier to toggle this here sometimes
|
||||
-- import qualified Hledger.Utils (ptrace)
|
||||
-- ptrace = Hledger.Utils.ptrace
|
||||
ptrace :: Monad m => a -> m a
|
||||
ptrace = return
|
||||
|
||||
reader :: Reader
|
||||
@ -65,12 +66,12 @@ reader = Reader
|
||||
parse :: Maybe FilePath -> Bool -> FilePath -> Text -> ExceptT String IO Journal
|
||||
parse _ = parseAndFinaliseJournal timedotfilep
|
||||
|
||||
timedotfilep :: ErroringJournalParser ParsedJournal
|
||||
timedotfilep :: JournalStateParser m ParsedJournal
|
||||
timedotfilep = do many timedotfileitemp
|
||||
eof
|
||||
get
|
||||
where
|
||||
timedotfileitemp :: ErroringJournalParser ()
|
||||
timedotfileitemp :: JournalStateParser m ()
|
||||
timedotfileitemp = do
|
||||
ptrace "timedotfileitemp"
|
||||
choice [
|
||||
@ -88,7 +89,7 @@ addTransactions ts j = foldl' (flip ($)) j (map addTransaction ts)
|
||||
-- biz.research .
|
||||
-- inc.client1 .... .... .... .... .... ....
|
||||
-- @
|
||||
timedotdayp :: ErroringJournalParser [Transaction]
|
||||
timedotdayp :: JournalStateParser m [Transaction]
|
||||
timedotdayp = do
|
||||
ptrace " timedotdayp"
|
||||
d <- datep <* lift eolof
|
||||
@ -100,7 +101,7 @@ timedotdayp = do
|
||||
-- @
|
||||
-- fos.haskell .... ..
|
||||
-- @
|
||||
timedotentryp :: ErroringJournalParser Transaction
|
||||
timedotentryp :: JournalStateParser m Transaction
|
||||
timedotentryp = do
|
||||
ptrace " timedotentryp"
|
||||
pos <- genericSourcePos <$> getPosition
|
||||
@ -124,14 +125,14 @@ timedotentryp = do
|
||||
}
|
||||
return t
|
||||
|
||||
timedotdurationp :: ErroringJournalParser Quantity
|
||||
timedotdurationp :: JournalStateParser m Quantity
|
||||
timedotdurationp = try timedotnumberp <|> timedotdotsp
|
||||
|
||||
-- | Parse a duration written as a decimal number of hours (optionally followed by the letter h).
|
||||
-- @
|
||||
-- 1.5h
|
||||
-- @
|
||||
timedotnumberp :: ErroringJournalParser Quantity
|
||||
timedotnumberp :: JournalStateParser m Quantity
|
||||
timedotnumberp = do
|
||||
(q, _, _, _) <- lift numberp
|
||||
lift (many spacenonewline)
|
||||
@ -143,7 +144,7 @@ timedotnumberp = do
|
||||
-- @
|
||||
-- .... ..
|
||||
-- @
|
||||
timedotdotsp :: ErroringJournalParser Quantity
|
||||
timedotdotsp :: JournalStateParser m Quantity
|
||||
timedotdotsp = do
|
||||
dots <- filter (not.isSpace) <$> many (oneOf (". " :: [Char]))
|
||||
return $ (/4) $ fromIntegral $ length dots
|
||||
|
||||
@ -22,7 +22,7 @@ type JournalStateParser m a = StateT Journal (ParsecT Dec Text m) a
|
||||
type JournalParser a = StateT Journal (ParsecT Dec Text Identity) a
|
||||
|
||||
-- | A journal parser that runs in IO and can throw an error mid-parse.
|
||||
type ErroringJournalParser a = StateT Journal (ParsecT Dec Text (ExceptT String IO)) a
|
||||
type ErroringJournalParser m a = StateT Journal (ParsecT Dec Text (ExceptT String m)) a
|
||||
|
||||
-- | Backtracking choice, use this when alternatives share a prefix.
|
||||
-- Consumes no input if all choices fail.
|
||||
|
||||
@ -56,3 +56,5 @@ hledger print -f personal.journal -f a.timeclock -f b.timedot
|
||||
(b.bb) 1.00
|
||||
|
||||
>>>=0
|
||||
|
||||
u
|
||||
Loading…
Reference in New Issue
Block a user