{-# LANGUAGE LambdaCase #-}

module Language.Fortran.Transformer
  ( transform
  , transformWithModFiles
  , Transformation(..)
  , defaultTransformations
  ) where

import Data.Map (empty)
import Data.Data

import Language.Fortran.Util.ModFile
import Language.Fortran.Transformation.TransformMonad (Transform, runTransform)
import Language.Fortran.Transformation.Disambiguation.Function
import Language.Fortran.Transformation.Disambiguation.Intrinsic
import Language.Fortran.Transformation.Grouping
import Language.Fortran.AST (ProgramFile)
import Language.Fortran.Version (FortranVersion(..))

data Transformation =
    GroupForall
  | GroupDo
  | GroupLabeledDo
  | DisambiguateFunction
  | DisambiguateIntrinsic
  deriving (Transformation -> Transformation -> Bool
(Transformation -> Transformation -> Bool)
-> (Transformation -> Transformation -> Bool) -> Eq Transformation
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Transformation -> Transformation -> Bool
$c/= :: Transformation -> Transformation -> Bool
== :: Transformation -> Transformation -> Bool
$c== :: Transformation -> Transformation -> Bool
Eq)

transformationMapping :: Data a => Transformation -> Transform a ()
transformationMapping :: forall a. Data a => Transformation -> Transform a ()
transformationMapping = \case
  Transformation
GroupForall           -> Transform a ()
forall a. Data a => Transform a ()
groupForall
  Transformation
GroupDo               -> Transform a ()
forall a. Data a => Transform a ()
groupDo
  Transformation
GroupLabeledDo        -> Transform a ()
forall a. Data a => Transform a ()
groupLabeledDo
  Transformation
DisambiguateFunction  -> Transform a ()
forall a. Data a => Transform a ()
disambiguateFunction
  Transformation
DisambiguateIntrinsic -> Transform a ()
forall a. Data a => Transform a ()
disambiguateIntrinsic

transformWithModFiles :: Data a => ModFiles -> [ Transformation ] -> ProgramFile a -> ProgramFile a
transformWithModFiles :: forall a.
Data a =>
ModFiles -> [Transformation] -> ProgramFile a -> ProgramFile a
transformWithModFiles ModFiles
mods [Transformation]
trs = TypeEnv
-> ModuleMap -> Transform a () -> ProgramFile a -> ProgramFile a
forall a.
Data a =>
TypeEnv
-> ModuleMap -> Transform a () -> ProgramFile a -> ProgramFile a
runTransform (ModFiles -> TypeEnv
combinedTypeEnv ModFiles
mods) (ModFiles -> ModuleMap
combinedModuleMap ModFiles
mods) Transform a ()
trans
  where
    trans :: Transform a ()
trans = (Transformation -> Transform a ())
-> [Transformation] -> Transform a ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Transformation -> Transform a ()
forall a. Data a => Transformation -> Transform a ()
transformationMapping [Transformation]
trs

transform :: Data a => [ Transformation ] -> ProgramFile a -> ProgramFile a
transform :: forall a.
Data a =>
[Transformation] -> ProgramFile a -> ProgramFile a
transform [Transformation]
trs = TypeEnv
-> ModuleMap -> Transform a () -> ProgramFile a -> ProgramFile a
forall a.
Data a =>
TypeEnv
-> ModuleMap -> Transform a () -> ProgramFile a -> ProgramFile a
runTransform TypeEnv
forall k a. Map k a
empty ModuleMap
forall k a. Map k a
empty Transform a ()
trans
  where
    trans :: Transform a ()
trans = (Transformation -> Transform a ())
-> [Transformation] -> Transform a ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Transformation -> Transform a ()
forall a. Data a => Transformation -> Transform a ()
transformationMapping [Transformation]
trs

-- | The default post-parse AST transformations for each Fortran version.
--
-- Note that some of these may not be commutative with each other. Specifically,
-- the DO groupings are written so labeled (nonblock) DO grouping must occur
-- first, followed by block DO grouping.
defaultTransformations :: FortranVersion -> [Transformation]
defaultTransformations :: FortranVersion -> [Transformation]
defaultTransformations = \case
  FortranVersion
Fortran66 ->
    [ Transformation
GroupLabeledDo
    , Transformation
DisambiguateIntrinsic
    , Transformation
DisambiguateFunction
    ]
  FortranVersion
Fortran77         -> FortranVersion -> [Transformation]
defaultTransformations FortranVersion
Fortran66
  FortranVersion
Fortran77Legacy   ->
    [ Transformation
GroupLabeledDo
    , Transformation
GroupDo
    , Transformation
DisambiguateIntrinsic
    , Transformation
DisambiguateFunction
    ]
  FortranVersion
Fortran77Extended -> FortranVersion -> [Transformation]
defaultTransformations FortranVersion
Fortran77Legacy
  FortranVersion
Fortran90   -> FortranVersion -> [Transformation]
defaultTransformations FortranVersion
Fortran77Extended
  FortranVersion
Fortran95   -> FortranVersion -> [Transformation]
defaultTransformations FortranVersion
Fortran77Extended
  FortranVersion
Fortran2003 -> FortranVersion -> [Transformation]
defaultTransformations FortranVersion
Fortran77Extended
  FortranVersion
Fortran2008 -> FortranVersion -> [Transformation]
defaultTransformations FortranVersion
Fortran2003