{- |
    Module      :  $Header$
    Description :  Library to support meta-programming in Curry
    Copyright   :  (c) Michael Hanus  , 2004
                       Martin Engelke , 2005
                       Björn Peemöller, 2014
                       Finn Teegen    , 2016
    License     :  BSD-3-clause

    Maintainer  :  bjp@informatik.uni-kiel.de
    Stability   :  experimental
    Portability :  portable

    This library contains I/O actions to read Curry programs
    and transform them into this abstract representation as well as
    write them to a file.
-}
module Curry.AbstractCurry.Files
  ( readCurry, writeCurry, showCurry
  ) where

import qualified Control.Exception        as C (catch)
import           Data.List                     (intercalate)

import           Curry.Files.PathUtils         ( writeModule, readModule
                                               , addVersion, checkVersion)

import           Curry.AbstractCurry.Type

-- ---------------------------------------------------------------------------
-- Reading and writing AbstractCurry terms
-- ---------------------------------------------------------------------------

-- |Read an AbstractCurry file and return the corresponding AbstractCurry
--  program term of type 'CurryProg'
readCurry :: FilePath -> IO (Maybe CurryProg)
readCurry :: FilePath -> IO (Maybe CurryProg)
readCurry fn :: FilePath
fn = do
  Maybe FilePath
mbSrc <- FilePath -> IO (Maybe FilePath)
readModule FilePath
fn
  Maybe CurryProg -> IO (Maybe CurryProg)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe CurryProg -> IO (Maybe CurryProg))
-> Maybe CurryProg -> IO (Maybe CurryProg)
forall a b. (a -> b) -> a -> b
$ case Maybe FilePath
mbSrc of
    Nothing  -> Maybe CurryProg
forall a. Maybe a
Nothing
    Just src :: FilePath
src -> case FilePath -> FilePath -> Either FilePath FilePath
checkVersion FilePath
version FilePath
src of
      Left  _  -> Maybe CurryProg
forall a. Maybe a
Nothing
      Right ac :: FilePath
ac -> CurryProg -> Maybe CurryProg
forall a. a -> Maybe a
Just (FilePath -> CurryProg
forall a. Read a => FilePath -> a
read FilePath
ac)

-- |Write an AbstractCurry program term into a file.
writeCurry :: FilePath -> CurryProg -> IO ()
writeCurry :: FilePath -> CurryProg -> IO ()
writeCurry fn :: FilePath
fn p :: CurryProg
p = IO () -> (IOError -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
C.catch (FilePath -> FilePath -> IO ()
writeModule FilePath
fn (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath -> FilePath
addVersion FilePath
version (FilePath -> FilePath) -> FilePath -> FilePath
forall a b. (a -> b) -> a -> b
$ CurryProg -> FilePath
showCurry CurryProg
p)
                  IOError -> IO ()
forall a. IOError -> IO a
ioError

-- |Show an AbstractCurry program in a nicer way
showCurry :: CurryProg -> String
showCurry :: CurryProg -> FilePath
showCurry (CurryProg mname :: FilePath
mname imps :: [FilePath]
imps dflt :: Maybe CDefaultDecl
dflt clss :: [CClassDecl]
clss insts :: [CInstanceDecl]
insts types :: [CTypeDecl]
types funcs :: [CFuncDecl]
funcs ops :: [COpDecl]
ops)
  =  "CurryProg " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
mname FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ "\n"
  FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ [FilePath] -> FilePath
forall a. Show a => a -> FilePath
show [FilePath]
imps FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ "\n"
  FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Int -> Maybe CDefaultDecl -> FilePath -> FilePath
forall a. Show a => Int -> a -> FilePath -> FilePath
showsPrec 11 Maybe CDefaultDecl
dflt "\n"
  FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ [CClassDecl] -> FilePath
forall a. Show a => [a] -> FilePath
wrapList [CClassDecl]
clss
  FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ [CInstanceDecl] -> FilePath
forall a. Show a => [a] -> FilePath
wrapList [CInstanceDecl]
insts
  FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ [CTypeDecl] -> FilePath
forall a. Show a => [a] -> FilePath
wrapList [CTypeDecl]
types
  FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ [CFuncDecl] -> FilePath
forall a. Show a => [a] -> FilePath
wrapList [CFuncDecl]
funcs
  FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ [COpDecl] -> FilePath
forall a. Show a => [a] -> FilePath
wrapList [COpDecl]
ops
  where wrapList :: [a] -> FilePath
wrapList xs :: [a]
xs = " [" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath -> [FilePath] -> FilePath
forall a. [a] -> [[a]] -> [a]
intercalate ",\n  " ((a -> FilePath) -> [a] -> [FilePath]
forall a b. (a -> b) -> [a] -> [b]
map a -> FilePath
forall a. Show a => a -> FilePath
show [a]
xs) FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ "]\n"