lib: refactor includedirectivep to avoid "re-parsing"

This commit is contained in:
Alex Chen 2018-06-06 00:21:00 -06:00
parent b034fa7ca9
commit 4a9e418b7a
2 changed files with 41 additions and 36 deletions

View File

@ -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
-- parse include file
let parsers = [ journalp
, timeclockfilep , timeclockfilep
, timedotfilep , timedotfilep
-- can't include a csv file yet, that reader is special ] -- can't include a csv file yet, that reader is special
]) updatedChildj <- journalAddFile (filepath, childInput) <$>
childj) region (withSource childInput) (choiceInState parsers)
filepath txt
either -- restore parent state, prepending the child's parse info
(throwError setParserState parentParserState
. ((show parentpos ++ " in included file " ++ show filename ++ ":\n") ++) put $ updatedChildj <> parentj
. parseErrorPretty)
(return . journalAddFile (filepath, txt))
ej1
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

View File

@ -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