module Jacinda.File ( tcIO , tySrc , runOnHandle , runOnFile , exprEval ) where import Control.Applicative ((<|>)) import Control.Exception (Exception, throw, throwIO) import Control.Monad ((<=<)) import Control.Monad.IO.Class (liftIO) import Control.Monad.State.Strict (StateT, get, put, runStateT) import Data.Bifunctor (second) import qualified Data.ByteString as BS import qualified Data.ByteString.Char8 as ASCII import qualified Data.ByteString.Lazy as BSL import qualified Data.ByteString.Lazy.Char8 as ASCIIL import Data.Functor (void, ($>)) import Data.Tuple (swap) import Jacinda.AST import Jacinda.Backend.Normalize import Jacinda.Backend.TreeWalk import Jacinda.Include import Jacinda.Lexer import Jacinda.Parser import Jacinda.Parser.Rewrite import Jacinda.Regex import Jacinda.Rename import Jacinda.Ty import Regex.Rure (RurePtr) import System.IO (Handle) parseLib :: [FilePath] -> FilePath -> StateT AlexUserState IO [D AlexPosn] parseLib incls fp = do contents <- liftIO $ BSL.readFile =<< resolveImport incls fp st <- get case parseLibWithCtx contents st of Left err -> liftIO (throwIO err) Right (st', ([], ds)) -> put st' $> (rewriteD <$> ds) Right (st', (is, ds)) -> do { put st' ; dss <- traverse (parseLib incls) is ; pure (concat dss ++ fmap rewriteD ds) } parseE :: [FilePath] -> BSL.ByteString -> StateT AlexUserState IO (Program AlexPosn) parseE incls bs = do st <- get case parseWithCtx bs st of Left err -> liftIO $ throwIO err Right (st', (is, Program ds e)) -> do put st' dss <- traverse (parseLib incls) is pure $ Program (concat dss ++ fmap rewriteD ds) (rewriteE e) -- | Parse + rename (decls) parseEWithMax :: [FilePath] -> BSL.ByteString -> IO (Program AlexPosn, Int) parseEWithMax incls bsl = uncurry renamePGlobal . swap . second fst3 <$> runStateT (parseE incls bsl) alexInitUserState where fst3 (x, _, _) = x -- | Parse + rename (globally) parseWithMax' :: BSL.ByteString -> Either (ParseError AlexPosn) (Program AlexPosn, Int) parseWithMax' = fmap (uncurry renamePGlobal . second (rewriteProgram . snd)) . parseWithMax exprEval :: BSL.ByteString -> E (T K) exprEval src = case parseWithMax' src of Left err -> throw err Right (ast, m) -> let (typed, i) = yeet $ runTypeM m (tyProgram ast) in closedProgram i (compileIn typed) compileFS :: Maybe BS.ByteString -> RurePtr compileFS (Just bs) = compileDefault bs compileFS Nothing = defaultRurePtr runOnBytes :: [FilePath] -> FilePath -- ^ Data file name, for @nf@ -> BSL.ByteString -- ^ Program -> Maybe BS.ByteString -- ^ Field separator -> BSL.ByteString -> IO () runOnBytes incls fp src cliFS contents = do incls' <- defaultIncludes <*> pure incls (ast, m) <- parseEWithMax incls' src (typed, i) <- yeetIO $ runTypeM m (tyProgram ast) cont <- yeetIO $ runJac (ASCII.pack fp) (compileFS (cliFS <|> getFS ast)) i typed cont $ fmap BSL.toStrict (ASCIIL.lines contents) -- see: BSL.split, BSL.splitWith runOnHandle :: [FilePath] -> BSL.ByteString -- ^ Program -> Maybe BS.ByteString -- ^ Field separator -> Handle -> IO () runOnHandle is src cliFS = runOnBytes is "(runOnBytes)" src cliFS <=< BSL.hGetContents runOnFile :: [FilePath] -> BSL.ByteString -> Maybe BS.ByteString -> FilePath -> IO () runOnFile is e fs fp = runOnBytes is fp e fs =<< BSL.readFile fp tcIO :: [FilePath] -> BSL.ByteString -> IO () tcIO incls src = do incls' <- defaultIncludes <*> pure incls (ast, m) <- parseEWithMax incls' src yeetIO $ void $ runTypeM m (tyProgram ast) tySrc :: BSL.ByteString -> T K tySrc src = case parseWithMax' src of Right (ast, m) -> yeet $ fst <$> runTypeM m (tyOf (expr ast)) Left err -> throw err yeetIO :: Exception e => Either e a -> IO a yeetIO = either throwIO pure yeet :: Exception e => Either e a -> a yeet = either throw id