packages feed

fortran-vars-0.3.0: src/Language/Fortran/Vars/StorageClass.hs

module Language.Fortran.Vars.StorageClass
  ( processStorageClass
  )
where

import           Data.Data                      ( Data )
import           Data.List                      ( foldl' )
import qualified Data.Map                      as M
import           Language.Fortran.Analysis      ( Analysis
                                                , srcName
                                                )
import           Language.Fortran.AST           ( aStrip
                                                , Declarator(..)
                                                , Expression(..)
                                                , Name
                                                , Statement(..)
                                                , Value(..)
                                                )

import           Language.Fortran.Vars.Types
                                                ( SymbolTableEntry(..)
                                                , MemoryBlock(..)
                                                , ProgramUnitModel
                                                , StorageClass(..)
                                                )

storageClassStmt
  :: Data a => ProgramUnitModel -> Statement (Analysis a) -> ProgramUnitModel
storageClassStmt puModel (StAutomatic _ _ decls) = foldl' f
                                                          puModel
                                                          (aStrip decls)
 where
  f m (Declarator _ _ varExp _ _ _) =
    updateStorageClass (srcName varExp) Automatic m
storageClassStmt puModel (StSave _ _ (Just exps)) = foldl' f
                                                           puModel
                                                           (aStrip exps)
 where
  f m e@(ExpValue _ _ (ValVariable _)) =
    updateStorageClass (srcName e) Static m
  f m _ = m
storageClassStmt puModel _ = puModel

updateStorageClass
  :: Name -> StorageClass -> ProgramUnitModel -> ProgramUnitModel
updateStorageClass symbol stClass m@(symTable, storageTable) =
  case M.lookup symbol symTable of
    Just (SVariable _ (blockName, _)) ->
      case M.lookup blockName storageTable of
        Just block | storageClass block /= stClass ->
          let blk = block { storageClass = stClass }
          in  (symTable, M.insert blockName blk storageTable)
        _ -> m
    _ -> m

-- | Given all of the 'Statement's in a program as well as a 'ProgramUnitModel', produce a new
-- 'ProgramUnitModel' where the 'StorageClass's of each symbol have been determined
processStorageClass
  :: Data a => [Statement (Analysis a)] -> ProgramUnitModel -> ProgramUnitModel
processStorageClass stmts puModel0 = foldl' storageClassStmt puModel0 stmts