fortran-vars-0.1.0: src/Language/Fortran/Vars/Assignments.hs
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Language.Fortran.Vars.Assignments
( allAssignStmts
)
where
import Data.Data ( Data )
import Data.List ( foldl' )
import qualified Data.Map as M
import Data.Generics.Uniplate.Data ( universeBi )
import Language.Fortran.Analysis ( Analysis )
import Language.Fortran.AST ( ProgramUnit
, Statement(..)
, DataGroup(..)
, Expression(..)
, Declarator(..)
, Value(..)
, aStrip
)
import Language.Fortran.Util.Position ( Spanned(..) )
import Language.Fortran.Extras.Encoding
( pprint77l )
import Language.Fortran.Vars.StructureTable
( collectStructures )
import Language.Fortran.Vars.SymbolTable
( collectSymbols )
import Language.Fortran.Vars.Types
( SymbolTable
, StructureTable
, SymbolTableEntry(..)
, Dimensions
, Type(..)
, SemType(..)
, TypeError(..)
, typeError
)
import Language.Fortran.Vars.TypeCheck
( typeOf )
-- | Method to retrieve the type of the lhs and expression on the rhs of all
-- assign like statements: expression assign, parameter, data and declarations
-- It returns the type of the lhs due to the expansion of array types to scalar
-- types in datagroups and declarations and returns TypeError's for the
-- expressions it can't calculate.
allAssignStmts
:: forall a
. Data a
=> ProgramUnit (Analysis a)
-> [Either TypeError (Type, Expression (Analysis a))]
allAssignStmts pu =
let
symt = collectSymbols pu
strt = collectStructures symt pu
in
[ (, e) <$> ty
| StExpressionAssign _ _ v e <- universeBi pu :: [Statement (Analysis a)]
, let ty = typeOf strt symt v
]
<> [ (, e) <$> ty
| StParameter _ _ decls <- universeBi pu :: [Statement (Analysis a)]
, DeclVariable _ _ v _ (Just e) <- aStrip decls
, let ty = typeOf strt symt v
]
<> [ res
| StData _ _ groups <- universeBi pu :: [Statement (Analysis a)]
, res <- dataGroups strt symt (aStrip groups)
]
<> [ res
| StDeclaration _ _ _ _ decls <-
universeBi pu :: [Statement (Analysis a)]
, res <- declarators strt symt $ aStrip decls
]
-- | Deal with data groups
dataGroups
:: StructureTable
-> SymbolTable
-> [DataGroup (Analysis a)]
-> [Either TypeError (Type, Expression (Analysis a))]
dataGroups strt symt = concatMap f
where
f (DataGroup _ _ vas eas) =
let vs = aStrip vas
es = aStrip eas
expandedVs = concatMap (expandArrays strt symt) vs
g (Left err) _ = Left err
g (Right ty ) e = Right (ty, e)
in zipWith g expandedVs es
-- | Expands declarators to lhs type and rhs expression
declarators
:: StructureTable
-> SymbolTable
-> [Declarator (Analysis a)]
-> [Either TypeError (Type, Expression (Analysis a))]
declarators strt symt = concatMap f where
f (DeclVariable _ _ v _ (Just e)) = pure $ (, e) <$> typeOf strt symt v
f d@(DeclArray _ _ (ExpValue _ s (ValVariable v)) _ _ (Just (ExpInitialisation _ _ vals)))
= case M.lookup v symt of
Just (SVariable (TArray ty (Just dims)) _) ->
let tys = expandDimensions dims ty
vals' = aStrip vals
in if length tys /= length vals'
then
pure
. Left
. typeError s
. mconcat
$ [ "Length of lhs and rhs in declarator do not match: "
, ": "
, pprint77l d
]
else fmap Right $ zip (expandDimensions dims ty) $ aStrip vals
_ ->
pure
. Left
. typeError s
$ "Unexpected lhs in array declaration at: "
<> pprint77l d
f _ = [] -- All other cases have no initial values
-- | Expands arrays to give a list of types given the length of an array
expandArrays
:: StructureTable
-> SymbolTable
-> Expression (Analysis a)
-> [Either TypeError Type]
expandArrays strt symt e = case e of
ExpValue _ _ (ValVariable var) -> case M.lookup var symt of
Just (SVariable (TArray ty (Just dims)) _) ->
expandDimensions dims (Right ty)
Just (SVariable ty _) -> [Right ty]
_ ->
pure
. Left
. typeError (getSpan e)
$ "Got unexpected lhs type: "
<> pprint77l e
_ -> pure $ typeOf strt symt e
-- | Function to expand dimensions into appropriate number of types for use in
-- other expand functions
expandDimensions :: Dimensions -> a -> [a]
expandDimensions dims =
replicate (foldl' (\acc (x, y) -> abs (y - x + 1) * acc) 1 dims)