packages feed

spade-0.1.0.7: src/Interpreter/Lib/FileSystem.hs

module Interpreter.Lib.FileSystem where

import Control.Concurrent.STM (newTVarIO)
import Control.Monad.IO.Class
import qualified Data.ByteString as BS
import qualified Data.ByteString.Internal as BSI
import Data.Coerce
import Data.Maybe (fromMaybe)
import Data.Text as T
import Data.Text.Encoding
import Data.Text.IO as T
import System.Directory
import qualified System.IO as SIO
import System.Posix.Directory as POSIX
import System.FilePath

import Interpreter.Common

builtInWriteFile :: BuiltInFnWithDoc '[ '("filename", FilePath), '("data", BytesOrText)]
builtInWriteFile ((coerce -> filepath) :> (coerce -> bot) :> EmptyArgs) = liftIO $ case bot of
  BTBytes bin -> do
      BS.writeFile filepath bin
      pure Nothing
  BTText dat -> do
      T.writeFile filepath dat
      pure Nothing

builtInReadFile :: BuiltInFnWithDoc '[ '("filename", FilePath)]
builtInReadFile ((coerce -> filepath) :> _) = liftIO $ do
  c <- BS.readFile filepath
  pure $ Just $ BytesValue c

builtInIsFile :: BuiltInFnWithDoc '[ '("filename", FilePath)]
builtInIsFile ((coerce -> filepath) :> _) = liftIO $ do
  c <- doesFileExist filepath
  pure $ Just $ BoolValue c

builtInIsDir :: BuiltInFnWithDoc '[ '("filename", FilePath)]
builtInIsDir ((coerce -> filepath) :> _) = liftIO $ do
  c <- doesDirectoryExist filepath
  pure $ Just $ BoolValue c

builtInOpenFileHandle :: BuiltInFnWithDoc '[ '("filepath", FilePath), '("openmode", Text) ]
builtInOpenFileHandle ((coerce -> filepath) :> (coerce -> (openmode :: Text)) :>  EmptyArgs) = liftIO $ do
  let
    oMode = case openmode of
      "r" -> SIO.ReadMode
      "w" -> SIO.WriteMode
      "a" -> SIO.AppendMode
      "rw" -> SIO.ReadWriteMode
      _ -> error "Unknown file open mode"
  handle <- SIO.openBinaryFile filepath oMode
  pure $ Just $ FileHandleValue $ FileHandle handle

builtInReadFileHandle :: BuiltInFnWithDoc '[ '("handle", SIO.Handle), '("length", Int) ]
builtInReadFileHandle ((coerce -> (handle :: SIO.Handle)) :> (coerce -> len) :> EmptyArgs) = liftIO $ do
  dat <- BSI.createAndTrim len (\buf -> SIO.hGetBuf handle buf len)
  pure $ Just $ BytesValue dat

builtInGetFileSize :: BuiltInFnWithDoc '[ '("handle", SIO.Handle) ]
builtInGetFileSize ((coerce -> (handle :: SIO.Handle)) :>  EmptyArgs) = liftIO $ do
  s <- SIO.hFileSize handle
  pure $ Just $ NumberValue $ NumberInt s

builtInWriteFileHandle :: BuiltInFnWithDoc '[ '("filepath", SIO.Handle), '("data", BS.ByteString) ]
builtInWriteFileHandle ((coerce -> (handle :: SIO.Handle)) :> (coerce -> dat) :> EmptyArgs) = liftIO $ do
  BS.useAsCString dat (\buf -> SIO.hPutBuf handle buf (BS.length dat))
  pure Nothing

builtInOpenDir :: BuiltInFnWithDoc '[ '("dirpath", FilePath), '("recursive", Maybe Bool)]
builtInOpenDir ((coerce -> filepath) :> (coerce -> mrecursive) :> _) = liftIO $ do
  afp <- makeAbsolute filepath
  ds <- POSIX.openDirStream filepath
  ref <- newTVarIO [DirStreamInfo (AbsoluteFilePath afp) (Just ds)]
  pure $ Just $ DirectoryStack $ DirHandleRef (fromMaybe False mrecursive) ref

builtInGetCurrentDir :: BuiltInFnWithDoc '[]
builtInGetCurrentDir _ = liftIO $ do
  Just . StringValue . T.pack <$> getCurrentDirectory

builtInReadTextFile :: BuiltInFnWithDoc '[ '("filename", FilePath)]
builtInReadTextFile ((coerce -> filepath) :> _) = do
  c <- decodeUtf8 <$> (liftIO $ BS.readFile filepath)
  pure $ Just $ StringValue c

builtInRenameFile :: BuiltInFnWithDoc '[ '("filename", FilePath), '("newfilename", FilePath)]
builtInRenameFile ((coerce -> filepath) :> (coerce -> newfile) :> _) = do
  liftIO $ renameFile filepath ((takeDirectory filepath) </> newfile)
  pure Nothing

builtInTakeFilename :: BuiltInFnWithDoc '[ '("filepath", FilePath)]
builtInTakeFilename ((coerce -> filepath) :> _) =
  pure $ Just $ StringValue $ T.pack $ takeFileName filepath

builtInTakeDirectory :: BuiltInFnWithDoc '[ '("filepath", FilePath)]
builtInTakeDirectory ((coerce -> filepath) :> _) =
  pure $ Just $ StringValue $ T.pack $ takeDirectory filepath

builtInTakeExtension :: BuiltInFnWithDoc '[ '("filepath", FilePath)]
builtInTakeExtension ((coerce -> filepath) :> _) =
  pure $ Just $ StringValue $ T.pack $ takeExtension filepath

builtInDropExtension :: BuiltInFnWithDoc '[ '("filepath", FilePath)]
builtInDropExtension ((coerce -> filepath) :> _) =
  pure $ Just $ StringValue $ T.pack $ dropExtension filepath

builtInTakeBaseName :: BuiltInFnWithDoc '[ '("filepath", FilePath)]
builtInTakeBaseName ((coerce -> filepath) :> _) =
  pure $ Just $ StringValue $ T.pack $ takeBaseName filepath

builtInJoinPaths :: BuiltInFnWithDoc '[ '("filepath", FilePath), '("filepath", FilePath)]
builtInJoinPaths ((coerce -> filepath1) :> (coerce -> filepath2) :> _) =
  pure $ Just $ StringValue $ T.pack $ filepath1 </> filepath2