fortran-vars-0.1.0: src/Language/Fortran/Vars/Kind.hs
{-# LANGUAGE LambdaCase #-}
module Language.Fortran.Vars.Kind
( module Language.Fortran.Vars.Kind
, kindOfBaseType
, getTypeSize
, setTypeSize
, deriveSemTypeFromBaseType
) where
import Data.Either ( either )
import Data.Maybe ( fromJust )
import Language.Fortran.Analysis ( Analysis )
import Language.Fortran.Analysis.Types
( deriveSemTypeFromBaseType )
import Language.Fortran.AST ( BaseType(..)
, Expression(..)
, Selector(..)
, TypeSpec(..)
, Value(..)
)
import Language.Fortran.Analysis.SemanticTypes
( kindOfBaseType
, getTypeSize
, setTypeSize
)
import Language.Fortran.Vars.Errors
( invalidArg )
import Language.Fortran.Vars.Eval
( eval' )
import Language.Fortran.Vars.Types
( ExpVal(..)
, Type(..)
, SemType(..)
, CharacterLen(..)
, SymbolTable
)
baseToType :: BaseType -> Type
baseToType = deriveSemTypeFromBaseType
getTypeKind :: Type -> Maybe Int
getTypeKind = getTypeSize
setTypeKind :: Type -> Maybe Int -> Type
setTypeKind = setTypeSize
-- | Given an 'ExpVal', return the 'Type' of that value
typeOfExpVal :: ExpVal -> Type
typeOfExpVal = \case
Int _ -> TInteger 4
Real _ -> TReal 4
Logical _ -> TLogical 4
Str _ -> TCharacter (CharLenInt 1) 1
Boz _ -> error "BOZ constant is type-less"
-- | Given an 'ExpVal', return true if it is a 'Str', else false
isStr :: ExpVal -> Bool
isStr e = case e of
Str _ -> True
_ -> False
-- | Given an 'ExpVal' determine the kind of it
getKindOfExpVal :: ExpVal -> Int
getKindOfExpVal (Str s) = length s
getKindOfExpVal ev = fromJust . getTypeSize . typeOfExpVal $ ev
-- | Convert an 'ExpVal' to an 'Int'. This will fail if the
-- 'ExpVal' is not already known to be an 'Int'
toInt :: ExpVal -> Int
toInt (Int i) = i
toInt e = invalidArg "toInt" [e]
-- | Given a 'SymbolTable', a 'TypeSpec' for a variable, and possibly an 'Expression'
-- for the length of a character array, determine the kind of that variable
-- The charLength also works for nonstandard kind
getKind
:: SymbolTable
-> TypeSpec (Analysis a)
-> Maybe (Expression (Analysis a))
-> Maybe Int
getKind symTable (TypeSpec _ _ bt selector) charLength =
let evalMaybeKind kind =
either (const Nothing) (Just . toInt) $ eval' symTable kind
in case charLength of
Just charLen -> evalMaybeKind charLen
Nothing -> case selector of
Just (Selector _ _ _ (Just kindExp)) ->
let k' = kindExp
in case k' of
ExpValue _ _ ValStar -> Nothing
_ -> evalMaybeKind kindExp
Just (Selector _ _ (Just lengthExp) _) ->
let l' = lengthExp
in case l' of
ExpValue _ _ ValStar -> Nothing
_ -> evalMaybeKind lengthExp
_ -> Just $ kindOfBaseType bt