fortran-vars-0.4.0: src/Language/Fortran/Vars/SymbolTable/Arrays.hs
module Language.Fortran.Vars.SymbolTable.Arrays where
import Language.Fortran.AST
import Language.Fortran.Vars.Eval ( eval' )
import Language.Fortran.Vars.Types ( ExpVal(..), SymbolTable, Dim(..), Dims(..), Dimensions )
import Control.Monad.Except
--import Data.List.NonEmpty ( NonEmpty( (:|) ) )
resolveDims
:: SymbolTable -> [DimensionDeclarator a] -> Maybe Dimensions
resolveDims symt dds
-- We assume array type from a quick look at the dimension declarators.
| any dimDeclLooksLikeAssumedSize dds =
case resolveDimsAssumedSize symt dds of
Left _err -> Nothing -- discard errors/warnings :(
Right (Nothing, x) -> Just $ DimsAssumedSize Nothing x
-- resolveDimsAssumedSize can't return an empty list. Clumsy code means
-- we don't prove this in types.
Right (Just (a:as), x) -> Just $ DimsAssumedSize (Just (a :| as)) x
Right (Just [], _x) -> error "impossible"
| any dimDeclLooksLikeAssumedShape dds =
case resolveDimsAssumedShape symt dds of
Left _err -> Nothing -- discard errors/warnings :(
Right [] -> error "empty DimensionDeclarator list (should not be parseable)"
Right (a:as) -> Just $ DimsAssumedShape $ a :| as
| otherwise =
case resolveDimsExplicitShape symt dds of
Left _err -> Nothing -- discard errors/warnings :(
Right [] -> error "empty DimensionDeclarator list (should not be parseable)"
Right (a:as) -> Just $ DimsExplicitShape $ a :| as
-- | Assumed-size arrays have the special 'ValStar' upper bound (whereas
-- explicit-shape and assumed-shape arrays never do).
dimDeclLooksLikeAssumedSize :: DimensionDeclarator a -> Bool
dimDeclLooksLikeAssumedSize = \case
DimensionDeclarator _ _ _ (Just (ExpValue _ _ ValStar)) -> True
_ -> False
-- | Assumed-shape arrays have no upper bounds (whereas explicit-shape and
-- assumed-size arrays always do).
dimDeclLooksLikeAssumedShape :: DimensionDeclarator a -> Bool
dimDeclLooksLikeAssumedShape = \case
DimensionDeclarator _ _ _ Nothing -> True
_ -> False
evalStaticDimBoundExpr :: SymbolTable -> Expression a -> Either String Int
evalStaticDimBoundExpr symt expr =
case eval' symt expr of
Right (Int val) -> pure val
Right{} -> throwError $ "wrong type for array dimension bound"
Left err -> throwError $ "error evaluating array dimension bound expression: "<>err
-- | Returns @'Right' 'Nothing'@ for dynamic bounds (e.g. which use dummy vars).
evalDynamicDimBoundExpr :: SymbolTable -> Expression a -> Either String (Maybe Int)
evalDynamicDimBoundExpr symt expr =
case eval' symt expr of
Right (Int val) -> pure $ Just val
Right{} -> throwError $ "wrong type for array dimension bound"
Left{} -> pure Nothing
resolveDimsExplicitShape
:: SymbolTable -> [DimensionDeclarator a] -> Either String [Dim (Maybe Int)]
resolveDimsExplicitShape symt = traverse (resolveDimExplicitShape symt)
resolveDimExplicitShape
:: SymbolTable -> DimensionDeclarator a -> Either String (Dim (Maybe Int))
resolveDimExplicitShape symt (DimensionDeclarator _ _ mlb mub) =
case mub of
Nothing -> throwError "explicit-shape array must have an upper bound for every dimension"
Just ubExpr -> do
lb <- case mlb of
Nothing -> pure $ Just 1
Just lbExpr -> evalDynamicDimBoundExpr symt lbExpr
ub <- evalDynamicDimBoundExpr symt ubExpr
pure $ Dim lb ub
resolveDimsAssumedShape
:: SymbolTable -> [DimensionDeclarator a] -> Either String [Maybe Int]
resolveDimsAssumedShape symt = traverse go
where
go (DimensionDeclarator _ _ mlb mub) =
case mub of
Just{} ->
throwError "assumed-shape array can't have a dimension with an upper bound"
Nothing ->
case mlb of
Nothing -> pure $ Just 1
Just lbExpr -> evalDynamicDimBoundExpr symt lbExpr
resolveDimsAssumedSize
:: SymbolTable -> [DimensionDeclarator a]
-> Either String (Maybe [Dim (Maybe Int)], Maybe Int)
resolveDimsAssumedSize symt = \case
[] -> throwError "resolveDimsAssumedSize: array can't have zero dimensions"
d:[] ->
case resolveDimStar symt d of
Left err -> Left err
Right a -> Right (Nothing, a)
ds ->
case go [] ds of
Left err -> Left err
Right (l, r) -> Right (Just l, r)
where
go
:: [Dim (Maybe Int)] -> [DimensionDeclarator a]
-> Either String ([Dim (Maybe Int)], Maybe Int)
go ds = \case
[] -> Right (reverse ds, Nothing)
dd:[] ->
case resolveDimStar symt dd of
Left err -> Left err
Right d -> Right (ds, d)
dd:dds ->
case resolveDimExplicitShape symt dd of
Left err -> Left err
Right d -> go (d:ds) dds
resolveDimStar
:: SymbolTable -> DimensionDeclarator a -> Either String (Maybe Int)
resolveDimStar symt (DimensionDeclarator _ _ mlb mub) = do
lb <- case mlb of
Nothing -> pure $ Just 1
Just lbExpr -> evalDynamicDimBoundExpr symt lbExpr
() <- resolveDimBoundStar mub
pure lb
resolveDimBoundStar :: Maybe (Expression a) -> Either String ()
resolveDimBoundStar = \case
Just (ExpValue _ _ ValStar) -> pure ()
Just{} -> throwError "resolveDimBoundStar: expression wasn't a ValStar"
Nothing -> throwError "resolveDimBoundStar: upper bound must be present"