packages feed

fortran-vars-0.4.0: src/Language/Fortran/Vars/Eval/FortranSrc/Translate.hs

{- | Translate fortran-vars Fortran types and values to fortran-src
     (Language.Fortran.Repr).

TODO

  * BYTE is apparently LOGICAL(1). Or INTEGER(1) (same thing?). Could make a
    special check for that.
-}

module Language.Fortran.Vars.Eval.FortranSrc.Translate where

import qualified Language.Fortran.Vars.Rep as FV
import qualified Language.Fortran.AST.Literal.Boz as AST

import Language.Fortran.Repr
import Language.Fortran.Repr.Type.Array

import GHC.Float ( float2Double )
import qualified Data.Text as Text
import qualified Data.List.NonEmpty as NonEmpty

translateFType :: FType -> FV.SemType
translateFType = \case
  MkFScalarType fsty -> translateFScalarType fsty
  MkFArrayType  fat  -> translateFArrayType  fat

translateFScalarType :: FScalarType -> FV.SemType
translateFScalarType = \case
  FSTInt     ftint  -> kinded FV.TInteger ftint
  FSTReal    ftreal -> kinded FV.TReal    ftreal
  FSTComplex ftreal -> kinded FV.TComplex (FTComplexWrapper ftreal)
  FSTLogical ftint  -> kinded FV.TInteger ftint
  --FSTLogical ftint  -> kinded FV.TLogical ftint
  FSTString  n      -> FV.TCharacter (FV.CharLenInt (fromIntegral n)) 1
  FSTCustom  ty     -> FV.TCustom ty
  where kinded f = f . translateFKind . printFKind

translateFArrayType :: FArrayType -> FV.SemType
translateFArrayType (FArrayType fsty shape) =
    FV.TArray (translateFScalarType fsty) (translateShape shape)

translateFKind :: FKindLit -> FV.Kind
translateFKind = fromIntegral

-- | Note that Fortran defaults to 1-indexed arrays.
translateShape :: Shape -> FV.Dimensions
translateShape =
      FV.DimsExplicitShape
    . NonEmpty.fromList
    . map (\ub -> FV.Dim (Just 1) (Just (fromIntegral ub)))
    . getShape

--------------------------------------------------------------------------------

translateFValue :: FValue -> Either String FV.ExpVal
translateFValue = \case
  MkFScalarValue fsv  -> translateFScalarValue fsv

translateFScalarValue :: FScalarValue -> Either String FV.ExpVal
translateFScalarValue = \case
  FSVInt     fint      -> Right $ FV.Int  $ fIntUOp fromIntegral fint
  FSVReal    freal     -> Right $ FV.Real $ fRealUOp' float2Double id freal
  FSVComplex _fcomplex -> Left "ExpVal doesn't support complex values"
  FSVLogical fint -> Right $ FV.Logical $ fLogicalToBool fint
  FSVString  t -> Right $ FV.Str $ Text.unpack t

--------------------------------------------------------------------------------

translateExpVal :: FV.ExpVal -> FScalarValue
translateExpVal = \case
  FV.Int     i   -> FSVInt     $ FInt4 $ fromIntegral i

  -- TODO getting some precisions errors, fortran-src over-precise? unsure where
  -- coming from, but need to compare using an epsilon
  FV.Real    r   -> FSVReal    $ FReal8 r

  FV.Str     s   -> FSVString  $ Text.pack s
  FV.Logical b   -> FSVLogical $ FInt4 $ fLogicalNumericFromBool b

  -- TODO fortran-vars always converts BOZs at INTEGER(2)
  FV.Boz     boz -> FSVInt     $ FInt2 $ AST.bozAsTwosComp boz