module BNFC.Backend.Haskell.HsOpts where

import BNFC.Utils
import BNFC.Options
import System.FilePath (pathSeparator, (<.>))
import Data.List (intercalate)
import Data.Maybe (catMaybes)

type Options = SharedOptions

absFile, absFileM,
 alexFile, alexFileHs, alexFileM,
 composOpFile, composOpFileM,
 happyFile, happyFileHs, happyFileM,
 errFile, errFileM,
 templateFile, templateFileM,
 printerFile, printerFileM,
 layoutFile, layoutFileM,
 tFile, tFileExe :: Options -> String
absFile :: Options -> String
absFile       = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"Abs" String
"hs"
absFileM :: Options -> String
absFileM      = (Options -> String -> String) -> String -> Options -> String
mkMod  Options -> String -> String
withLang String
"Abs"
alexFile :: Options -> String
alexFile      = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"Lex" String
"x"
alexFileHs :: Options -> String
alexFileHs    = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"Lex" String
"hs"
alexFileM :: Options -> String
alexFileM     = (Options -> String -> String) -> String -> Options -> String
mkMod  Options -> String -> String
withLang String
"Lex"
happyFile :: Options -> String
happyFile     = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"Par" String
"y"
happyFileHs :: Options -> String
happyFileHs   = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"Par" String
"hs"
happyFileM :: Options -> String
happyFileM    = (Options -> String -> String) -> String -> Options -> String
mkMod  Options -> String -> String
withLang String
"Par"
txtFile :: Options -> String
txtFile       = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"Doc" String
"txt"
templateFile :: Options -> String
templateFile  = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"Skel" String
"hs"
templateFileM :: Options -> String
templateFileM = (Options -> String -> String) -> String -> Options -> String
mkMod  Options -> String -> String
withLang String
"Skel"
printerFile :: Options -> String
printerFile   = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"Print" String
"hs"
printerFileM :: Options -> String
printerFileM  = (Options -> String -> String) -> String -> Options -> String
mkMod  Options -> String -> String
withLang String
"Print"
tFile :: Options -> String
tFile         = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"Test" String
"hs"
tFileExe :: Options -> String
tFileExe      = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"Test" String
""
errFile :: Options -> String
errFile       = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
noLang   String
"ErrM" String
"hs"
errFileM :: Options -> String
errFileM      = (Options -> String -> String) -> String -> Options -> String
mkMod  Options -> String -> String
noLang   String
"ErrM"
layoutFileM :: Options -> String
layoutFileM   = (Options -> String -> String) -> String -> Options -> String
mkMod  Options -> String -> String
withLang String
"Layout"
layoutFile :: Options -> String
layoutFile    = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"Layout" String
"hs"
xmlFile :: Options -> String
xmlFile       = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"XML" String
"hs"
xmlFileM :: Options -> String
xmlFileM      = (Options -> String -> String) -> String -> Options -> String
mkMod  Options -> String -> String
withLang String
"XML"
composOpFile :: Options -> String
composOpFile  = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
noLang   String
"ComposOp" String
"hs"
composOpFileM :: Options -> String
composOpFileM = (Options -> String -> String) -> String -> Options -> String
mkMod  Options -> String -> String
noLang   String
"ComposOp"

-- Files created by the Agda backend

agdaASTFile
  , agdaASTFileM
  , agdaParserFile
  , agdaParserFileM
  , agdaLibFile
  , agdaLibFileM
  , agdaMainFile
  , agdaMainFileM
 :: Options -> String
agdaASTFile :: Options -> String
agdaASTFile     = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"AST" String
"agda"
agdaASTFileM :: Options -> String
agdaASTFileM    = (Options -> String -> String) -> String -> Options -> String
mkMod  Options -> String -> String
withLang String
"AST"
agdaParserFile :: Options -> String
agdaParserFile  = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
withLang String
"Parser" String
"agda"
agdaParserFileM :: Options -> String
agdaParserFileM = (Options -> String -> String) -> String -> Options -> String
mkMod  Options -> String -> String
withLang String
"Parser"
agdaLibFile :: Options -> String
agdaLibFile     = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
noLang   String
"IOLib" String
"agda"
agdaLibFileM :: Options -> String
agdaLibFileM    = (Options -> String -> String) -> String -> Options -> String
mkMod  Options -> String -> String
noLang   String
"IOLib"
agdaMainFile :: Options -> String
agdaMainFile    = (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
noLang   String
"Main" String
"agda"
agdaMainFileM :: Options -> String
agdaMainFileM   = (Options -> String -> String) -> String -> Options -> String
mkMod  Options -> String -> String
noLang   String
"Main"


noLang :: Options -> String -> String
noLang :: Options -> String -> String
noLang Options
_ String
name = String
name

withLang :: Options -> String -> String
withLang :: Options -> String -> String
withLang Options
opts String
name = String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> NameStyle -> String -> String
mkName [] NameStyle
CamelCase (Options -> String
lang Options
opts)

pkgToDir :: String -> FilePath
pkgToDir :: String -> String
pkgToDir String
s = Char -> Char -> String -> String
forall a. Eq a => a -> a -> [a] -> [a]
replace Char
'.' Char
pathSeparator String
s


-- |
-- >>> mkMod withLang "Abstract" defaultOptions { lang = "abc" }
-- "AbstractAbc"
-- >>> mkMod noLang "Abstract" defaultOptions { lang = "abc" }
-- "Abstract"
-- >>> mkMod withLang "Abstract" defaultOptions { lang = "abc", inPackage = Just "A.B.C" }
-- "A.B.C.AbstractAbc"
-- >>> mkMod withLang "Abstract" defaultOptions { lang = "abc", inDir = True }
-- "Abc.Abstract"
-- >>> mkMod withLang "Abstract" defaultOptions { lang = "abc", inDir = True, inPackage = Just "A.B.C" }
-- "A.B.C.Abc.Abstract"
mkMod :: (Options -> String -> String) -> String -> Options -> String
mkMod :: (Options -> String -> String) -> String -> Options -> String
mkMod Options -> String -> String
addLang String
name Options
opts = Options -> String
mkNamespace Options
opts String -> String -> String
<.> String
mod
  where
    [] <.> :: String -> String -> String
<.> String
s = String
s
    String
s1 <.> String
s2 = String
s1 String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"." String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s2
    mod :: String
mod | Options -> Bool
inDir Options
opts = String
name
        | Bool
otherwise  = Options -> String -> String
addLang Options
opts String
name
-- |
-- >>> mkFile withLang "Abstract" "hs" defaultOptions { lang = "abc" }
-- "AbstractAbc.hs"
-- >>> mkFile noLang "Abstract" "hs" defaultOptions { lang = "abc" }
-- "Abstract.hs"
-- >>> mkFile withLang "Abstract" "" defaultOptions { lang = "abc" }
-- "AbstractAbc"
-- >>> mkFile noLang "Abstract" "" defaultOptions { lang = "abc" }
-- "Abstract"
-- >>> mkFile withLang "Abstract" "hs" defaultOptions { lang = "abc", inDir = True }
-- "Abc/Abstract.hs"
-- >>> mkFile withLang "Abstract" "hs" defaultOptions { lang = "abc", inDir = True, inPackage = Just "A.B.C" }
-- "A/B/C/Abc/Abstract.hs"
mkFile :: (Options -> String -> String) -> String -> String -> Options -> FilePath
mkFile :: (Options -> String -> String)
-> String -> String -> Options -> String
mkFile Options -> String -> String
addLang String
name String
ext Options
opts = String -> String
pkgToDir ((Options -> String -> String) -> String -> Options -> String
mkMod Options -> String -> String
addLang String
name Options
opts) String -> String -> String
<.> String
ext


-- | Determine the modules' namespace
--
-- >>> mkNamespace defaultOptions
-- ""
-- >>> mkNamespace defaultOptions { lang = "Bla", inDir = True }
-- "Bla"
-- >>> mkNamespace defaultOptions { inPackage = Just "My.Cool.Package" }
-- "My.Cool.Package"
-- >>> mkNamespace defaultOptions { lang = "bla_bla", inDir = True }
-- "BlaBla"
-- >>> mkNamespace defaultOptions { lang = "bla", inDir = True, inPackage = Just "P"}
-- "P.Bla"
mkNamespace :: Options -> FilePath
mkNamespace :: Options -> String
mkNamespace Options
opts = String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"." ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ [Maybe String] -> [String]
forall a. [Maybe a] -> [a]
catMaybes [Options -> Maybe String
inPackage Options
opts, Maybe String
dir]
  where
    dir :: Maybe String
dir | Options -> Bool
inDir Options
opts = String -> Maybe String
forall a. a -> Maybe a
Just ([String] -> NameStyle -> String -> String
mkName [] NameStyle
CamelCase (Options -> String
lang Options
opts))
        | Bool
otherwise  = Maybe String
forall a. Maybe a
Nothing

-- | Determine the directory corresponding to the modules' namespace
--
-- >>> codeDir defaultOptions
-- ""
-- >>> codeDir defaultOptions { lang = "Bla", inDir = True }
-- "Bla"
-- >>> codeDir defaultOptions { inPackage = Just "My.Cool.Package" }
-- "My/Cool/Package"
-- >>> codeDir defaultOptions { lang = "bla_bla", inDir = True }
-- "BlaBla"
-- >>> codeDir defaultOptions { lang = "bla", inDir = True, inPackage = Just "P"}
-- "P/Bla"
codeDir :: Options -> FilePath
codeDir :: Options -> String
codeDir = String -> String
pkgToDir (String -> String) -> (Options -> String) -> Options -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Options -> String
mkNamespace