imp: journal: also parse (lot notes) in amounts (ledger compat)
and rename lotpricep -> lotcostp and instrument some amount parsers for debugging with megaparsec's dbg
This commit is contained in:
parent
aa54c3273a
commit
1ea2bcc83f
@ -80,7 +80,7 @@ module Hledger.Read.Common (
|
|||||||
commoditysymbolp,
|
commoditysymbolp,
|
||||||
costp,
|
costp,
|
||||||
balanceassertionp,
|
balanceassertionp,
|
||||||
lotpricep,
|
lotcostp,
|
||||||
numberp,
|
numberp,
|
||||||
fromRawNumber,
|
fromRawNumber,
|
||||||
rawnumberp,
|
rawnumberp,
|
||||||
@ -133,24 +133,25 @@ import Data.List.NonEmpty (NonEmpty(..))
|
|||||||
import Data.Maybe (catMaybes, fromMaybe, isJust, listToMaybe)
|
import Data.Maybe (catMaybes, fromMaybe, isJust, listToMaybe)
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import qualified Data.Semigroup as Sem
|
import qualified Data.Semigroup as Sem
|
||||||
import Data.Text (Text)
|
import Data.Text (Text, stripEnd)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Data.Time.Calendar (Day, fromGregorianValid, toGregorian)
|
import Data.Time.Calendar (Day, fromGregorianValid, toGregorian)
|
||||||
import Data.Time.Clock.POSIX (getPOSIXTime)
|
import Data.Time.Clock.POSIX (getPOSIXTime)
|
||||||
import Data.Time.LocalTime (LocalTime(..), TimeOfDay(..))
|
import Data.Time.LocalTime (LocalTime(..), TimeOfDay(..))
|
||||||
import Data.Word (Word8)
|
import Data.Word (Word8)
|
||||||
|
import System.FilePath (takeFileName)
|
||||||
import Text.Megaparsec
|
import Text.Megaparsec
|
||||||
import Text.Megaparsec.Char (char, char', digitChar, newline, string)
|
import Text.Megaparsec.Char (char, char', digitChar, newline, string)
|
||||||
import Text.Megaparsec.Char.Lexer (decimal)
|
import Text.Megaparsec.Char.Lexer (decimal)
|
||||||
import Text.Megaparsec.Custom
|
import Text.Megaparsec.Custom
|
||||||
(FinalParseError, attachSource, finalErrorBundlePretty, parseErrorAt, parseErrorAtRegion)
|
(FinalParseError, attachSource, finalErrorBundlePretty, parseErrorAt, parseErrorAtRegion)
|
||||||
|
-- import Text.Megaparsec.Debug (dbg) -- from megaparsec 9.3+
|
||||||
|
|
||||||
import Hledger.Data
|
import Hledger.Data
|
||||||
import Hledger.Query (Query(..), filterQuery, parseQueryTerm, queryEndDate, queryStartDate, queryIsDate, simplifyQuery)
|
import Hledger.Query (Query(..), filterQuery, parseQueryTerm, queryEndDate, queryStartDate, queryIsDate, simplifyQuery)
|
||||||
import Hledger.Reports.ReportOptions (ReportOpts(..), queryFromFlags, rawOptsToReportOpts)
|
import Hledger.Reports.ReportOptions (ReportOpts(..), queryFromFlags, rawOptsToReportOpts)
|
||||||
import Hledger.Utils
|
import Hledger.Utils
|
||||||
import Hledger.Read.InputOptions
|
import Hledger.Read.InputOptions
|
||||||
import System.FilePath (takeFileName)
|
|
||||||
|
|
||||||
--- ** doctest setup
|
--- ** doctest setup
|
||||||
-- $setup
|
-- $setup
|
||||||
@ -732,18 +733,24 @@ amountp = amountp' False
|
|||||||
-- A flag indicates whether we are parsing a multiplier amount;
|
-- A flag indicates whether we are parsing a multiplier amount;
|
||||||
-- if not, a commodity-less amount will have the default commodity applied to it.
|
-- if not, a commodity-less amount will have the default commodity applied to it.
|
||||||
amountp' :: Bool -> JournalParser m Amount
|
amountp' :: Bool -> JournalParser m Amount
|
||||||
amountp' mult = label "amount" $ do
|
amountp' mult =
|
||||||
|
-- dbg "amountp'" $
|
||||||
|
label "amount" $ do
|
||||||
let spaces = lift $ skipNonNewlineSpaces
|
let spaces = lift $ skipNonNewlineSpaces
|
||||||
amt <- simpleamountp mult <* spaces
|
amt <- simpleamountp mult <* spaces
|
||||||
(mprice, _elotprice, _elotdate) <- runPermutation $
|
(mcost, _mlotcost, _mlotdate, _mlotnote) <- runPermutation $
|
||||||
(,,) <$> toPermutationWithDefault Nothing (Just <$> costp amt <* spaces)
|
-- need a try on costp so that it doesn't consume the ( of a lot note
|
||||||
<*> toPermutationWithDefault Nothing (Just <$> lotpricep <* spaces)
|
(,,,) <$> toPermutationWithDefault Nothing (Just <$> try (costp amt) <* spaces)
|
||||||
<*> toPermutationWithDefault Nothing (Just <$> lotdatep <* spaces)
|
<*> toPermutationWithDefault Nothing (Just <$> lotcostp <* spaces)
|
||||||
pure $ amt { aprice = mprice }
|
<*> toPermutationWithDefault Nothing (Just <$> lotdatep <* spaces)
|
||||||
|
<*> toPermutationWithDefault Nothing (Just <$> lotnotep <* spaces)
|
||||||
|
pure $ amt { aprice = mcost }
|
||||||
|
|
||||||
-- An amount with optional cost, but no cost basis.
|
-- An amount with optional cost, but no cost basis.
|
||||||
amountnobasisp :: JournalParser m Amount
|
amountnobasisp :: JournalParser m Amount
|
||||||
amountnobasisp = label "amount" $ do
|
amountnobasisp =
|
||||||
|
-- dbg "amountnobasisp" $
|
||||||
|
label "amount" $ do
|
||||||
let spaces = lift $ skipNonNewlineSpaces
|
let spaces = lift $ skipNonNewlineSpaces
|
||||||
amt <- simpleamountp False
|
amt <- simpleamountp False
|
||||||
spaces
|
spaces
|
||||||
@ -754,7 +761,9 @@ amountnobasisp = label "amount" $ do
|
|||||||
-- A flag indicates whether we are parsing a multiplier amount;
|
-- A flag indicates whether we are parsing a multiplier amount;
|
||||||
-- if not, a commodity-less amount will have the default commodity applied to it.
|
-- if not, a commodity-less amount will have the default commodity applied to it.
|
||||||
simpleamountp :: Bool -> JournalParser m Amount
|
simpleamountp :: Bool -> JournalParser m Amount
|
||||||
simpleamountp mult = do
|
simpleamountp mult =
|
||||||
|
-- dbg "simpleamountp" $
|
||||||
|
do
|
||||||
sign <- lift signp
|
sign <- lift signp
|
||||||
leftsymbolamountp sign <|> rightornosymbolamountp sign
|
leftsymbolamountp sign <|> rightornosymbolamountp sign
|
||||||
|
|
||||||
@ -871,7 +880,9 @@ simplecommoditysymbolp = takeWhile1P Nothing (not . isNonsimpleCommodityChar)
|
|||||||
-- | Ledger-style cost notation:
|
-- | Ledger-style cost notation:
|
||||||
-- @ UNITAMT, @@ TOTALAMT, (@) UNITAMT, or (@@) TOTALAMT. The () are ignored.
|
-- @ UNITAMT, @@ TOTALAMT, (@) UNITAMT, or (@@) TOTALAMT. The () are ignored.
|
||||||
costp :: Amount -> JournalParser m AmountPrice
|
costp :: Amount -> JournalParser m AmountPrice
|
||||||
costp baseAmt = label "transaction price" $ do
|
costp baseAmt =
|
||||||
|
-- dbg "costp" $
|
||||||
|
label "transaction price" $ do
|
||||||
-- https://www.ledger-cli.org/3.0/doc/ledger3.html#Virtual-posting-costs
|
-- https://www.ledger-cli.org/3.0/doc/ledger3.html#Virtual-posting-costs
|
||||||
parenthesised <- option False $ char '(' >> pure True
|
parenthesised <- option False $ char '(' >> pure True
|
||||||
char '@'
|
char '@'
|
||||||
@ -906,12 +917,13 @@ balanceassertionp = do
|
|||||||
, baposition = sourcepos
|
, baposition = sourcepos
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Parse a Ledger-style fixed {=UNITPRICE} or non-fixed {UNITPRICE}
|
-- Parse a Ledger-style lot cost,
|
||||||
-- or fixed {{=TOTALPRICE}} or non-fixed {{TOTALPRICE}} lot price,
|
-- {UNITCOST} or {{TOTALCOST}} or {=FIXEDUNITCOST} or {{=FIXEDTOTALCOST}},
|
||||||
-- and ignore it.
|
-- and discard it.
|
||||||
-- https://www.ledger-cli.org/3.0/doc/ledger3.html#Fixing-Lot-Prices .
|
lotcostp :: JournalParser m ()
|
||||||
lotpricep :: JournalParser m ()
|
lotcostp =
|
||||||
lotpricep = label "ledger-style lot price" $ do
|
-- dbg "lotcostp" $
|
||||||
|
label "ledger-style lot cost" $ do
|
||||||
char '{'
|
char '{'
|
||||||
doublebrace <- option False $ char '{' >> pure True
|
doublebrace <- option False $ char '{' >> pure True
|
||||||
_fixed <- fmap isJust $ optional $ lift skipNonNewlineSpaces >> char '='
|
_fixed <- fmap isJust $ optional $ lift skipNonNewlineSpaces >> char '='
|
||||||
@ -921,17 +933,28 @@ lotpricep = label "ledger-style lot price" $ do
|
|||||||
char '}'
|
char '}'
|
||||||
when (doublebrace) $ void $ char '}'
|
when (doublebrace) $ void $ char '}'
|
||||||
|
|
||||||
-- Parse a Ledger-style lot date [DATE], and ignore it.
|
-- Parse a Ledger-style [LOTDATE], and discard it.
|
||||||
-- https://www.ledger-cli.org/3.0/doc/ledger3.html#Fixing-Lot-Prices .
|
|
||||||
lotdatep :: JournalParser m ()
|
lotdatep :: JournalParser m ()
|
||||||
lotdatep = (do
|
lotdatep =
|
||||||
|
-- dbg "lotdatep" $
|
||||||
|
label "ledger-style lot date" $ do
|
||||||
char '['
|
char '['
|
||||||
lift skipNonNewlineSpaces
|
lift skipNonNewlineSpaces
|
||||||
_d <- datep
|
_d <- datep
|
||||||
lift skipNonNewlineSpaces
|
lift skipNonNewlineSpaces
|
||||||
char ']'
|
char ']'
|
||||||
return ()
|
return ()
|
||||||
) <?> "ledger-style lot date"
|
|
||||||
|
-- Parse a Ledger-style (LOT NOTE), and discard it.
|
||||||
|
lotnotep :: JournalParser m ()
|
||||||
|
lotnotep =
|
||||||
|
-- dbg "lotnotep" $
|
||||||
|
label "ledger-style lot note" $ do
|
||||||
|
char '('
|
||||||
|
lift skipNonNewlineSpaces
|
||||||
|
_note <- stripEnd . T.pack <$> (many $ noneOf [')','\n']) -- XXX other line endings ?
|
||||||
|
char ')'
|
||||||
|
return ()
|
||||||
|
|
||||||
-- | Parse a string representation of a number for its value and display
|
-- | Parse a string representation of a number for its value and display
|
||||||
-- attributes.
|
-- attributes.
|
||||||
|
|||||||
@ -1385,14 +1385,12 @@ Currently, hledger treats the above like `@` and `@@`; the parentheses are ignor
|
|||||||
- when buying, attaches this acquisition date to the lot
|
- when buying, attaches this acquisition date to the lot
|
||||||
- when selling, selects a lot by its acquisition date
|
- when selling, selects a lot by its acquisition date
|
||||||
|
|
||||||
Currently, hledger accepts any or all of the above in any order after the posting amount, but ignores them.
|
- `(SOME TEXT)` ([lot note][ledger: lot notes])
|
||||||
(To select lots, we use subaccounts instead.)
|
|
||||||
|
|
||||||
- also: `(SOME TEXT)` ([lot note][ledger: lot notes])
|
|
||||||
- when buying, attaches this note to the lot
|
- when buying, attaches this note to the lot
|
||||||
- when selling, selects a lot by its note
|
- when selling, selects a lot by its note
|
||||||
|
|
||||||
Currently, hledger rejects lot notes.
|
Currently, hledger accepts any or all of the above in any order after the posting amount, but ignores them.
|
||||||
|
(This can break transaction balancing.)
|
||||||
|
|
||||||
[ledger: virtual posting costs]: https://www.ledger-cli.org/3.0/doc/ledger3.html#Virtual-posting-costs
|
[ledger: virtual posting costs]: https://www.ledger-cli.org/3.0/doc/ledger3.html#Virtual-posting-costs
|
||||||
[ledger: buying and selling stock]: https://www.ledger-cli.org/3.0/doc/ledger3.html#Buying-and-Selling-Stock
|
[ledger: buying and selling stock]: https://www.ledger-cli.org/3.0/doc/ledger3.html#Buying-and-Selling-Stock
|
||||||
|
|||||||
@ -220,7 +220,7 @@ $ hledger -f - print
|
|||||||
(a) A1B 2
|
(a) A1B 2
|
||||||
|
|
||||||
$ hledger -f- print cur:A1B amt:2
|
$ hledger -f- print cur:A1B amt:2
|
||||||
>2 /expecting ';', '=', digit, end of input, exponent, ledger-style lot date, ledger-style lot price, newline, space, or transaction price/
|
>2 /unexpected 'B'/
|
||||||
>=1
|
>=1
|
||||||
|
|
||||||
# 16. Unquoted commodity symbol on the right, gives this long error message.
|
# 16. Unquoted commodity symbol on the right, gives this long error message.
|
||||||
@ -229,7 +229,7 @@ $ hledger -f- print cur:A1B amt:2
|
|||||||
(a) 1 A2
|
(a) 1 A2
|
||||||
|
|
||||||
$ hledger -f- print cur:A1 amt:2
|
$ hledger -f- print cur:A1 amt:2
|
||||||
>2 /expecting ';', '=', end of input, ledger-style lot date, ledger-style lot price, newline, or transaction price/
|
>2 /unexpected '2'/
|
||||||
>=1
|
>=1
|
||||||
|
|
||||||
# 17. Unquoted commodity symbol on the left ending with numbers, could parse successfully.
|
# 17. Unquoted commodity symbol on the left ending with numbers, could parse successfully.
|
||||||
|
|||||||
@ -41,13 +41,3 @@ $ hledger -f- check
|
|||||||
$ hledger -f- check
|
$ hledger -f- check
|
||||||
>2//
|
>2//
|
||||||
>=1
|
>=1
|
||||||
|
|
||||||
# lot notation
|
|
||||||
<
|
|
||||||
2012-04-10
|
|
||||||
Assets:Brokerage:Cash $375.00
|
|
||||||
Assets:Brokerage -5 AAPL {$50.00} [2012-04-10] (Oh my!) @@ $375.00
|
|
||||||
Income:Capital Gains $-125.00
|
|
||||||
$ hledger -f- check
|
|
||||||
>2//
|
|
||||||
>=1
|
|
||||||
|
|||||||
@ -78,3 +78,15 @@ eval foo
|
|||||||
--command-line-flag
|
--command-line-flag
|
||||||
|
|
||||||
$ hledger -f- check
|
$ hledger -f- check
|
||||||
|
|
||||||
|
|
||||||
|
# lot notation
|
||||||
|
<
|
||||||
|
2022-01-01 sell 5 AAPL acquired at $50 for $375, for a $125 gain
|
||||||
|
Assets:Brokerage:Cash $375.00
|
||||||
|
Assets:Brokerage -5 AAPL {$50.00} [2012-04-10] (a lot note) (@@) $375.00 ; using (@@) to make parsing harder
|
||||||
|
Income:Capital Gains $-125.00
|
||||||
|
|
||||||
|
$ hledger -f- check
|
||||||
|
>2 /transaction is unbalanced/
|
||||||
|
>=1
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user