module Language.Drasil.Code.Imperative.Build.Import (
makeBuild
) where
import Language.Drasil.Code.Imperative.Build.AST (asFragment, DocConfig(..),
BuildConfig(BuildConfig), BuildDependencies(..), Ext(..), includeExt,
NameOpts, nameOpts, packSep, Runnable(Runnable), BuildName(..), RunType(..))
import Drasil.GOOL (FileData(..), ProgData(..), GOOLState(..), headers, sources,
mainMod)
import Build.Drasil (Annotation, (+:+), genMake, makeS, MakeString, mkFile, mkRule,
mkCheckedCommand, mkFreeVar, RuleTransformer(makeRule))
import Data.Containers.ListUtils (nubOrd)
import Control.Lens ((^.))
import Data.Maybe (maybeToList)
import System.FilePath.Posix (takeExtension, takeBaseName)
import Text.PrettyPrint.HughesPJ (Doc)
import Utils.Drasil (capitalize)
import Metadata.Drasil.DrasilMetaCall (watermark)
data CodeHarness = Ch {
CodeHarness -> Maybe BuildConfig
buildConfig :: Maybe BuildConfig,
CodeHarness -> Maybe Runnable
runnable :: Maybe Runnable,
CodeHarness -> GOOLState
goolState :: GOOLState,
CodeHarness -> ProgData
progData :: ProgData,
CodeHarness -> Maybe DocConfig
docConfig :: Maybe DocConfig}
instance RuleTransformer CodeHarness where
makeRule :: CodeHarness -> [Rule]
makeRule (Ch Maybe BuildConfig
b Maybe Runnable
r GOOLState
s ProgData
m Maybe DocConfig
d) = [Rule] -> (BuildConfig -> [Rule]) -> Maybe BuildConfig -> [Rule]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [[String] -> MakeString -> Dependencies -> [Command] -> Rule
mkRule (ProgData -> [String]
openingComments ProgData
m) MakeString
buildTarget [] []]
(\(BuildConfig Dependencies -> MakeString -> MakeString -> [Dependencies]
comp Maybe BuildName
onm Maybe BuildName
anm BuildDependencies
bt) ->
let outnm :: MakeString
outnm = MakeString
-> (BuildName -> MakeString) -> Maybe BuildName -> MakeString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> MakeString
asFragment String
"") (GOOLState -> ProgData -> NameOpts -> BuildName -> MakeString
renderBuildName GOOLState
s ProgData
m NameOpts
nameOpts) Maybe BuildName
onm
addnm :: MakeString
addnm = MakeString
-> (BuildName -> MakeString) -> Maybe BuildName -> MakeString
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> MakeString
asFragment String
"") (GOOLState -> ProgData -> NameOpts -> BuildName -> MakeString
renderBuildName GOOLState
s ProgData
m NameOpts
nameOpts) Maybe BuildName
anm
in [
[String] -> MakeString -> Dependencies -> [Command] -> Rule
mkRule (ProgData -> [String]
openingComments ProgData
m) MakeString
buildTarget [MakeString
outnm] [],
[String] -> MakeString -> Dependencies -> [Command] -> Rule
mkFile [] MakeString
outnm ((FileData -> MakeString) -> [FileData] -> Dependencies
forall a b. (a -> b) -> [a] -> [b]
map (String -> MakeString
makeS (String -> MakeString)
-> (FileData -> String) -> FileData -> MakeString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FileData -> String
filePath) (ProgData -> [FileData]
progMods ProgData
m)) ([Command] -> Rule) -> [Command] -> Rule
forall a b. (a -> b) -> a -> b
$
(Dependencies -> Command) -> [Dependencies] -> [Command]
forall a b. (a -> b) -> [a] -> [b]
map (MakeString -> Command
mkCheckedCommand (MakeString -> Command)
-> (Dependencies -> MakeString) -> Dependencies -> Command
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MakeString -> MakeString -> MakeString)
-> MakeString -> Dependencies -> MakeString
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr MakeString -> MakeString -> MakeString
(+:+) MakeString
forall a. Monoid a => a
mempty) ([Dependencies] -> [Command]) -> [Dependencies] -> [Command]
forall a b. (a -> b) -> a -> b
$
Dependencies -> MakeString -> MakeString -> [Dependencies]
comp (BuildDependencies -> GOOLState -> ProgData -> Dependencies
getCompilerInput BuildDependencies
bt GOOLState
s ProgData
m) MakeString
outnm MakeString
addnm
]) Maybe BuildConfig
b [Rule] -> [Rule] -> [Rule]
forall a. [a] -> [a] -> [a]
++ [Rule] -> (Runnable -> [Rule]) -> Maybe Runnable -> [Rule]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] (\(Runnable BuildName
nm NameOpts
no RunType
ty) -> [
[String] -> MakeString -> Dependencies -> [Command] -> Rule
mkRule [] (String -> MakeString
makeS String
"run") [MakeString
buildTarget] [
MakeString -> Command
mkCheckedCommand (MakeString -> Command) -> MakeString -> Command
forall a b. (a -> b) -> a -> b
$ MakeString -> RunType -> MakeString
buildRunTarget (GOOLState -> ProgData -> NameOpts -> BuildName -> MakeString
renderBuildName GOOLState
s ProgData
m NameOpts
no BuildName
nm) RunType
ty MakeString -> MakeString -> MakeString
+:+
String -> MakeString
mkFreeVar String
"RUNARGS"
]
]) Maybe Runnable
r [Rule] -> [Rule] -> [Rule]
forall a. [a] -> [a] -> [a]
++ [Rule] -> (DocConfig -> [Rule]) -> Maybe DocConfig -> [Rule]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] (\(DocConfig Dependencies
dps [Command]
cmds) -> [
[String] -> MakeString -> Dependencies -> [Command] -> Rule
mkRule [] (String -> MakeString
makeS String
"doc") (Dependencies
dps Dependencies -> Dependencies -> Dependencies
forall a. [a] -> [a] -> [a]
++ GOOLState -> Dependencies
getCommentedFiles GOOLState
s) [Command]
cmds
]) Maybe DocConfig
d where
buildTarget :: MakeString
buildTarget = String -> MakeString
makeS String
"build"
openingComments :: ProgData -> Annotation
ProgData
m = [String
watermark,String
"Project Name: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ ProgData -> String
progName ProgData
m, ProgData -> String
progPurpAdd ProgData
m]
progPurpAdd :: ProgData -> String
progPurpAdd :: ProgData -> String
progPurpAdd ProgData
m = if ProgData -> String
progPurp ProgData
m String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= [] then String
"Project Purpose: " String -> String -> String
forall a. [a] -> [a] -> [a]
++
String -> String
capitalize (ProgData -> String
progPurp ProgData
m)
else []
renderBuildName :: GOOLState -> ProgData -> NameOpts -> BuildName -> MakeString
renderBuildName :: GOOLState -> ProgData -> NameOpts -> BuildName -> MakeString
renderBuildName GOOLState
s ProgData
_ NameOpts
_ BuildName
BMain = String -> MakeString
makeS (String -> MakeString) -> String -> MakeString
forall a b. (a -> b) -> a -> b
$ String -> (String -> String) -> Maybe String -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> String
forall a. HasCallStack => String -> a
error String
"Main module missing")
String -> String
takeBaseName (GOOLState
s GOOLState
-> Getting (Maybe String) GOOLState (Maybe String) -> Maybe String
forall s a. s -> Getting a s a -> a
^. Getting (Maybe String) GOOLState (Maybe String)
Lens' GOOLState (Maybe String)
mainMod)
renderBuildName GOOLState
_ ProgData
p NameOpts
_ BuildName
BPackName = String -> MakeString
makeS (ProgData -> String
progName ProgData
p)
renderBuildName GOOLState
s ProgData
p NameOpts
o (BPack BuildName
a) = GOOLState -> ProgData -> NameOpts -> BuildName -> MakeString
renderBuildName GOOLState
s ProgData
p NameOpts
o BuildName
BPackName MakeString -> MakeString -> MakeString
forall a. Semigroup a => a -> a -> a
<>
String -> MakeString
makeS (NameOpts -> String
packSep NameOpts
o) MakeString -> MakeString -> MakeString
forall a. Semigroup a => a -> a -> a
<> GOOLState -> ProgData -> NameOpts -> BuildName -> MakeString
renderBuildName GOOLState
s ProgData
p NameOpts
o BuildName
a
renderBuildName GOOLState
s ProgData
p NameOpts
o (BWithExt BuildName
a Ext
e) = GOOLState -> ProgData -> NameOpts -> BuildName -> MakeString
renderBuildName GOOLState
s ProgData
p NameOpts
o BuildName
a MakeString -> MakeString -> MakeString
forall a. Semigroup a => a -> a -> a
<>
if NameOpts -> Bool
includeExt NameOpts
o then Ext -> String -> MakeString
renderExt Ext
e ([String] -> String
forall {a}. [a] -> a
takeSrc ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ GOOLState
s GOOLState -> Getting [String] GOOLState [String] -> [String]
forall s a. s -> Getting a s a -> a
^. Getting [String] GOOLState [String]
Lens' GOOLState [String]
sources) else String -> MakeString
makeS String
""
where takeSrc :: [a] -> a
takeSrc (a
src:[a]
_) = a
src
takeSrc [] = String -> a
forall a. HasCallStack => String -> a
error String
"Generated code has no source files"
renderExt :: Ext -> FilePath -> MakeString
renderExt :: Ext -> String -> MakeString
renderExt Ext
CodeExt String
f = String -> MakeString
makeS (String -> MakeString) -> String -> MakeString
forall a b. (a -> b) -> a -> b
$ String -> String
takeExtension String
f
renderExt (OtherExt MakeString
e) String
_ = MakeString
e
getCompilerInput :: BuildDependencies -> GOOLState -> ProgData -> [MakeString]
getCompilerInput :: BuildDependencies -> GOOLState -> ProgData -> Dependencies
getCompilerInput BuildDependencies
BcSource GOOLState
s ProgData
_ = (String -> MakeString) -> [String] -> Dependencies
forall a b. (a -> b) -> [a] -> [b]
map String -> MakeString
makeS ([String] -> Dependencies) -> [String] -> Dependencies
forall a b. (a -> b) -> a -> b
$ GOOLState
s GOOLState -> Getting [String] GOOLState [String] -> [String]
forall s a. s -> Getting a s a -> a
^. Getting [String] GOOLState [String]
Lens' GOOLState [String]
sources
getCompilerInput (BcSingle BuildName
n) GOOLState
s ProgData
p = [GOOLState -> ProgData -> NameOpts -> BuildName -> MakeString
renderBuildName GOOLState
s ProgData
p NameOpts
nameOpts BuildName
n]
getCommentedFiles :: GOOLState -> [MakeString]
GOOLState
s = (String -> MakeString) -> [String] -> Dependencies
forall a b. (a -> b) -> [a] -> [b]
map String -> MakeString
makeS ([String] -> [String]
forall a. Ord a => [a] -> [a]
nubOrd (GOOLState
s GOOLState -> Getting [String] GOOLState [String] -> [String]
forall s a. s -> Getting a s a -> a
^. Getting [String] GOOLState [String]
Lens' GOOLState [String]
headers [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++
Maybe String -> [String]
forall a. Maybe a -> [a]
maybeToList (GOOLState
s GOOLState
-> Getting (Maybe String) GOOLState (Maybe String) -> Maybe String
forall s a. s -> Getting a s a -> a
^. Getting (Maybe String) GOOLState (Maybe String)
Lens' GOOLState (Maybe String)
mainMod)))
buildRunTarget :: MakeString -> RunType -> MakeString
buildRunTarget :: MakeString -> RunType -> MakeString
buildRunTarget MakeString
fn RunType
Standalone = String -> MakeString
makeS String
"./" MakeString -> MakeString -> MakeString
forall a. Semigroup a => a -> a -> a
<> MakeString
fn
buildRunTarget MakeString
fn (Interpreter Dependencies
i) = (MakeString -> MakeString -> MakeString)
-> MakeString -> Dependencies -> MakeString
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr MakeString -> MakeString -> MakeString
(+:+) MakeString
forall a. Monoid a => a
mempty (Dependencies -> MakeString) -> Dependencies -> MakeString
forall a b. (a -> b) -> a -> b
$ Dependencies
i Dependencies -> Dependencies -> Dependencies
forall a. [a] -> [a] -> [a]
++ [MakeString
fn]
makeBuild :: Maybe DocConfig -> Maybe BuildConfig -> Maybe Runnable ->
GOOLState -> ProgData -> Doc
makeBuild :: Maybe DocConfig
-> Maybe BuildConfig
-> Maybe Runnable
-> GOOLState
-> ProgData
-> Doc
makeBuild Maybe DocConfig
d Maybe BuildConfig
b Maybe Runnable
r GOOLState
s ProgData
p = [CodeHarness] -> Doc
forall c. RuleTransformer c => [c] -> Doc
genMake [Ch {
buildConfig :: Maybe BuildConfig
buildConfig = Maybe BuildConfig
b,
runnable :: Maybe Runnable
runnable = Maybe Runnable
r,
goolState :: GOOLState
goolState = GOOLState
s,
progData :: ProgData
progData = ProgData
p,
docConfig :: Maybe DocConfig
docConfig = Maybe DocConfig
d}]