lib: Remove non-law-abiding Monoid instance for Journal.
This commit is contained in:
parent
702c958487
commit
e0dde6fe57
@ -90,6 +90,7 @@ import Control.Monad.Extra
|
|||||||
import Control.Monad.Reader as R
|
import Control.Monad.Reader as R
|
||||||
import Control.Monad.ST
|
import Control.Monad.ST
|
||||||
import Data.Array.ST
|
import Data.Array.ST
|
||||||
|
import Data.Default (Default(..))
|
||||||
import Data.Function ((&))
|
import Data.Function ((&))
|
||||||
import qualified Data.HashTable.ST.Cuckoo as H
|
import qualified Data.HashTable.ST.Cuckoo as H
|
||||||
import Data.List
|
import Data.List
|
||||||
@ -97,9 +98,8 @@ import Data.List.Extra (groupSort, nubSort)
|
|||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
#if !(MIN_VERSION_base(4,11,0))
|
#if !(MIN_VERSION_base(4,11,0))
|
||||||
import Data.Monoid
|
import Data.Semigroup (Semigroup(..))
|
||||||
#endif
|
#endif
|
||||||
import qualified Data.Semigroup as Sem
|
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
@ -157,7 +157,7 @@ instance Show Journal where
|
|||||||
-- ,show $ map fst $ jfiles j
|
-- ,show $ map fst $ jfiles j
|
||||||
-- ]
|
-- ]
|
||||||
|
|
||||||
-- The monoid instance for Journal is useful for two situations.
|
-- The semigroup instance for Journal is useful for two situations.
|
||||||
--
|
--
|
||||||
-- 1. concatenating finalised journals, eg with multiple -f options:
|
-- 1. concatenating finalised journals, eg with multiple -f options:
|
||||||
-- FIRST <> SECOND. The second's list fields are appended to the
|
-- FIRST <> SECOND. The second's list fields are appended to the
|
||||||
@ -168,7 +168,9 @@ instance Show Journal where
|
|||||||
-- CHILD <> PARENT. A parsed journal's data is in reverse order, so
|
-- CHILD <> PARENT. A parsed journal's data is in reverse order, so
|
||||||
-- this gives what we want.
|
-- this gives what we want.
|
||||||
--
|
--
|
||||||
instance Sem.Semigroup Journal where
|
-- Note that (<>) is right-biased, so nulljournal is only a left identity.
|
||||||
|
-- In particular, this prevents Journal from being a monoid.
|
||||||
|
instance Semigroup Journal where
|
||||||
j1 <> j2 = Journal {
|
j1 <> j2 = Journal {
|
||||||
jparsedefaultyear = jparsedefaultyear j2
|
jparsedefaultyear = jparsedefaultyear j2
|
||||||
,jparsedefaultcommodity = jparsedefaultcommodity j2
|
,jparsedefaultcommodity = jparsedefaultcommodity j2
|
||||||
@ -190,12 +192,8 @@ instance Sem.Semigroup Journal where
|
|||||||
,jlastreadtime = max (jlastreadtime j1) (jlastreadtime j2)
|
,jlastreadtime = max (jlastreadtime j1) (jlastreadtime j2)
|
||||||
}
|
}
|
||||||
|
|
||||||
instance Monoid Journal where
|
instance Default Journal where
|
||||||
mempty = nulljournal
|
def = nulljournal
|
||||||
#if !(MIN_VERSION_base(4,11,0))
|
|
||||||
-- This is redundant starting with base-4.11 / GHC 8.4.
|
|
||||||
mappend = (Sem.<>)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
nulljournal :: Journal
|
nulljournal :: Journal
|
||||||
nulljournal = Journal {
|
nulljournal = Journal {
|
||||||
|
|||||||
@ -48,22 +48,24 @@ import Control.Arrow (right)
|
|||||||
import qualified Control.Exception as C
|
import qualified Control.Exception as C
|
||||||
import Control.Monad (when)
|
import Control.Monad (when)
|
||||||
import "mtl" Control.Monad.Except (runExceptT)
|
import "mtl" Control.Monad.Except (runExceptT)
|
||||||
import Data.Default
|
import Data.Default (def)
|
||||||
import Data.Foldable (asum)
|
import Data.Foldable (asum)
|
||||||
import Data.List
|
import Data.List (group, sort, sortBy)
|
||||||
import Data.Maybe
|
import Data.List.NonEmpty (nonEmpty)
|
||||||
import Data.Ord
|
import Data.Maybe (fromMaybe)
|
||||||
|
import Data.Ord (comparing)
|
||||||
|
import Data.Semigroup (sconcat)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Data.Time (Day)
|
import Data.Time (Day)
|
||||||
import Safe
|
import Safe (headDef)
|
||||||
import System.Directory (doesFileExist, getHomeDirectory)
|
import System.Directory (doesFileExist, getHomeDirectory)
|
||||||
import System.Environment (getEnv)
|
import System.Environment (getEnv)
|
||||||
import System.Exit (exitFailure)
|
import System.Exit (exitFailure)
|
||||||
import System.FilePath
|
import System.FilePath ((<.>), (</>), splitDirectories, splitFileName)
|
||||||
import System.Info (os)
|
import System.Info (os)
|
||||||
import System.IO
|
import System.IO (stderr, writeFile)
|
||||||
import Text.Printf
|
import Text.Printf (hPrintf, printf)
|
||||||
|
|
||||||
import Hledger.Data.Dates (getCurrentDay, parsedate, showDate)
|
import Hledger.Data.Dates (getCurrentDay, parsedate, showDate)
|
||||||
import Hledger.Data.Types
|
import Hledger.Data.Types
|
||||||
@ -150,11 +152,7 @@ type PrefixedFilePath = FilePath
|
|||||||
-- Also the final parse state saved in the Journal does span all files.
|
-- Also the final parse state saved in the Journal does span all files.
|
||||||
readJournalFiles :: InputOpts -> [PrefixedFilePath] -> IO (Either String Journal)
|
readJournalFiles :: InputOpts -> [PrefixedFilePath] -> IO (Either String Journal)
|
||||||
readJournalFiles iopts =
|
readJournalFiles iopts =
|
||||||
(right mconcat1 . sequence <$>) . mapM (readJournalFile iopts)
|
fmap (right (maybe def sconcat . nonEmpty) . sequence) . mapM (readJournalFile iopts)
|
||||||
where
|
|
||||||
mconcat1 :: Monoid t => [t] -> t
|
|
||||||
mconcat1 [] = mempty
|
|
||||||
mconcat1 x = foldr1 mappend x
|
|
||||||
|
|
||||||
-- | Read a Journal from this file, or from stdin if the file path is -,
|
-- | Read a Journal from this file, or from stdin if the file path is -,
|
||||||
-- or return an error message. The file path can have a READER: prefix.
|
-- or return an error message. The file path can have a READER: prefix.
|
||||||
|
|||||||
@ -222,7 +222,7 @@ rtp = runTextParser
|
|||||||
runJournalParser, rjp
|
runJournalParser, rjp
|
||||||
:: Monad m
|
:: Monad m
|
||||||
=> JournalParser m a -> Text -> m (Either (ParseErrorBundle Text CustomErr) a)
|
=> JournalParser m a -> Text -> m (Either (ParseErrorBundle Text CustomErr) a)
|
||||||
runJournalParser p t = runParserT (evalStateT p mempty) "" t
|
runJournalParser p t = runParserT (evalStateT p nulljournal) "" t
|
||||||
rjp = runJournalParser
|
rjp = runJournalParser
|
||||||
|
|
||||||
-- | Run an erroring journal parser in some monad. See also: parseWithState.
|
-- | Run an erroring journal parser in some monad. See also: parseWithState.
|
||||||
@ -232,7 +232,7 @@ runErroringJournalParser, rejp
|
|||||||
-> Text
|
-> Text
|
||||||
-> m (Either FinalParseError (Either (ParseErrorBundle Text CustomErr) a))
|
-> m (Either FinalParseError (Either (ParseErrorBundle Text CustomErr) a))
|
||||||
runErroringJournalParser p t =
|
runErroringJournalParser p t =
|
||||||
runExceptT $ runParserT (evalStateT p mempty) "" t
|
runExceptT $ runParserT (evalStateT p nulljournal) "" t
|
||||||
rejp = runErroringJournalParser
|
rejp = runErroringJournalParser
|
||||||
|
|
||||||
genericSourcePos :: SourcePos -> GenericSourcePos
|
genericSourcePos :: SourcePos -> GenericSourcePos
|
||||||
@ -680,7 +680,7 @@ amountwithoutpricep = do
|
|||||||
-- | Parse an amount from a string, or get an error.
|
-- | Parse an amount from a string, or get an error.
|
||||||
amountp' :: String -> Amount
|
amountp' :: String -> Amount
|
||||||
amountp' s =
|
amountp' s =
|
||||||
case runParser (evalStateT (amountp <* eof) mempty) "" (T.pack s) of
|
case runParser (evalStateT (amountp <* eof) nulljournal) "" (T.pack s) of
|
||||||
Right amt -> amt
|
Right amt -> amt
|
||||||
Left err -> error' $ show err -- XXX should throwError
|
Left err -> error' $ show err -- XXX should throwError
|
||||||
|
|
||||||
|
|||||||
@ -963,7 +963,7 @@ mkPosting rules record number accountFld amountFld amountInFld amountOutFld bala
|
|||||||
| all isSpace str = Nothing
|
| all isSpace str = Nothing
|
||||||
| otherwise = Just
|
| otherwise = Just
|
||||||
(either (balanceerror n str) id $
|
(either (balanceerror n str) id $
|
||||||
runParser (evalStateT (amountp <* eof) mempty) "" $
|
runParser (evalStateT (amountp <* eof) nulljournal) "" $
|
||||||
T.pack $ (currency++) $ simplifySign str
|
T.pack $ (currency++) $ simplifySign str
|
||||||
,nullsourcepos) -- XXX parse position to show when assertion fails,
|
,nullsourcepos) -- XXX parse position to show when assertion fails,
|
||||||
-- the csv record's line number would be good
|
-- the csv record's line number would be good
|
||||||
@ -1039,7 +1039,7 @@ chooseAmount rules record currency amountFld amountInFld amountOutFld =
|
|||||||
|
|
||||||
parseAmount currency amountstr =
|
parseAmount currency amountstr =
|
||||||
either (amounterror amountstr) (Mixed . (:[]))
|
either (amounterror amountstr) (Mixed . (:[]))
|
||||||
<$> runParser (evalStateT (amountp <* eof) mempty) ""
|
<$> runParser (evalStateT (amountp <* eof) nulljournal) ""
|
||||||
<$> T.pack
|
<$> T.pack
|
||||||
<$> (currency++)
|
<$> (currency++)
|
||||||
<$> simplifySign
|
<$> simplifySign
|
||||||
|
|||||||
@ -85,7 +85,7 @@ import Control.Monad.Trans.Class (lift)
|
|||||||
import Data.Either (isRight)
|
import Data.Either (isRight)
|
||||||
import qualified Data.Map.Strict as M
|
import qualified Data.Map.Strict as M
|
||||||
#if !(MIN_VERSION_base(4,11,0))
|
#if !(MIN_VERSION_base(4,11,0))
|
||||||
import Data.Monoid ((<>))
|
import Data.Semigroup ((<>))
|
||||||
#endif
|
#endif
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Data.String
|
import Data.String
|
||||||
@ -298,7 +298,7 @@ includedirectivep = do
|
|||||||
put $ updatedChildj <> parentj
|
put $ updatedChildj <> parentj
|
||||||
|
|
||||||
newJournalWithParseStateFrom :: FilePath -> Journal -> Journal
|
newJournalWithParseStateFrom :: FilePath -> Journal -> Journal
|
||||||
newJournalWithParseStateFrom filepath j = mempty{
|
newJournalWithParseStateFrom filepath j = nulljournal{
|
||||||
jparsedefaultyear = jparsedefaultyear j
|
jparsedefaultyear = jparsedefaultyear j
|
||||||
,jparsedefaultcommodity = jparsedefaultcommodity j
|
,jparsedefaultcommodity = jparsedefaultcommodity j
|
||||||
,jparseparentaccounts = jparseparentaccounts j
|
,jparseparentaccounts = jparseparentaccounts j
|
||||||
@ -747,7 +747,7 @@ tests_JournalReader = tests "JournalReader" [
|
|||||||
,test "yearless date with no default year" $ assertParseError datep "1/1" "current year is unknown"
|
,test "yearless date with no default year" $ assertParseError datep "1/1" "current year is unknown"
|
||||||
,test "yearless date with default year" $ do
|
,test "yearless date with default year" $ do
|
||||||
let s = "1/1"
|
let s = "1/1"
|
||||||
ep <- parseWithState mempty{jparsedefaultyear=Just 2018} datep s
|
ep <- parseWithState nulljournal{jparsedefaultyear=Just 2018} datep s
|
||||||
either (assertFailure . ("parse error at "++) . customErrorBundlePretty) (const $ return ()) ep
|
either (assertFailure . ("parse error at "++) . customErrorBundlePretty) (const $ return ()) ep
|
||||||
,test "no leading zero" $ assertParse datep "2018/1/1"
|
,test "no leading zero" $ assertParse datep "2018/1/1"
|
||||||
]
|
]
|
||||||
|
|||||||
@ -25,8 +25,9 @@ where
|
|||||||
|
|
||||||
import Control.Monad.Except (ExceptT, runExceptT)
|
import Control.Monad.Except (ExceptT, runExceptT)
|
||||||
import Control.Monad.State.Strict (StateT, evalStateT, execStateT)
|
import Control.Monad.State.Strict (StateT, evalStateT, execStateT)
|
||||||
|
import Data.Default (Default(..))
|
||||||
#if !(MIN_VERSION_base(4,11,0))
|
#if !(MIN_VERSION_base(4,11,0))
|
||||||
import Data.Monoid ((<>))
|
import Data.Semigroup ((<>))
|
||||||
#endif
|
#endif
|
||||||
-- import Data.CallStack
|
-- import Data.CallStack
|
||||||
import Data.List (isInfixOf)
|
import Data.List (isInfixOf)
|
||||||
@ -73,35 +74,35 @@ assertRight (Left a) = assertFailure $ "expected Right, got (Left " ++ show a +
|
|||||||
-- | Assert that this stateful parser runnable in IO successfully parses
|
-- | Assert that this stateful parser runnable in IO successfully parses
|
||||||
-- all of the given input text, showing the parse error if it fails.
|
-- all of the given input text, showing the parse error if it fails.
|
||||||
-- Suitable for hledger's JournalParser parsers.
|
-- Suitable for hledger's JournalParser parsers.
|
||||||
assertParse :: (HasCallStack, Eq a, Show a, Monoid st) =>
|
assertParse :: (HasCallStack, Eq a, Show a, Default st) =>
|
||||||
StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> Assertion
|
StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> Assertion
|
||||||
assertParse parser input = do
|
assertParse parser input = do
|
||||||
ep <- runParserT (evalStateT (parser <* eof) mempty) "" input
|
ep <- runParserT (evalStateT (parser <* eof) def) "" input
|
||||||
either (assertFailure.(++"\n").("\nparse error at "++).customErrorBundlePretty)
|
either (assertFailure.(++"\n").("\nparse error at "++).customErrorBundlePretty)
|
||||||
(const $ return ())
|
(const $ return ())
|
||||||
ep
|
ep
|
||||||
|
|
||||||
-- | Assert a parser produces an expected value.
|
-- | Assert a parser produces an expected value.
|
||||||
assertParseEq :: (HasCallStack, Eq a, Show a, Monoid st) =>
|
assertParseEq :: (HasCallStack, Eq a, Show a, Default st) =>
|
||||||
StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> a -> Assertion
|
StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> a -> Assertion
|
||||||
assertParseEq parser input expected = assertParseEqOn parser input id expected
|
assertParseEq parser input expected = assertParseEqOn parser input id expected
|
||||||
|
|
||||||
-- | Like assertParseEq, but transform the parse result with the given function
|
-- | Like assertParseEq, but transform the parse result with the given function
|
||||||
-- before comparing it.
|
-- before comparing it.
|
||||||
assertParseEqOn :: (HasCallStack, Eq b, Show b, Monoid st) =>
|
assertParseEqOn :: (HasCallStack, Eq b, Show b, Default st) =>
|
||||||
StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> (a -> b) -> b -> Assertion
|
StateT st (ParsecT CustomErr T.Text IO) a -> T.Text -> (a -> b) -> b -> Assertion
|
||||||
assertParseEqOn parser input f expected = do
|
assertParseEqOn parser input f expected = do
|
||||||
ep <- runParserT (evalStateT (parser <* eof) mempty) "" input
|
ep <- runParserT (evalStateT (parser <* eof) def) "" input
|
||||||
either (assertFailure . (++"\n") . ("\nparse error at "++) . customErrorBundlePretty)
|
either (assertFailure . (++"\n") . ("\nparse error at "++) . customErrorBundlePretty)
|
||||||
(assertEqual "" expected . f)
|
(assertEqual "" expected . f)
|
||||||
ep
|
ep
|
||||||
|
|
||||||
-- | Assert that this stateful parser runnable in IO fails to parse
|
-- | Assert that this stateful parser runnable in IO fails to parse
|
||||||
-- the given input text, with a parse error containing the given string.
|
-- the given input text, with a parse error containing the given string.
|
||||||
assertParseError :: (HasCallStack, Eq a, Show a, Monoid st) =>
|
assertParseError :: (HasCallStack, Eq a, Show a, Default st) =>
|
||||||
StateT st (ParsecT CustomErr T.Text IO) a -> String -> String -> Assertion
|
StateT st (ParsecT CustomErr T.Text IO) a -> String -> String -> Assertion
|
||||||
assertParseError parser input errstr = do
|
assertParseError parser input errstr = do
|
||||||
ep <- runParserT (evalStateT parser mempty) "" (T.pack input)
|
ep <- runParserT (evalStateT parser def) "" (T.pack input)
|
||||||
case ep of
|
case ep of
|
||||||
Right v -> assertFailure $ "\nparse succeeded unexpectedly, producing:\n" ++ pshow v ++ "\n"
|
Right v -> assertFailure $ "\nparse succeeded unexpectedly, producing:\n" ++ pshow v ++ "\n"
|
||||||
Left e -> do
|
Left e -> do
|
||||||
@ -113,28 +114,28 @@ assertParseError parser input errstr = do
|
|||||||
-- | Run a stateful parser in IO like assertParse, then assert that the
|
-- | Run a stateful parser in IO like assertParse, then assert that the
|
||||||
-- final state (the wrapped state, not megaparsec's internal state),
|
-- final state (the wrapped state, not megaparsec's internal state),
|
||||||
-- transformed by the given function, matches the given expected value.
|
-- transformed by the given function, matches the given expected value.
|
||||||
assertParseStateOn :: (HasCallStack, Eq b, Show b, Monoid st) =>
|
assertParseStateOn :: (HasCallStack, Eq b, Show b, Default st) =>
|
||||||
StateT st (ParsecT CustomErr T.Text IO) a
|
StateT st (ParsecT CustomErr T.Text IO) a
|
||||||
-> T.Text
|
-> T.Text
|
||||||
-> (st -> b)
|
-> (st -> b)
|
||||||
-> b
|
-> b
|
||||||
-> Assertion
|
-> Assertion
|
||||||
assertParseStateOn parser input f expected = do
|
assertParseStateOn parser input f expected = do
|
||||||
es <- runParserT (execStateT (parser <* eof) mempty) "" input
|
es <- runParserT (execStateT (parser <* eof) def) "" input
|
||||||
case es of
|
case es of
|
||||||
Left err -> assertFailure $ (++"\n") $ ("\nparse error at "++) $ customErrorBundlePretty err
|
Left err -> assertFailure $ (++"\n") $ ("\nparse error at "++) $ customErrorBundlePretty err
|
||||||
Right s -> assertEqual "" expected $ f s
|
Right s -> assertEqual "" expected $ f s
|
||||||
|
|
||||||
-- | These "E" variants of the above are suitable for hledger's ErroringJournalParser parsers.
|
-- | These "E" variants of the above are suitable for hledger's ErroringJournalParser parsers.
|
||||||
assertParseE
|
assertParseE
|
||||||
:: (HasCallStack, Eq a, Show a, Monoid st)
|
:: (HasCallStack, Eq a, Show a, Default st)
|
||||||
=> StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a
|
=> StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a
|
||||||
-> T.Text
|
-> T.Text
|
||||||
-> Assertion
|
-> Assertion
|
||||||
assertParseE parser input = do
|
assertParseE parser input = do
|
||||||
let filepath = ""
|
let filepath = ""
|
||||||
eep <- runExceptT $
|
eep <- runExceptT $
|
||||||
runParserT (evalStateT (parser <* eof) mempty) filepath input
|
runParserT (evalStateT (parser <* eof) def) filepath input
|
||||||
case eep of
|
case eep of
|
||||||
Left finalErr ->
|
Left finalErr ->
|
||||||
let prettyErr = finalErrorBundlePretty $ attachSource filepath input finalErr
|
let prettyErr = finalErrorBundlePretty $ attachSource filepath input finalErr
|
||||||
@ -145,7 +146,7 @@ assertParseE parser input = do
|
|||||||
ep
|
ep
|
||||||
|
|
||||||
assertParseEqE
|
assertParseEqE
|
||||||
:: (Monoid st, Eq a, Show a, HasCallStack)
|
:: (Default st, Eq a, Show a, HasCallStack)
|
||||||
=> StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a
|
=> StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a
|
||||||
-> T.Text
|
-> T.Text
|
||||||
-> a
|
-> a
|
||||||
@ -153,7 +154,7 @@ assertParseEqE
|
|||||||
assertParseEqE parser input expected = assertParseEqOnE parser input id expected
|
assertParseEqE parser input expected = assertParseEqOnE parser input id expected
|
||||||
|
|
||||||
assertParseEqOnE
|
assertParseEqOnE
|
||||||
:: (HasCallStack, Eq b, Show b, Monoid st)
|
:: (HasCallStack, Eq b, Show b, Default st)
|
||||||
=> StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a
|
=> StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a
|
||||||
-> T.Text
|
-> T.Text
|
||||||
-> (a -> b)
|
-> (a -> b)
|
||||||
@ -161,7 +162,7 @@ assertParseEqOnE
|
|||||||
-> Assertion
|
-> Assertion
|
||||||
assertParseEqOnE parser input f expected = do
|
assertParseEqOnE parser input f expected = do
|
||||||
let filepath = ""
|
let filepath = ""
|
||||||
eep <- runExceptT $ runParserT (evalStateT (parser <* eof) mempty) filepath input
|
eep <- runExceptT $ runParserT (evalStateT (parser <* eof) def) filepath input
|
||||||
case eep of
|
case eep of
|
||||||
Left finalErr ->
|
Left finalErr ->
|
||||||
let prettyErr = finalErrorBundlePretty $ attachSource filepath input finalErr
|
let prettyErr = finalErrorBundlePretty $ attachSource filepath input finalErr
|
||||||
@ -172,14 +173,14 @@ assertParseEqOnE parser input f expected = do
|
|||||||
ep
|
ep
|
||||||
|
|
||||||
assertParseErrorE
|
assertParseErrorE
|
||||||
:: (Monoid st, Eq a, Show a, HasCallStack)
|
:: (Default st, Eq a, Show a, HasCallStack)
|
||||||
=> StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a
|
=> StateT st (ParsecT CustomErr T.Text (ExceptT FinalParseError IO)) a
|
||||||
-> T.Text
|
-> T.Text
|
||||||
-> String
|
-> String
|
||||||
-> Assertion
|
-> Assertion
|
||||||
assertParseErrorE parser input errstr = do
|
assertParseErrorE parser input errstr = do
|
||||||
let filepath = ""
|
let filepath = ""
|
||||||
eep <- runExceptT $ runParserT (evalStateT parser mempty) filepath input
|
eep <- runExceptT $ runParserT (evalStateT parser def) filepath input
|
||||||
case eep of
|
case eep of
|
||||||
Left finalErr -> do
|
Left finalErr -> do
|
||||||
let prettyErr = finalErrorBundlePretty $ attachSource filepath input finalErr
|
let prettyErr = finalErrorBundlePretty $ attachSource filepath input finalErr
|
||||||
|
|||||||
@ -166,7 +166,7 @@ validatePostings acctRes amtRes = let
|
|||||||
foldl (\s a -> s <> parseErrorTextPretty a) "" .
|
foldl (\s a -> s <> parseErrorTextPretty a) "" .
|
||||||
bundleErrors)
|
bundleErrors)
|
||||||
checkAccount = errorToFormMsg . runParser (accountnamep <* eof) "" . T.strip
|
checkAccount = errorToFormMsg . runParser (accountnamep <* eof) "" . T.strip
|
||||||
checkAmount = errorToFormMsg . runParser (evalStateT (amountp <* eof) mempty) "" . T.strip
|
checkAmount = errorToFormMsg . runParser (evalStateT (amountp <* eof) nulljournal) "" . T.strip
|
||||||
|
|
||||||
-- Add errors to forms with zero or one rows if the form is not a FormMissing
|
-- Add errors to forms with zero or one rows if the form is not a FormMissing
|
||||||
result :: [(Text, Text, Either (Maybe Text, Maybe Text) Posting)]
|
result :: [(Text, Text, Either (Maybe Text, Maybe Text) Posting)]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user