journal: parse and store commodity formats
This commit is contained in:
parent
207922a023
commit
2c0ef877eb
@ -127,6 +127,7 @@ nulljournal :: Journal
|
|||||||
nulljournal = Journal { jmodifiertxns = []
|
nulljournal = Journal { jmodifiertxns = []
|
||||||
, jperiodictxns = []
|
, jperiodictxns = []
|
||||||
, jtxns = []
|
, jtxns = []
|
||||||
|
, jcommodities = M.fromList []
|
||||||
, open_timeclock_entries = []
|
, open_timeclock_entries = []
|
||||||
, jmarketprices = []
|
, jmarketprices = []
|
||||||
, final_comment_lines = []
|
, final_comment_lines = []
|
||||||
|
|||||||
@ -114,7 +114,9 @@ type CommoditySymbol = String
|
|||||||
data Commodity = Commodity {
|
data Commodity = Commodity {
|
||||||
csymbol :: CommoditySymbol,
|
csymbol :: CommoditySymbol,
|
||||||
cformat :: Maybe AmountStyle
|
cformat :: Maybe AmountStyle
|
||||||
} -- deriving (Eq,Ord,Typeable,Data,Generic)
|
} deriving (Show,Eq,Data,Generic) --,Ord,Typeable,Data,Generic)
|
||||||
|
|
||||||
|
instance NFData Commodity
|
||||||
|
|
||||||
data Amount = Amount {
|
data Amount = Amount {
|
||||||
acommodity :: CommoditySymbol,
|
acommodity :: CommoditySymbol,
|
||||||
@ -257,6 +259,8 @@ data Journal = Journal {
|
|||||||
jmodifiertxns :: [ModifierTransaction],
|
jmodifiertxns :: [ModifierTransaction],
|
||||||
jperiodictxns :: [PeriodicTransaction],
|
jperiodictxns :: [PeriodicTransaction],
|
||||||
jtxns :: [Transaction],
|
jtxns :: [Transaction],
|
||||||
|
jcommoditystyles :: M.Map CommoditySymbol AmountStyle, -- ^ commodities and formats inferred from journal amounts
|
||||||
|
jcommodities :: M.Map CommoditySymbol Commodity, -- ^ commodities and formats defined by commodity directives
|
||||||
open_timeclock_entries :: [TimeclockEntry],
|
open_timeclock_entries :: [TimeclockEntry],
|
||||||
jmarketprices :: [MarketPrice],
|
jmarketprices :: [MarketPrice],
|
||||||
final_comment_lines :: String, -- ^ any trailing comments from the journal file
|
final_comment_lines :: String, -- ^ any trailing comments from the journal file
|
||||||
@ -265,8 +269,7 @@ data Journal = Journal {
|
|||||||
-- any included journal files. The main file is
|
-- any included journal files. The main file is
|
||||||
-- first followed by any included files in the
|
-- first followed by any included files in the
|
||||||
-- order encountered.
|
-- order encountered.
|
||||||
filereadtime :: ClockTime, -- ^ when this journal was last read from its file(s)
|
filereadtime :: ClockTime -- ^ when this journal was last read from its file(s)
|
||||||
jcommoditystyles :: M.Map CommoditySymbol AmountStyle -- ^ how to display amounts in each commodity
|
|
||||||
} deriving (Eq, Typeable, Data, Generic)
|
} deriving (Eq, Typeable, Data, Generic)
|
||||||
|
|
||||||
instance NFData Journal
|
instance NFData Journal
|
||||||
|
|||||||
@ -25,7 +25,7 @@ reader should handle many ledger files as well. Example:
|
|||||||
|
|
||||||
-- {-# OPTIONS_GHC -F -pgmF htfpp #-}
|
-- {-# OPTIONS_GHC -F -pgmF htfpp #-}
|
||||||
|
|
||||||
{-# LANGUAGE CPP, RecordWildCards, NoMonoLocalBinds, ScopedTypeVariables, FlexibleContexts, TupleSections #-}
|
{-# LANGUAGE CPP, RecordWildCards, NamedFieldPuns, NoMonoLocalBinds, ScopedTypeVariables, FlexibleContexts, TupleSections #-}
|
||||||
|
|
||||||
module Hledger.Read.JournalReader (
|
module Hledger.Read.JournalReader (
|
||||||
|
|
||||||
@ -83,6 +83,7 @@ import Data.Char (isNumber)
|
|||||||
import Data.Functor.Identity
|
import Data.Functor.Identity
|
||||||
import Data.List.Compat
|
import Data.List.Compat
|
||||||
import Data.List.Split (wordsBy)
|
import Data.List.Split (wordsBy)
|
||||||
|
import qualified Data.Map.Strict as M
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Time.Calendar
|
import Data.Time.Calendar
|
||||||
import Data.Time.LocalTime
|
import Data.Time.LocalTime
|
||||||
@ -307,6 +308,7 @@ directivep = do
|
|||||||
,endaliasesdirectivep
|
,endaliasesdirectivep
|
||||||
,accountdirectivep
|
,accountdirectivep
|
||||||
,applyaccountdirectivep
|
,applyaccountdirectivep
|
||||||
|
,commoditydirectivep
|
||||||
,endapplyaccountdirectivep
|
,endapplyaccountdirectivep
|
||||||
,tagdirectivep
|
,tagdirectivep
|
||||||
,endtagdirectivep
|
,endtagdirectivep
|
||||||
@ -350,17 +352,58 @@ journalAddFile :: (FilePath,String) -> Journal -> Journal
|
|||||||
journalAddFile f j@Journal{files=fs} = j{files=fs++[f]}
|
journalAddFile f j@Journal{files=fs} = j{files=fs++[f]}
|
||||||
-- NOTE: first encountered file to left, to avoid a reverse
|
-- NOTE: first encountered file to left, to avoid a reverse
|
||||||
|
|
||||||
|
indentedlinep = many1 spacenonewline >> (rstrip <$> restofline)
|
||||||
|
|
||||||
accountdirectivep :: ErroringJournalParser JournalUpdate
|
accountdirectivep :: ErroringJournalParser JournalUpdate
|
||||||
accountdirectivep = do
|
accountdirectivep = do
|
||||||
string "account"
|
string "account"
|
||||||
many1 spacenonewline
|
many1 spacenonewline
|
||||||
acct <- accountnamep
|
acct <- accountnamep
|
||||||
newline
|
newline
|
||||||
let indentedline = many1 spacenonewline >> restofline
|
_ <- many indentedlinep
|
||||||
many indentedline
|
|
||||||
pushAccount acct
|
pushAccount acct
|
||||||
return $ ExceptT $ return $ Right id
|
return $ ExceptT $ return $ Right id
|
||||||
|
|
||||||
|
-- | Terminate parsing entirely, returning the given error message
|
||||||
|
-- with the current parse position prepended.
|
||||||
|
parserError :: String -> ErroringJournalParser a
|
||||||
|
parserError s = do
|
||||||
|
pos <- getPosition
|
||||||
|
parserErrorAt pos s
|
||||||
|
|
||||||
|
-- | Terminate parsing entirely, returning the given error message
|
||||||
|
-- with the given parse position prepended.
|
||||||
|
parserErrorAt :: SourcePos -> String -> ErroringJournalParser a
|
||||||
|
parserErrorAt pos s = do
|
||||||
|
throwError $ show pos ++ ":\n" ++ s
|
||||||
|
|
||||||
|
-- | Parse a commodity directive, containing 0 or more format subdirectives.
|
||||||
|
commoditydirectivep :: ErroringJournalParser JournalUpdate
|
||||||
|
commoditydirectivep = do
|
||||||
|
string "commodity"
|
||||||
|
many1 spacenonewline
|
||||||
|
sym <- commoditysymbolp
|
||||||
|
_ <- followingcommentp
|
||||||
|
mformat <- lastMay <$> many (indented $ formatdirectivep sym)
|
||||||
|
let comm = Commodity{csymbol=sym, cformat=mformat}
|
||||||
|
return $ ExceptT $ return $ Right $ \j -> j{jcommodities=M.insert sym comm $ jcommodities j}
|
||||||
|
|
||||||
|
indented = (many1 spacenonewline >>)
|
||||||
|
|
||||||
|
-- | Parse a format (sub)directive, throwing a parse error if its
|
||||||
|
-- symbol does not match the one given.
|
||||||
|
formatdirectivep :: CommoditySymbol -> ErroringJournalParser AmountStyle
|
||||||
|
formatdirectivep expectedsym = do
|
||||||
|
string "format"
|
||||||
|
many1 spacenonewline
|
||||||
|
pos <- getPosition
|
||||||
|
Amount{acommodity,astyle} <- amountp
|
||||||
|
_ <- followingcommentp
|
||||||
|
if acommodity==expectedsym
|
||||||
|
then return astyle
|
||||||
|
else parserErrorAt pos $
|
||||||
|
printf "commodity directive symbol \"%s\" and format directive symbol \"%s\" should be the same" expectedsym acommodity
|
||||||
|
|
||||||
applyaccountdirectivep :: ErroringJournalParser JournalUpdate
|
applyaccountdirectivep :: ErroringJournalParser JournalUpdate
|
||||||
applyaccountdirectivep = do
|
applyaccountdirectivep = do
|
||||||
string "apply" >> many1 spacenonewline >> string "account"
|
string "apply" >> many1 spacenonewline >> string "account"
|
||||||
@ -370,6 +413,11 @@ applyaccountdirectivep = do
|
|||||||
pushParentAccount parent
|
pushParentAccount parent
|
||||||
return $ ExceptT $ return $ Right id
|
return $ ExceptT $ return $ Right id
|
||||||
|
|
||||||
|
data Commodity2 = Commodity2 {
|
||||||
|
csymbol :: String,
|
||||||
|
cformat :: Maybe AmountStyle
|
||||||
|
} -- deriving (Eq,Ord,Typeable,Data,Generic)
|
||||||
|
|
||||||
endapplyaccountdirectivep :: ErroringJournalParser JournalUpdate
|
endapplyaccountdirectivep :: ErroringJournalParser JournalUpdate
|
||||||
endapplyaccountdirectivep = do
|
endapplyaccountdirectivep = do
|
||||||
string "end" >> many1 spacenonewline >> string "apply" >> many1 spacenonewline >> string "account"
|
string "end" >> many1 spacenonewline >> string "apply" >> many1 spacenonewline >> string "account"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user