packages feed

fortran-src-0.16.2: src/Language/Fortran/AST/Literal/Complex.hs

-- | Supporting definitions for COMPLEX literals.

module Language.Fortran.AST.Literal.Complex where

import Language.Fortran.AST.Common ( Name )
import Language.Fortran.AST.Literal ( KindParam )
import Language.Fortran.AST.Literal.Real
import Language.Fortran.Util.Position ( SrcSpan, Spanned )

import GHC.Generics                   ( Generic )
import Data.Data                      ( Data, Typeable )
import Control.DeepSeq                ( NFData )
import Text.PrettyPrint.GenericPretty ( Out )
import Language.Fortran.Util.FirstParameter  ( FirstParameter )
import Language.Fortran.Util.SecondParameter ( SecondParameter )
import Language.Fortran.AST.Annotated ( Annotated )

-- | A COMPLEX literal, composed of a real part and an imaginary part.
--
-- Fortran has lots of rules on how COMPLEX literals are defined and used in
-- various contexts. To support all that, we define the syntactic structure
-- 'ComplexLit' to wrap all the parsing rules. Then during a analysis pass, you
-- may (attempt to) convert these into a more regular type, like a Haskell
-- @(Double, Double)@ tuple.
data ComplexLit a = ComplexLit
  { complexLitAnno     :: a
  , complexLitPos      :: SrcSpan
  , complexLitRealPart :: ComplexPart a
  , complexLitImagPart :: ComplexPart a
  } deriving stock    (Eq, Ord, Show, Data, Typeable, Generic, Functor)
    deriving anyclass (NFData, Out)

instance FirstParameter  (ComplexLit a) a
instance Annotated       ComplexLit
instance SecondParameter (ComplexLit a) SrcSpan
instance Spanned         (ComplexLit a)

-- | A part (either real or imaginary) of a complex literal.
--
-- Since Fortran 2003, complex literal parts support named constants, which must
-- be resolved in context at compile time (R422, R423).
--
-- Some compilers also allow constant expressions for the parts, and must
-- evaluate at compile time. That's not allowed in any standard. Apparently,
-- gfortran and ifort don't allow it, while nvfortran does. See:
-- https://fortran-lang.discourse.group/t/complex-constants-and-variables/2909/3
--
-- We specifically avoid supporting that by defining complex parts without being
-- mutually recursive with 'Expression'.
data ComplexPart a
  = ComplexPartReal   a SrcSpan RealLit (Maybe (KindParam a)) -- ^ signed real lit
  | ComplexPartInt    a SrcSpan String  (Maybe (KindParam a)) -- ^ signed int  lit
  | ComplexPartNamed  a SrcSpan Name                          -- ^ named constant
    deriving stock    (Eq, Ord, Show, Data, Typeable, Generic, Functor)
    deriving anyclass (NFData, Out)

instance FirstParameter  (ComplexPart a) a
instance Annotated       ComplexPart
instance SecondParameter (ComplexPart a) SrcSpan
instance Spanned         (ComplexPart a)

-- | Is the given COMPLEX literal "pure", i.e. does it have no named constant
--   components?
complexLitIsPure :: ComplexLit a -> Bool
complexLitIsPure c =
    check (complexLitRealPart c) && check (complexLitImagPart c)
  where check = \case ComplexPartNamed{} -> False
                      _                  -> True