;csv: refactor amount parsing

This commit is contained in:
Simon Michael 2020-11-05 20:07:26 -10:00
parent dae007a372
commit 4242a8592a

View File

@ -1024,55 +1024,64 @@ getAmount rules record currency p1IsVirtual n =
"\t=> value: " ++ showMixedAmount a -- XXX not sure this is showing all the right info
| (f,a) <- fs]
where
-- | Given a non-empty amount string to parse, along with a possibly
-- non-empty currency symbol to prepend, parse as a hledger amount (as
-- in journal format), or raise an error.
-- The CSV rules and record are provided for the error message.
parseAmount :: CsvRules -> CsvRecord -> String -> String -> MixedAmount
parseAmount rules record currency amountstr =
either mkerror (Mixed . (:[])) $ -- PARTIAL:
runParser (evalStateT (amountp <* eof) nulljournal) "" $
T.pack $ (currency++) $ simplifySign amountstr
where
mkerror e = error' $ unlines
["error: could not parse \""++amountstr++"\" as an amount"
,showRecord record
,showRules rules record
-- ,"the default-currency is: "++fromMaybe "unspecified" (getDirective "default-currency" rules)
,"the parse error is: "++customErrorBundlePretty e
,"you may need to "
++"change your amount*, balance*, or currency* rules, "
++"or add or change your skip rule"
]
-- | Figure out the expected balance (assertion or assignment) specified for posting N,
-- if any (and its parse position).
getBalance :: CsvRules -> CsvRecord -> String -> Int -> Maybe (Amount, GenericSourcePos)
getBalance rules record currency n =
(fieldval ("balance"++show n)
-- for posting 1, also recognise the old field name
<|> if n==1 then fieldval "balance" else Nothing)
>>= parsebalance currency n . strip
getBalance rules record currency n = do
v <- (fieldval ("balance"++show n)
-- for posting 1, also recognise the old field name
<|> if n==1 then fieldval "balance" else Nothing)
case v of
"" -> Nothing
s -> Just (
parseBalanceAmount rules record currency n s
,nullsourcepos -- parse position to show when assertion fails,
) -- XXX the csv record's line number would be good
where
parsebalance currency n s
| null s = Nothing
| otherwise = Just
(either (mkerror n s) id $
runParser (evalStateT (amountp <* eof) nulljournal) "" $
T.pack $ (currency++) $ simplifySign s
,nullsourcepos) -- XXX parse position to show when assertion fails,
-- the csv record's line number would be good
where
mkerror n s e = error' $ unlines
["error: could not parse \""++s++"\" as balance"++show n++" amount"
,showRecord record
,showRules rules record
-- ,"the default-currency is: "++fromMaybe "unspecified" mdefaultcurrency
,"the parse error is: "++customErrorBundlePretty e
]
-- mdefaultcurrency = rule "default-currency"
fieldval = hledgerFieldValue rules record :: HledgerFieldName -> Maybe String
fieldval = fmap strip . hledgerFieldValue rules record :: HledgerFieldName -> Maybe String
-- | Given a non-empty amount string (from CSV) to parse, along with a
-- possibly non-empty currency symbol to prepend,
-- parse as a hledger MixedAmount (as in journal format), or raise an error.
-- The whole CSV record is provided for the error message.
parseAmount :: CsvRules -> CsvRecord -> String -> String -> MixedAmount
parseAmount rules record currency s =
either mkerror (Mixed . (:[])) $ -- PARTIAL:
runParser (evalStateT (amountp <* eof) nulljournal) "" $
T.pack $ (currency++) $ simplifySign s
where
mkerror e = error' $ unlines
["error: could not parse \""++s++"\" as an amount"
,showRecord record
,showRules rules record
-- ,"the default-currency is: "++fromMaybe "unspecified" (getDirective "default-currency" rules)
,"the parse error is: "++customErrorBundlePretty e
,"you may need to "
++"change your amount*, balance*, or currency* rules, "
++"or add or change your skip rule"
]
-- XXX unify these
-- | Almost but not quite the same as parseAmount.
-- Given a non-empty amount string (from CSV) to parse, along with a
-- possibly non-empty currency symbol to prepend,
-- parse as a hledger Amount (as in journal format), or raise an error.
-- The CSV record and the field's numeric suffix are provided for the error message.
parseBalanceAmount :: CsvRules -> CsvRecord -> String -> Int -> String -> Amount
parseBalanceAmount rules record currency n s =
either (mkerror n s) id $
runParser (evalStateT (amountp <* eof) nulljournal) "" $
T.pack $ (currency++) $ simplifySign s
-- the csv record's line number would be good
where
mkerror n s e = error' $ unlines
["error: could not parse \""++s++"\" as balance"++show n++" amount"
,showRecord record
,showRules rules record
-- ,"the default-currency is: "++fromMaybe "unspecified" mdefaultcurrency
,"the parse error is: "++customErrorBundlePretty e
]
-- | Make a balance assertion for the given amount, with the given parse
-- position (to be shown in assertion failures), with the assertion type