lib: refactor includedirectivep to avoid "re-parsing"
This commit is contained in:
parent
b034fa7ca9
commit
4a9e418b7a
@ -75,7 +75,7 @@ import Prelude ()
|
|||||||
import "base-compat-batteries" Prelude.Compat hiding (readFile)
|
import "base-compat-batteries" Prelude.Compat hiding (readFile)
|
||||||
import qualified Control.Exception as C
|
import qualified Control.Exception as C
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.Except (ExceptT(..), runExceptT, throwError)
|
import Control.Monad.Except (ExceptT(..))
|
||||||
import Control.Monad.State.Strict
|
import Control.Monad.State.Strict
|
||||||
import qualified Data.Map.Strict as M
|
import qualified Data.Map.Strict as M
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
@ -190,37 +190,41 @@ includedirectivep :: MonadIO m => ErroringJournalParser m ()
|
|||||||
includedirectivep = do
|
includedirectivep = do
|
||||||
string "include"
|
string "include"
|
||||||
lift (skipSome spacenonewline)
|
lift (skipSome spacenonewline)
|
||||||
filename <- lift restofline
|
filename <- T.unpack <$> takeWhileP Nothing (/= '\n') -- don't consume newline yet
|
||||||
parentpos <- getPosition
|
|
||||||
|
-- save parent state
|
||||||
|
parentParserState <- getParserState
|
||||||
parentj <- get
|
parentj <- get
|
||||||
|
|
||||||
let childj = newJournalWithParseStateFrom parentj
|
let childj = newJournalWithParseStateFrom parentj
|
||||||
(ej :: Either String ParsedJournal) <-
|
parentpos <- getPosition
|
||||||
liftIO $ runExceptT $ do
|
|
||||||
|
-- read child input
|
||||||
let curdir = takeDirectory (sourceName parentpos)
|
let curdir = takeDirectory (sourceName parentpos)
|
||||||
filepath <- expandPath curdir filename `orRethrowIOError` (show parentpos ++ " locating " ++ filename)
|
filepath <- lift $ expandPath curdir filename `orRethrowIOError` (show parentpos ++ " locating " ++ filename)
|
||||||
txt <- readFilePortably filepath `orRethrowIOError` (show parentpos ++ " reading " ++ filepath)
|
childInput <- lift $ readFilePortably filepath `orRethrowIOError` (show parentpos ++ " reading " ++ filepath)
|
||||||
(ej1::Either (ParseError Char CustomErr) ParsedJournal) <-
|
|
||||||
runParserT
|
-- set child state
|
||||||
(evalStateT
|
setInput childInput
|
||||||
(choiceInState
|
pushPosition $ initialPos filepath
|
||||||
[journalp
|
put childj
|
||||||
,timeclockfilep
|
|
||||||
,timedotfilep
|
-- parse include file
|
||||||
-- can't include a csv file yet, that reader is special
|
let parsers = [ journalp
|
||||||
])
|
, timeclockfilep
|
||||||
childj)
|
, timedotfilep
|
||||||
filepath txt
|
] -- can't include a csv file yet, that reader is special
|
||||||
either
|
updatedChildj <- journalAddFile (filepath, childInput) <$>
|
||||||
(throwError
|
region (withSource childInput) (choiceInState parsers)
|
||||||
. ((show parentpos ++ " in included file " ++ show filename ++ ":\n") ++)
|
|
||||||
. parseErrorPretty)
|
-- restore parent state, prepending the child's parse info
|
||||||
(return . journalAddFile (filepath, txt))
|
setParserState parentParserState
|
||||||
ej1
|
put $ updatedChildj <> parentj
|
||||||
case ej of
|
|
||||||
Left e -> throwError e
|
|
||||||
Right childj -> modify' (\parentj -> childj <> parentj)
|
|
||||||
-- discard child's parse info, prepend its (reversed) list data, combine other fields
|
-- discard child's parse info, prepend its (reversed) list data, combine other fields
|
||||||
|
|
||||||
|
void newline
|
||||||
|
|
||||||
|
|
||||||
newJournalWithParseStateFrom :: Journal -> Journal
|
newJournalWithParseStateFrom :: Journal -> Journal
|
||||||
newJournalWithParseStateFrom j = mempty{
|
newJournalWithParseStateFrom j = mempty{
|
||||||
jparsedefaultyear = jparsedefaultyear j
|
jparsedefaultyear = jparsedefaultyear j
|
||||||
@ -234,11 +238,12 @@ newJournalWithParseStateFrom j = mempty{
|
|||||||
|
|
||||||
-- | Lift an IO action into the exception monad, rethrowing any IO
|
-- | Lift an IO action into the exception monad, rethrowing any IO
|
||||||
-- error with the given message prepended.
|
-- error with the given message prepended.
|
||||||
orRethrowIOError :: IO a -> String -> ExceptT String IO a
|
orRethrowIOError :: MonadIO m => IO a -> String -> TextParser m a
|
||||||
orRethrowIOError io msg =
|
orRethrowIOError io msg = do
|
||||||
ExceptT $
|
eResult <- liftIO $ (Right <$> io) `C.catch` \(e::C.IOException) -> pure $ Left $ printf "%s:\n%s" msg (show e)
|
||||||
(Right <$> io)
|
case eResult of
|
||||||
`C.catch` \(e::C.IOException) -> return $ Left $ printf "%s:\n%s" msg (show e)
|
Right res -> pure res
|
||||||
|
Left errMsg -> fail errMsg
|
||||||
|
|
||||||
accountdirectivep :: JournalParser m ()
|
accountdirectivep :: JournalParser m ()
|
||||||
accountdirectivep = do
|
accountdirectivep = do
|
||||||
|
|||||||
@ -83,7 +83,7 @@ reader = Reader
|
|||||||
parse :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal
|
parse :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal
|
||||||
parse = parseAndFinaliseJournal timeclockfilep
|
parse = parseAndFinaliseJournal timeclockfilep
|
||||||
|
|
||||||
timeclockfilep :: ErroringJournalParser IO ParsedJournal
|
timeclockfilep :: MonadIO m => ErroringJournalParser m ParsedJournal
|
||||||
timeclockfilep = do many timeclockitemp
|
timeclockfilep = do many timeclockitemp
|
||||||
eof
|
eof
|
||||||
j@Journal{jparsetimeclockentries=es} <- get
|
j@Journal{jparsetimeclockentries=es} <- get
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user