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