packages feed

fortran-vars 0.3.1 → 0.4.0

raw patch · 29 files changed

+1244/−597 lines, 29 filesdep +mtldep ~fortran-srcdep ~fortran-src-extrasPVP ok

version bump matches the API change (PVP)

Dependencies added: mtl

Dependency ranges changed: fortran-src, fortran-src-extras

API changes (from Hackage documentation)

- Language.Fortran.Vars.Operation: binaryOp :: BinaryOp -> ExpVal -> ExpVal -> ExpVal
- Language.Fortran.Vars.Operation: binaryOp' :: BinaryOp -> ExpVal -> ExpVal -> Either String ExpVal
- Language.Fortran.Vars.Operation: binaryTransformEither :: (a -> a -> Either String b) -> Either String a -> Either String a -> Either String b
- Language.Fortran.Vars.Operation: intrinsicFunctionCall :: String -> [ExpVal] -> Either String ExpVal
- Language.Fortran.Vars.Operation: nonLogicalToLogical :: ExpVal -> Either String Bool
- Language.Fortran.Vars.Operation: transformEither :: (a -> Either String b) -> Either String a -> Either String b
- Language.Fortran.Vars.Operation: transformEitherList :: ([a] -> Either String b) -> [Either String a] -> Either String b
- Language.Fortran.Vars.Operation: unaryOp :: UnaryOp -> ExpVal -> ExpVal
- Language.Fortran.Vars.Operation: unaryOp' :: UnaryOp -> ExpVal -> Either String ExpVal
- Language.Fortran.Vars.Operation: valueToExpVal :: SrcSpan -> Value a -> ExpVal
- Language.Fortran.Vars.Operation: valueToExpVal' :: SrcSpan -> Value a -> Either String ExpVal
- Language.Fortran.Vars.Types: SDummy :: Type -> SymbolTableEntry
- Language.Fortran.Vars.Types: SExternal :: Type -> SymbolTableEntry
- Language.Fortran.Vars.Types: SParameter :: Type -> ExpVal -> SymbolTableEntry
- Language.Fortran.Vars.Types: SVariable :: Type -> Location -> SymbolTableEntry
- Language.Fortran.Vars.Types: [dumType] :: SymbolTableEntry -> Type
- Language.Fortran.Vars.Types: [extType] :: SymbolTableEntry -> Type
- Language.Fortran.Vars.Types: [parType] :: SymbolTableEntry -> Type
- Language.Fortran.Vars.Types: [parVal] :: SymbolTableEntry -> ExpVal
- Language.Fortran.Vars.Types: [varLoc] :: SymbolTableEntry -> Location
- Language.Fortran.Vars.Types: [varType] :: SymbolTableEntry -> Type
- Language.Fortran.Vars.Types: data SymbolTableEntry
- Language.Fortran.Vars.Types: instance Control.DeepSeq.NFData Language.Fortran.Vars.Types.ExpVal
- Language.Fortran.Vars.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.Fortran.AST.ProgramUnitName
- Language.Fortran.Vars.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.Fortran.Vars.Types.ExpVal
- Language.Fortran.Vars.Types: instance Data.Aeson.Types.FromJSON.FromJSON Language.Fortran.Vars.Types.SymbolTableEntry
- Language.Fortran.Vars.Types: instance Data.Aeson.Types.FromJSON.FromJSONKey Language.Fortran.AST.ProgramUnitName
- Language.Fortran.Vars.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.Fortran.AST.ProgramUnitName
- Language.Fortran.Vars.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.Fortran.Vars.Types.ExpVal
- Language.Fortran.Vars.Types: instance Data.Aeson.Types.ToJSON.ToJSON Language.Fortran.Vars.Types.SymbolTableEntry
- Language.Fortran.Vars.Types: instance Data.Aeson.Types.ToJSON.ToJSONKey Language.Fortran.AST.ProgramUnitName
- Language.Fortran.Vars.Types: instance Data.Data.Data Language.Fortran.Vars.Types.ExpVal
- Language.Fortran.Vars.Types: instance Data.Data.Data Language.Fortran.Vars.Types.SymbolTableEntry
- Language.Fortran.Vars.Types: instance GHC.Classes.Eq Language.Fortran.Vars.Types.ExpVal
- Language.Fortran.Vars.Types: instance GHC.Classes.Eq Language.Fortran.Vars.Types.SymbolTableEntry
- Language.Fortran.Vars.Types: instance GHC.Classes.Ord Language.Fortran.Vars.Types.ExpVal
- Language.Fortran.Vars.Types: instance GHC.Classes.Ord Language.Fortran.Vars.Types.SymbolTableEntry
- Language.Fortran.Vars.Types: instance GHC.Generics.Generic Language.Fortran.Vars.Types.ExpVal
- Language.Fortran.Vars.Types: instance GHC.Generics.Generic Language.Fortran.Vars.Types.SymbolTableEntry
- Language.Fortran.Vars.Types: instance GHC.Show.Show Language.Fortran.Vars.Types.ExpVal
- Language.Fortran.Vars.Types: instance GHC.Show.Show Language.Fortran.Vars.Types.SymbolTableEntry
- Language.Fortran.Vars.Types: type Location = (MemoryBlockName, Offset)
- Language.Fortran.Vars.Types: type MemoryBlockName = Name
- Language.Fortran.Vars.Types: type Offset = Int
- Language.Fortran.Vars.Types: type SymbolTable = Map Name SymbolTableEntry
+ Language.Fortran.Vars.Eval.Deprecated: eval :: SymbolTable -> Expression a -> ExpVal
+ Language.Fortran.Vars.Eval.Deprecated: eval' :: SymbolTable -> Expression a -> Either String ExpVal
+ Language.Fortran.Vars.Eval.Deprecated: evalWithShortcircuit :: SymbolTable -> Expression a -> Either String ExpVal
+ Language.Fortran.Vars.Eval.Deprecated.Operation: binaryOp :: BinaryOp -> ExpVal -> ExpVal -> ExpVal
+ Language.Fortran.Vars.Eval.Deprecated.Operation: binaryOp' :: BinaryOp -> ExpVal -> ExpVal -> Either String ExpVal
+ Language.Fortran.Vars.Eval.Deprecated.Operation: binaryTransformEither :: (a -> a -> Either String b) -> Either String a -> Either String a -> Either String b
+ Language.Fortran.Vars.Eval.Deprecated.Operation: intrinsicFunctionCall :: String -> [ExpVal] -> Either String ExpVal
+ Language.Fortran.Vars.Eval.Deprecated.Operation: nonLogicalToLogical :: ExpVal -> Either String Bool
+ Language.Fortran.Vars.Eval.Deprecated.Operation: transformEither :: (a -> Either String b) -> Either String a -> Either String b
+ Language.Fortran.Vars.Eval.Deprecated.Operation: transformEitherList :: ([a] -> Either String b) -> [Either String a] -> Either String b
+ Language.Fortran.Vars.Eval.Deprecated.Operation: unaryOp :: UnaryOp -> ExpVal -> ExpVal
+ Language.Fortran.Vars.Eval.Deprecated.Operation: unaryOp' :: UnaryOp -> ExpVal -> Either String ExpVal
+ Language.Fortran.Vars.Eval.Deprecated.Operation: valueToExpVal :: SrcSpan -> Value a -> ExpVal
+ Language.Fortran.Vars.Eval.Deprecated.Operation: valueToExpVal' :: SrcSpan -> Value a -> Either String ExpVal
+ Language.Fortran.Vars.Eval.FortranSrc: Eval :: Eval' a -> Eval a
+ Language.Fortran.Vars.Eval.FortranSrc: [unEval] :: Eval a -> Eval' a
+ Language.Fortran.Vars.Eval.FortranSrc: instance Control.Monad.Error.Class.MonadError Language.Fortran.Repr.Eval.Value.Error Language.Fortran.Vars.Eval.FortranSrc.Eval
+ Language.Fortran.Vars.Eval.FortranSrc: instance Control.Monad.Reader.Class.MonadReader Language.Fortran.Vars.Types.SymbolTable.SymbolTable Language.Fortran.Vars.Eval.FortranSrc.Eval
+ Language.Fortran.Vars.Eval.FortranSrc: instance GHC.Base.Applicative Language.Fortran.Vars.Eval.FortranSrc.Eval
+ Language.Fortran.Vars.Eval.FortranSrc: instance GHC.Base.Functor Language.Fortran.Vars.Eval.FortranSrc.Eval
+ Language.Fortran.Vars.Eval.FortranSrc: instance GHC.Base.Monad Language.Fortran.Vars.Eval.FortranSrc.Eval
+ Language.Fortran.Vars.Eval.FortranSrc: instance Language.Fortran.Repr.Eval.Common.MonadFEval Language.Fortran.Vars.Eval.FortranSrc.Eval
+ Language.Fortran.Vars.Eval.FortranSrc: newtype Eval a
+ Language.Fortran.Vars.Eval.FortranSrc: runEval :: SymbolTable -> Eval a -> Either Error a
+ Language.Fortran.Vars.Eval.FortranSrc: type Eval' = ExceptT Error (Reader SymbolTable)
+ Language.Fortran.Vars.Eval.FortranSrc.Translate: translateExpVal :: ExpVal -> FScalarValue
+ Language.Fortran.Vars.Eval.FortranSrc.Translate: translateFArrayType :: FArrayType -> SemType
+ Language.Fortran.Vars.Eval.FortranSrc.Translate: translateFKind :: FKindLit -> Kind
+ Language.Fortran.Vars.Eval.FortranSrc.Translate: translateFScalarType :: FScalarType -> SemType
+ Language.Fortran.Vars.Eval.FortranSrc.Translate: translateFScalarValue :: FScalarValue -> Either String ExpVal
+ Language.Fortran.Vars.Eval.FortranSrc.Translate: translateFType :: FType -> SemType
+ Language.Fortran.Vars.Eval.FortranSrc.Translate: translateFValue :: FValue -> Either String ExpVal
+ Language.Fortran.Vars.Eval.FortranSrc.Translate: translateShape :: Shape -> Dimensions
+ Language.Fortran.Vars.Orphans: instance Data.Aeson.Types.FromJSON.FromJSON (Language.Fortran.Common.Array.Dim (GHC.Maybe.Maybe GHC.Types.Int))
+ Language.Fortran.Vars.Orphans: instance Data.Aeson.Types.FromJSON.FromJSON Language.Fortran.AST.ProgramUnitName
+ Language.Fortran.Vars.Orphans: instance Data.Aeson.Types.FromJSON.FromJSON Language.Fortran.Analysis.SemanticTypes.Dimensions
+ Language.Fortran.Vars.Orphans: instance Data.Aeson.Types.FromJSON.FromJSONKey Language.Fortran.AST.ProgramUnitName
+ Language.Fortran.Vars.Orphans: instance Data.Aeson.Types.ToJSON.ToJSON Language.Fortran.AST.ProgramUnitName
+ Language.Fortran.Vars.Orphans: instance Data.Aeson.Types.ToJSON.ToJSONKey Language.Fortran.AST.ProgramUnitName
+ Language.Fortran.Vars.Rep: Boz :: Boz -> ExpVal
+ Language.Fortran.Vars.Rep: CharLenColon :: CharacterLen
+ Language.Fortran.Vars.Rep: CharLenExp :: CharacterLen
+ Language.Fortran.Vars.Rep: CharLenInt :: Int -> CharacterLen
+ Language.Fortran.Vars.Rep: CharLenStar :: CharacterLen
+ Language.Fortran.Vars.Rep: Dim :: a -> a -> Dim a
+ Language.Fortran.Vars.Rep: DimsAssumedShape :: t a -> Dims (t :: Type -> TYPE LiftedRep) a
+ Language.Fortran.Vars.Rep: DimsAssumedSize :: Maybe (t (Dim a)) -> a -> Dims (t :: Type -> TYPE LiftedRep) a
+ Language.Fortran.Vars.Rep: DimsExplicitShape :: t (Dim a) -> Dims (t :: Type -> TYPE LiftedRep) a
+ Language.Fortran.Vars.Rep: Int :: Int -> ExpVal
+ Language.Fortran.Vars.Rep: Logical :: Bool -> ExpVal
+ Language.Fortran.Vars.Rep: Real :: Double -> ExpVal
+ Language.Fortran.Vars.Rep: Str :: String -> ExpVal
+ Language.Fortran.Vars.Rep: TArray :: SemType -> Dimensions -> SemType
+ Language.Fortran.Vars.Rep: TByte :: Kind -> SemType
+ Language.Fortran.Vars.Rep: TCharacter :: CharacterLen -> Kind -> SemType
+ Language.Fortran.Vars.Rep: TComplex :: Kind -> SemType
+ Language.Fortran.Vars.Rep: TCustom :: String -> SemType
+ Language.Fortran.Vars.Rep: TInteger :: Kind -> SemType
+ Language.Fortran.Vars.Rep: TLogical :: Kind -> SemType
+ Language.Fortran.Vars.Rep: TReal :: Kind -> SemType
+ Language.Fortran.Vars.Rep: [dimLower] :: Dim a -> a
+ Language.Fortran.Vars.Rep: [dimUpper] :: Dim a -> a
+ Language.Fortran.Vars.Rep: data CharacterLen
+ Language.Fortran.Vars.Rep: data Dim a
+ Language.Fortran.Vars.Rep: data Dims (t :: Type -> TYPE LiftedRep) a
+ Language.Fortran.Vars.Rep: data ExpVal
+ Language.Fortran.Vars.Rep: data SemType
+ Language.Fortran.Vars.Rep: dimensionsToTuples :: Dimensions -> Maybe [(Int, Int)]
+ Language.Fortran.Vars.Rep: instance Control.DeepSeq.NFData Language.Fortran.Vars.Rep.ExpVal
+ Language.Fortran.Vars.Rep: instance Data.Aeson.Types.FromJSON.FromJSON Language.Fortran.Vars.Rep.ExpVal
+ Language.Fortran.Vars.Rep: instance Data.Aeson.Types.ToJSON.ToJSON Language.Fortran.Vars.Rep.ExpVal
+ Language.Fortran.Vars.Rep: instance Data.Data.Data Language.Fortran.Vars.Rep.ExpVal
+ Language.Fortran.Vars.Rep: instance GHC.Classes.Eq Language.Fortran.Vars.Rep.ExpVal
+ Language.Fortran.Vars.Rep: instance GHC.Classes.Ord Language.Fortran.Vars.Rep.ExpVal
+ Language.Fortran.Vars.Rep: instance GHC.Generics.Generic Language.Fortran.Vars.Rep.ExpVal
+ Language.Fortran.Vars.Rep: instance GHC.Show.Show Language.Fortran.Vars.Rep.ExpVal
+ Language.Fortran.Vars.Rep: type Dimensions = Dims NonEmpty Maybe Int
+ Language.Fortran.Vars.Rep: type Kind = Int
+ Language.Fortran.Vars.Rep: type Type = SemType
+ Language.Fortran.Vars.SymbolTable.Arrays: dimDeclLooksLikeAssumedShape :: DimensionDeclarator a -> Bool
+ Language.Fortran.Vars.SymbolTable.Arrays: dimDeclLooksLikeAssumedSize :: DimensionDeclarator a -> Bool
+ Language.Fortran.Vars.SymbolTable.Arrays: evalDynamicDimBoundExpr :: SymbolTable -> Expression a -> Either String (Maybe Int)
+ Language.Fortran.Vars.SymbolTable.Arrays: evalStaticDimBoundExpr :: SymbolTable -> Expression a -> Either String Int
+ Language.Fortran.Vars.SymbolTable.Arrays: resolveDimBoundStar :: Maybe (Expression a) -> Either String ()
+ Language.Fortran.Vars.SymbolTable.Arrays: resolveDimExplicitShape :: SymbolTable -> DimensionDeclarator a -> Either String (Dim (Maybe Int))
+ Language.Fortran.Vars.SymbolTable.Arrays: resolveDimStar :: SymbolTable -> DimensionDeclarator a -> Either String (Maybe Int)
+ Language.Fortran.Vars.SymbolTable.Arrays: resolveDims :: SymbolTable -> [DimensionDeclarator a] -> Maybe Dimensions
+ Language.Fortran.Vars.SymbolTable.Arrays: resolveDimsAssumedShape :: SymbolTable -> [DimensionDeclarator a] -> Either String [Maybe Int]
+ Language.Fortran.Vars.SymbolTable.Arrays: resolveDimsAssumedSize :: SymbolTable -> [DimensionDeclarator a] -> Either String (Maybe [Dim (Maybe Int)], Maybe Int)
+ Language.Fortran.Vars.SymbolTable.Arrays: resolveDimsExplicitShape :: SymbolTable -> [DimensionDeclarator a] -> Either String [Dim (Maybe Int)]
+ Language.Fortran.Vars.Types: Dim :: a -> a -> Dim a
+ Language.Fortran.Vars.Types: DimsAssumedShape :: t a -> Dims (t :: Type -> TYPE LiftedRep) a
+ Language.Fortran.Vars.Types: DimsAssumedSize :: Maybe (t (Dim a)) -> a -> Dims (t :: Type -> TYPE LiftedRep) a
+ Language.Fortran.Vars.Types: DimsExplicitShape :: t (Dim a) -> Dims (t :: Type -> TYPE LiftedRep) a
+ Language.Fortran.Vars.Types: [dimLower] :: Dim a -> a
+ Language.Fortran.Vars.Types: [dimUpper] :: Dim a -> a
+ Language.Fortran.Vars.Types: data Dim a
+ Language.Fortran.Vars.Types: data Dims (t :: Type -> TYPE LiftedRep) a
+ Language.Fortran.Vars.Types: dimensionsToTuples :: Dimensions -> Maybe [(Int, Int)]
+ Language.Fortran.Vars.Types: dimensionsToTuples' :: Dimensions -> [(Int, Int)]
+ Language.Fortran.Vars.Types: dimsLength :: forall (t :: TYPE LiftedRep -> Type) a. Foldable t => Dims t a -> Int
+ Language.Fortran.Vars.Types: dimsTraverse :: forall (t :: Type -> Type) f a. (Traversable t, Applicative f) => Dims t (f a) -> f (Dims t a)
+ Language.Fortran.Vars.Types: getStaticArrayBounds :: Traversable t => Dims t (Maybe a) -> Maybe (Dims t a)
+ Language.Fortran.Vars.Types.SymbolTable: SDummy :: Type -> SymbolTableEntry
+ Language.Fortran.Vars.Types.SymbolTable: SExternal :: Type -> SymbolTableEntry
+ Language.Fortran.Vars.Types.SymbolTable: SParameter :: Type -> ExpVal -> SymbolTableEntry
+ Language.Fortran.Vars.Types.SymbolTable: SVariable :: Type -> Location -> SymbolTableEntry
+ Language.Fortran.Vars.Types.SymbolTable: [dumType] :: SymbolTableEntry -> Type
+ Language.Fortran.Vars.Types.SymbolTable: [extType] :: SymbolTableEntry -> Type
+ Language.Fortran.Vars.Types.SymbolTable: [parType] :: SymbolTableEntry -> Type
+ Language.Fortran.Vars.Types.SymbolTable: [parVal] :: SymbolTableEntry -> ExpVal
+ Language.Fortran.Vars.Types.SymbolTable: [varLoc] :: SymbolTableEntry -> Location
+ Language.Fortran.Vars.Types.SymbolTable: [varType] :: SymbolTableEntry -> Type
+ Language.Fortran.Vars.Types.SymbolTable: data SymbolTableEntry
+ Language.Fortran.Vars.Types.SymbolTable: instance Data.Aeson.Types.FromJSON.FromJSON Language.Fortran.Vars.Types.SymbolTable.SymbolTableEntry
+ Language.Fortran.Vars.Types.SymbolTable: instance Data.Aeson.Types.ToJSON.ToJSON Language.Fortran.Vars.Types.SymbolTable.SymbolTableEntry
+ Language.Fortran.Vars.Types.SymbolTable: instance Data.Data.Data Language.Fortran.Vars.Types.SymbolTable.SymbolTableEntry
+ Language.Fortran.Vars.Types.SymbolTable: instance GHC.Classes.Eq Language.Fortran.Vars.Types.SymbolTable.SymbolTableEntry
+ Language.Fortran.Vars.Types.SymbolTable: instance GHC.Classes.Ord Language.Fortran.Vars.Types.SymbolTable.SymbolTableEntry
+ Language.Fortran.Vars.Types.SymbolTable: instance GHC.Generics.Generic Language.Fortran.Vars.Types.SymbolTable.SymbolTableEntry
+ Language.Fortran.Vars.Types.SymbolTable: instance GHC.Show.Show Language.Fortran.Vars.Types.SymbolTable.SymbolTableEntry
+ Language.Fortran.Vars.Types.SymbolTable: type Location = (MemoryBlockName, Offset)
+ Language.Fortran.Vars.Types.SymbolTable: type MemoryBlockName = Name
+ Language.Fortran.Vars.Types.SymbolTable: type Offset = Int
+ Language.Fortran.Vars.Types.SymbolTable: type SymbolTable = Map Name SymbolTableEntry
- Language.Fortran.Vars.MemoryLocation: generateLinearizedIndexRange :: [Int] -> Int -> [(Int, Int)] -> Int -> Range
+ Language.Fortran.Vars.MemoryLocation: generateLinearizedIndexRange :: (Functor t, Foldable t) => [Int] -> Int -> t (Dim Int) -> Int -> Range
- Language.Fortran.Vars.Types: TArray :: SemType -> Maybe Dimensions -> SemType
+ Language.Fortran.Vars.Types: TArray :: SemType -> Dimensions -> SemType
- Language.Fortran.Vars.Types: type Dimensions = [(Int, Int)]
+ Language.Fortran.Vars.Types: type Dimensions = Dims NonEmpty Maybe Int

Files

CHANGELOG.md view
@@ -1,3 +1,16 @@+## 0.4.0 (22 Jun 2023)+  * Replace expression evaluator with fortran-src one+    * Interface changes are mostly non-breaking. Some behaviour may be slightly+      different due to INTEGER etc. constants using different types.+    * Old evaluator remains available at+      `Language.Fortran.Vars.Eval.Deprecated` (and still gets used by constant+      propagation code).+    * Short-circuiting evaluator uses the old evaluator. (This is feasible for+      the fortran-src evaluator, and is pending work.)+  * Use more precise array dimensions encoding+    * Breaking change.+  * Update to fortran-src 0.15+ ## 0.3.1 (22 Aug 2022)   * Update to fortran-src 0.10.2   * Do some type checking for logical operators used with non LOGICAL arguments
fortran-vars.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.34.4.+-- This file has been generated from package.yaml by hpack version 0.35.2. -- -- see: https://github.com/sol/hpack  name:           fortran-vars-version:        0.3.1+version:        0.4.0 synopsis:       Fortran memory model and other static analysis tools. description:    Various Fortran static analysis tools focusing on a memory model for Fortran types. Uses fortran-src for the syntax representation. category:       Language@@ -36,18 +36,24 @@       Language.Fortran.Vars.Equivalence       Language.Fortran.Vars.Errors       Language.Fortran.Vars.Eval+      Language.Fortran.Vars.Eval.Deprecated+      Language.Fortran.Vars.Eval.Deprecated.Operation+      Language.Fortran.Vars.Eval.FortranSrc+      Language.Fortran.Vars.Eval.FortranSrc.Translate       Language.Fortran.Vars.Kind       Language.Fortran.Vars.Memory       Language.Fortran.Vars.MemoryLocation-      Language.Fortran.Vars.Operation       Language.Fortran.Vars.Orphans       Language.Fortran.Vars.PureExpression       Language.Fortran.Vars.Range+      Language.Fortran.Vars.Rep       Language.Fortran.Vars.StorageClass       Language.Fortran.Vars.StructureTable       Language.Fortran.Vars.SymbolTable+      Language.Fortran.Vars.SymbolTable.Arrays       Language.Fortran.Vars.TypeCheck       Language.Fortran.Vars.Types+      Language.Fortran.Vars.Types.SymbolTable       Language.Fortran.Vars.Union       Language.Fortran.Vars.Utils   other-modules:@@ -55,8 +61,36 @@   hs-source-dirs:       src   default-extensions:+      EmptyCase       LambdaCase+      InstanceSigs+      BangPatterns+      ExplicitNamespaces+      DerivingStrategies+      StandaloneDeriving+      DeriveAnyClass+      DeriveGeneric+      DeriveDataTypeable+      DeriveFunctor+      DeriveFoldable+      DeriveTraversable+      DeriveLift+      FlexibleContexts+      FlexibleInstances+      MultiParamTypeClasses+      GADTs+      PolyKinds+      RoleAnnotations+      RankNTypes       TypeApplications+      DefaultSignatures+      TypeFamilies+      DataKinds+      MagicHash+      BinaryLiterals+      ScopedTypeVariables+      TypeOperators+  ghc-options: -Wall   build-depends:       aeson >=1.5.0.0     , base >=4.7 && <5@@ -64,8 +98,9 @@     , containers >=0.5.7.1     , deepseq >=1.4.4.0     , fgl >=5-    , fortran-src >=0.10.2 && <0.11-    , fortran-src-extras >=0.3.1 && <0.4+    , fortran-src >=0.15.0 && <0.16+    , fortran-src-extras >=0.5.0 && <0.6+    , mtl     , text >=1.2.2.2     , uniplate >=1.6.10   default-language: Haskell2010@@ -77,9 +112,36 @@   hs-source-dirs:       app   default-extensions:+      EmptyCase       LambdaCase+      InstanceSigs+      BangPatterns+      ExplicitNamespaces+      DerivingStrategies+      StandaloneDeriving+      DeriveAnyClass+      DeriveGeneric+      DeriveDataTypeable+      DeriveFunctor+      DeriveFoldable+      DeriveTraversable+      DeriveLift+      FlexibleContexts+      FlexibleInstances+      MultiParamTypeClasses+      GADTs+      PolyKinds+      RoleAnnotations+      RankNTypes       TypeApplications-  ghc-options: -threaded -rtsopts+      DefaultSignatures+      TypeFamilies+      DataKinds+      MagicHash+      BinaryLiterals+      ScopedTypeVariables+      TypeOperators+  ghc-options: -Wall -threaded -rtsopts   build-depends:       aeson >=1.5.0.0     , base >=4.7 && <5@@ -87,9 +149,10 @@     , containers >=0.5.7.1     , deepseq >=1.4.4.0     , fgl >=5-    , fortran-src >=0.10.2 && <0.11-    , fortran-src-extras >=0.3.1 && <0.4+    , fortran-src >=0.15.0 && <0.16+    , fortran-src-extras >=0.5.0 && <0.6     , fortran-vars+    , mtl     , text >=1.2.2.2     , uniplate >=1.6.10   default-language: Haskell2010@@ -107,13 +170,41 @@       StructureTableSpec       SymbolTableSpec       TypeCheckSpec+      Util       Paths_fortran_vars   hs-source-dirs:       test   default-extensions:+      EmptyCase       LambdaCase+      InstanceSigs+      BangPatterns+      ExplicitNamespaces+      DerivingStrategies+      StandaloneDeriving+      DeriveAnyClass+      DeriveGeneric+      DeriveDataTypeable+      DeriveFunctor+      DeriveFoldable+      DeriveTraversable+      DeriveLift+      FlexibleContexts+      FlexibleInstances+      MultiParamTypeClasses+      GADTs+      PolyKinds+      RoleAnnotations+      RankNTypes       TypeApplications-  ghc-options: -threaded -rtsopts+      DefaultSignatures+      TypeFamilies+      DataKinds+      MagicHash+      BinaryLiterals+      ScopedTypeVariables+      TypeOperators+  ghc-options: -Wall -threaded -rtsopts   build-tool-depends:       hspec-discover:hspec-discover   build-depends:@@ -124,10 +215,11 @@     , containers >=0.5.7.1     , deepseq >=1.4.4.0     , fgl >=5-    , fortran-src >=0.10.2 && <0.11-    , fortran-src-extras >=0.3.1 && <0.4+    , fortran-src >=0.15.0 && <0.16+    , fortran-src-extras >=0.5.0 && <0.6     , fortran-vars     , hspec+    , mtl     , text >=1.2.2.2     , uniplate >=1.6.10   default-language: Haskell2010
src/Language/Fortran/Vars/Assignments.hs view
@@ -32,7 +32,9 @@ import           Language.Fortran.Vars.Types    ( SymbolTable                                                 , StructureTable                                                 , SymbolTableEntry(..)-                                                , Dimensions+                                                , Dims(..)+                                                , dimsTraverse+                                                , Dim(..)                                                 , Type                                                 , SemType(..)                                                 , TypeError(..)@@ -102,7 +104,9 @@     pure $ (, e) <$> typeOf strt symt v   f d@(Declarator _ _ (ExpValue _ s (ValVariable v)) ArrayDecl{} _ (Just (ExpInitialisation _ _ vals)))     = case M.lookup v symt of-      Just (SVariable (TArray ty (Just dims)) _) ->+      Just (SVariable (TArray ty dims') _) ->+       case dimsTraverse dims' of -- only static arrays+       Just (DimsExplicitShape dims) ->         let tys   = expandDimensions dims ty             vals' = aStrip vals         in  if length tys /= length vals'@@ -116,6 +120,19 @@                   , pprint77l d                   ]               else fmap Right $ zip (expandDimensions dims ty) $ aStrip vals+       -- only static explicit-shape arrays permitted+       Just{} ->+        pure+          .  Left+          .  typeError s+          $  "Unexpected lhs in array declaration at: "+          <> pprint77l d+       Nothing ->+        pure+          .  Left+          .  typeError s+          $  "Unexpected lhs in array declaration at: "+          <> pprint77l d       _ ->         pure           .  Left@@ -132,8 +149,10 @@   -> [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 (TArray sty dims') _) ->+     case dimsTraverse dims' of+      Just (DimsExplicitShape dims) -> expandDimensions dims (Right sty)+      _ -> [Right sty]     Just (SVariable ty _) -> [Right ty]     _ ->       pure@@ -145,6 +164,6 @@  -- | Function to expand dimensions into appropriate number of types for use in -- other expand functions-expandDimensions :: Dimensions -> a -> [a]+expandDimensions :: Foldable t => t (Dim Int) -> a -> [a] expandDimensions dims =-  replicate (foldl' (\acc (x, y) -> abs (y - x + 1) * acc) 1 dims)+  replicate (foldl' (\acc (Dim lb ub) -> abs (ub - lb + 1) * acc) 1 dims)
src/Language/Fortran/Vars/BozConstant.hs view
@@ -26,7 +26,7 @@ -- -- Currently, it only resolves BOZ Constants in context of INTEGER. resolveBozConstant :: SymbolTable -> String -> ExpVal -> ExpVal-resolveBozConstant symTable assignSymbol (Boz boz) = go boz+resolveBozConstant symTable assignSymbol (Boz b) = go b   where     go boz = case entry of       Just (SVariable (TInteger kind) _) ->
src/Language/Fortran/Vars/CPValue.hs view
@@ -15,7 +15,7 @@  import           Language.Fortran.Vars.Types                                                 ( ExpVal(..) )-import           Language.Fortran.Vars.Operation+import           Language.Fortran.Vars.Eval.Deprecated.Operation                                                 ( unaryOp                                                 , binaryOp                                                 )
src/Language/Fortran/Vars/ConstantPropagation.hs view
@@ -16,7 +16,7 @@                                                 , overlap                                                 , anyOverlap                                                 )-import           Language.Fortran.Vars.Operation+import           Language.Fortran.Vars.Eval.Deprecated.Operation                                                 ( valueToExpVal ) import           Language.Fortran.Vars.MemoryLocation                                                 ( generateLinearizedIndexRange )@@ -111,13 +111,12 @@   -> Maybe (Expression (Analysis a))   -> CPValue substringCPValue symTable memTables e is mb me =-  let errStr         = "Array sections are not allowed in FORTRAN 77"-      name           = srcName e+  let name           = srcName e       isArraySection = case fromJust $ M.lookup name symTable of-        (SVariable (TArray _ dims) _) -> length is < length dims+        (SVariable (TArray _ dims) _) -> length is < dimsLength dims         _                             -> False   in  if isArraySection-        then error errStr+        then errArraySection         else case lookupArray symTable memTables name is of           Top -> Top           Bot -> Bot@@ -126,7 +125,9 @@               Just (b', e') ->                 Const . Str $ take (e' - b' + 1) $ drop (b' - 1) s               Nothing -> Bot-          _ -> error errStr+          _ -> errArraySection+  where+    errArraySection = error "Array sections are not allowed in FORTRAN 77"  -- | Given 'SymbolTable', 'MemoryTables' and an 'Expression', determine the 'CPValue' -- of the 'Expression'@@ -157,8 +158,10 @@   -- Array pointer passed to subroutine/function (thus treated as 'ValVariable')   Just (SVariable (TArray ty dims) (memBlockName, offset)) -> do     kind  <- getTypeKind ty-    dims' <- dims-    Just (memBlockName, (offset, offset + sizeOfArray kind dims' - 1))+    case dimsTraverse dims of+      Just (DimsExplicitShape ds) ->+        Just (memBlockName, (offset, offset + sizeOfArray kind ds - 1))+      _ -> Nothing   Just (SVariable ty (memBlockName, offset)) -> do     kind <- getTypeKind ty     Just (memBlockName, (offset, offset + kind - 1))@@ -198,33 +201,44 @@   -> [Index (Analysis a)]   -> Maybe ArrayMemory getArrayMemory symTable memTables name indices =-  let Just entry  = M.lookup name symTable-      idxCPValues = cpValueOfIndices symTable memTables indices-  in  case entry of-        SVariable (TArray ty dims) (memBlockName, start)-          | any isBot idxCPValues-          -> UnknownIndices . (memBlockName, ) <$> arrayRange-          | any isTop idxCPValues-          -> UnknownIndices . (memBlockName, ) <$> arrayRange-          | not (all isConstInt idxCPValues)-          -> UnknownIndices . (memBlockName, ) <$> arrayRange-          | otherwise-          -> do-            let is = map unsafeStripIndexCP idxCPValues-            range <- generateLinearizedIndexRange is start <$> dims <*> kind-            Just $ ConstantIndices (memBlockName, range)-         where-          kind       = getTypeKind ty-          size       = sizeOfArray <$> kind <*> dims-          arrayRange = (\x -> (start, start + x - 1)) <$> size-        SVariable ty (memBlockName, start)-          | null indices -> ConstantIndices . (memBlockName, ) <$> range-          | otherwise    -> UnknownIndices . (memBlockName, ) <$> range-         where-          kind  = getTypeKind ty-          range = (\x -> (start, start + x - 1)) <$> kind-        _ -> Nothing+    case M.lookup name symTable of+      Nothing -> error $ "variable not in symbol table: "<>name+      Just entry ->+        case entry of+          SVariable ty (memBlockName, start) ->+            case ty of+              TArray _ dims' ->+                case dimsTraverse dims' of -- only handle static+                  Just (DimsExplicitShape dims)+                    | any isBot idxCPValues+                    -> UnknownIndices . (memBlockName, ) <$> arrayRange+                    | any isTop idxCPValues+                    -> UnknownIndices . (memBlockName, ) <$> arrayRange+                    | not (all isConstInt idxCPValues)+                    -> UnknownIndices . (memBlockName, ) <$> arrayRange+                    | otherwise+                    -> do+                      let is = map unsafeStripIndexCP idxCPValues+                      range <- generateLinearizedIndexRange is start <$> pure dims <*> kind+                      Just $ ConstantIndices (memBlockName, range)+                   where+                    kind       = getTypeKind ty+                    size       = sizeOfArray <$> kind <*> pure dims+                    arrayRange = (\x -> (start, start + x - 1)) <$> size +                  -- only handle explicit-shape arrays+                  Just{} -> Nothing+                  Nothing -> Nothing+              _+                | null indices -> ConstantIndices . (memBlockName, ) <$> range+                | otherwise    -> UnknownIndices . (memBlockName, ) <$> range+               where+                kind  = getTypeKind ty+                range = (\x -> (start, start + x - 1)) <$> kind+          _ -> Nothing+  where+    idxCPValues = cpValueOfIndices symTable memTables indices+ -- | Internal function to find 'CPValue' of a symbol lookupName :: SymbolTable -> MemoryTables -> Name -> CPValue lookupName symTable memTables name = case M.lookup name symTable of@@ -558,7 +572,7 @@ label = insLabel . getAnnotation  -- | Given kind and dimensions, calculate the size of an array-sizeOfArray :: Int -> [(Int, Int)] -> Int-sizeOfArray kind dimension =-  let arraySize = foldl (\acc (l, h) -> acc * (h - l + 1)) 1 dimension-  in  kind * arraySize+sizeOfArray :: Foldable t => Int -> t (Dim Int) -> Int+sizeOfArray kind dims = kind * arraySize+  where+    arraySize = foldl' (\acc (Dim l h) -> acc * (h - l + 1)) 1 dims
src/Language/Fortran/Vars/Eval.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DerivingVia #-}+ module Language.Fortran.Vars.Eval   ( eval   , eval'@@ -6,7 +8,6 @@ where  import           Prelude                 hiding ( fail )-import qualified Data.Map                      as M import           Language.Fortran.AST           ( BinaryOp(..)                                                 , Expression(..)                                                 , Value(..)@@ -15,48 +16,32 @@                                                 ) import           Language.Fortran.Util.Position ( getSpan ) -import           Language.Fortran.Vars.Operation-                                                ( binaryOp'-                                                , binaryTransformEither-                                                , nonLogicalToLogical-                                                , transformEither-                                                , transformEitherList-                                                , unaryOp'-                                                , valueToExpVal'-                                                , intrinsicFunctionCall-                                                ) import           Language.Fortran.Vars.Types    ( SymbolTableEntry(..)                                                 , ExpVal(..)                                                 , SymbolTable                                                 ) --- | Given a 'SymbolTable' and some 'Expression', evaluate that expression--- into a basic type and return it as an 'ExpVal' or a 'String' describing--- the issue that prevented the evaluation+import qualified Language.Fortran.Vars.Eval.FortranSrc as ViaFS+import qualified Language.Fortran.Repr as FS+import qualified Language.Fortran.Repr.Eval.Common as FS.Eval+import qualified Language.Fortran.Repr.Eval.Value as FS.Eval++import Control.Monad.Reader+import Control.Monad.Except++import qualified Data.Map as Map++-- | Given a 'SymbolTable' and some 'Expression', attempt to evaluate that+--   expression into a value in fortran-src's representation, translate it into+--   an 'ExpVal', and return. eval' :: SymbolTable -> Expression a -> Either String ExpVal-eval' symTable expr = case expr of-  ExpValue _ _ (ValVariable name) -> case M.lookup name symTable of-    Just (SParameter _ expVal) -> Right expVal-    Just _ -> Left $ "Cannot be evaluated: " ++ name ++ " is not a parameter."-    Nothing -> Left $ "Cannot find parameter : " ++ name-  ExpValue _ s val  -> valueToExpVal' s val-  ExpUnary _ _ op e -> transformEither (unaryOp' op) $ eval' symTable e-  ExpBinary _ _ op e1 e2 ->-    binaryTransformEither (binaryOp' op) (eval' symTable e1) (eval' symTable e2)-  ExpFunctionCall _ _ (ExpValue _ _ function) (AList _ _ args) ->-    transformEitherList intrinsicFunctionCall'-      $   eval' symTable-      .   argExtractExpr-      <$> args-   where-    intrinsicFunctionCall' = intrinsicFunctionCall $ functionName function-    functionName (ValVariable  name) = name-    functionName (ValIntrinsic name) = name-    functionName _                   = ""-  _ -> Left $ "Unsupported expression at: " ++ show (getSpan expr)+eval' symt expr =+    case ViaFS.runEval symt (FS.Eval.evalExpr expr) of+      Left err -> Left $ show err+      Right a -> ViaFS.translateFValue a  -- | Given a 'SymbolTable' and some 'Expression', evaluate that expression--- into a basic type and return it as an 'ExpVal'+-- into a basic type and return it as an 'ExpVal'. eval :: SymbolTable -> Expression a -> ExpVal eval symTable expr = case eval' symTable expr of   Left  err -> error (err ++ show (getSpan expr))@@ -78,19 +63,4 @@ --       .TRUE. -- @ evalWithShortcircuit :: SymbolTable -> Expression a -> Either String ExpVal-evalWithShortcircuit symTable expr = case expr of-  ExpUnary _ _ op e ->-    transformEither (unaryOp' op) $ evalWithShortcircuit symTable e-  ExpBinary _ _ op e1 e2 ->-    let e1' = evalWithShortcircuit symTable e1-        e2' = evalWithShortcircuit symTable e2-        t   = transformEither nonLogicalToLogical-    in  case (op, t e1', t e2') of-          (And, Right r    , Right l    ) -> Right . Logical $ r && l-          (And, Right False, _          ) -> Right $ Logical False-          (And, _          , Right False) -> Right $ Logical False-          (Or , Right r    , Right l    ) -> Right . Logical $ r || l-          (Or , Right True , _          ) -> Right $ Logical True-          (Or , _          , Right True ) -> Right $ Logical True-          _ -> binaryTransformEither (binaryOp' op) e1' e2'-  _ -> eval' symTable expr+evalWithShortcircuit = error "TODO unimplemented in fortran-src evaluator"
+ src/Language/Fortran/Vars/Eval/Deprecated.hs view
@@ -0,0 +1,80 @@+{- | TODO -}++module Language.Fortran.Vars.Eval.Deprecated where++import Language.Fortran.Vars.Eval.Deprecated.Operation++import Language.Fortran.Vars.Rep+import Language.Fortran.Vars.Types.SymbolTable++import Language.Fortran.AST+import Language.Fortran.Util.Position ( getSpan )++import qualified Data.Map as Map++-- | Given a 'SymbolTable' and some 'Expression', evaluate that expression+-- into a basic type and return it as an 'ExpVal' or a 'String' describing+-- the issue that prevented the evaluation+eval' :: SymbolTable -> Expression a -> Either String ExpVal+eval' symTable = \case+  ExpValue _ _ (ValVariable name) -> case Map.lookup name symTable of+    Just (SParameter _ expVal) -> Right expVal+    Just _ -> Left $ "Cannot be evaluated: " ++ name ++ " is not a parameter."+    Nothing -> Left $ "Cannot find parameter : " ++ name++  ExpValue _ s val  -> valueToExpVal' s val++  ExpUnary _ _ op e -> transformEither (unaryOp' op) $ eval' symTable e+  ExpBinary _ _ op e1 e2 ->+    binaryTransformEither (binaryOp' op) (eval' symTable e1) (eval' symTable e2)+  ExpFunctionCall _ _ (ExpValue _ _ function) (AList _ _ args) ->+    transformEitherList intrinsicFunctionCall'+      $   eval' symTable+      .   argExtractExpr+      <$> args+   where+    intrinsicFunctionCall' = intrinsicFunctionCall $ functionName function+    functionName (ValVariable  name) = name+    functionName (ValIntrinsic name) = name+    functionName _                   = ""+  e -> Left $ "Unsupported expression at: " ++ show (getSpan e)++-- | Given a 'SymbolTable' and some 'Expression', evaluate that expression+-- into a basic type and return it as an 'ExpVal'+eval :: SymbolTable -> Expression a -> ExpVal+eval symTable expr = case eval' symTable expr of+  Left  err -> error (err ++ show (getSpan expr))+  Right r   -> r++-- | Given a 'SymbolTable' and some 'Expression', evaluate that expression+-- into a basic type and return it as an 'ExpVal' or a 'String' describing+-- the issue that prevented the evaluation. In the case of expressions like+--+-- @+--       foobar .AND. .FALSE.+--       .TRUE. .OR. .foobar+-- @+--+-- the expressions will be shortcircuited to produce+--+-- @+--       .FALSE.+--       .TRUE.+-- @+evalWithShortcircuit :: SymbolTable -> Expression a -> Either String ExpVal+evalWithShortcircuit symTable expr = case expr of+  ExpUnary _ _ op e ->+    transformEither (unaryOp' op) $ evalWithShortcircuit symTable e+  ExpBinary _ _ op e1 e2 ->+    let e1' = evalWithShortcircuit symTable e1+        e2' = evalWithShortcircuit symTable e2+        t   = transformEither nonLogicalToLogical+    in  case (op, t e1', t e2') of+          (And, Right r    , Right l    ) -> Right . Logical $ r && l+          (And, Right False, _          ) -> Right $ Logical False+          (And, _          , Right False) -> Right $ Logical False+          (Or , Right r    , Right l    ) -> Right . Logical $ r || l+          (Or , Right True , _          ) -> Right $ Logical True+          (Or , _          , Right True ) -> Right $ Logical True+          _ -> binaryTransformEither (binaryOp' op) e1' e2'+  _ -> eval' symTable expr
+ src/Language/Fortran/Vars/Eval/Deprecated/Operation.hs view
@@ -0,0 +1,258 @@+module Language.Fortran.Vars.Eval.Deprecated.Operation+  ( valueToExpVal'+  , valueToExpVal+  , transformEither+  , transformEitherList+  , binaryTransformEither+  , unaryOp'+  , unaryOp+  , binaryOp'+  , binaryOp+  , intrinsicFunctionCall+  , nonLogicalToLogical+  )+where++import           Prelude                 hiding ( GT+                                                , EQ+                                                , LT+                                                )+import           Data.Char                      ( chr )++import           Language.Fortran.AST           ( BinaryOp(..)+                                                , UnaryOp(..)+                                                , Value(..)+                                                )+import           Language.Fortran.AST.Literal.Real ( readRealLit )+import           Language.Fortran.Util.Position ( SrcSpan )+++import           Language.Fortran.Vars.BozConstant+                                                ( bozToInt8+                                                , bozToInt+                                                )+import           Language.Fortran.Vars.Errors   ( invalidArg' )+import           Language.Fortran.Vars.Types    ( ExpVal(..) )++import           Data.Bits                      ( (.|.)+                                                , complement+                                                )++-- | Given a function that returns an 'Either' and an 'Either' with+-- the 'Right' case as the same type input to the function, return+-- an either by possibly applying the function to the 'Right' value or+-- propagating the 'Left' case+transformEither :: (a -> Either String b) -> Either String a -> Either String b+transformEither = either Left+{-# INLINABLE transformEither #-}++-- | Given a function that takes two arguments of the same type and returns an+-- 'Either' as well as two 'Either's whose 'Right' cases hold the inputs to the+-- function, apply the function if possible. Otherwise propagate the 'Left' cases+binaryTransformEither+  :: (a -> a -> Either String b)+  -> Either String a+  -> Either String a+  -> Either String b+binaryTransformEither _ (Left e)   _          = Left e+binaryTransformEither _ _          (Left  e ) = Left e+binaryTransformEither t (Right v1) (Right v2) = t v1 v2++-- | Given a function that takes a list of arguments of the same type and returns an+-- 'Either' as well as a list of 'Either's whose 'Right' cases hold the inputs to the+-- function, apply the function if possible. Otherwise propagate the 'Left' cases+transformEitherList+  :: ([a] -> Either String b) -> [Either String a] -> Either String b+transformEitherList t el = case eitherListToList el of+  Left  l  -> Left l+  Right rs -> t rs+ where+  eitherListToList :: [Either String a] -> Either String [a]+  eitherListToList []             = Right []+  eitherListToList (Left  l : _ ) = Left l+  eitherListToList (Right r : rs) = case eitherListToList rs of+    Left  l   -> Left l+    Right rs' -> Right (r : rs')++-- | Given a 'SrcSpan' and the 'Value' in that span either+-- return a 'String' describing the issue or the 'ExpVal' held+-- by that 'Value'.+valueToExpVal' :: SrcSpan -> Value a -> Either String ExpVal+valueToExpVal' s val = case val of+  ValInteger i _  -> Right $ Int $ read i+  ValReal    r _  -> Right $ Real $ readRealLit r+  ValLogical l _  -> Right $ Logical l+  ValString    s' -> Right $ Str s'+  ValHollerith h  -> Right $ Str h+  ValBoz       b  -> Right $ Boz b+  _               -> Left ("toExpVal: unsupported value at " ++ show s)++-- | Given a 'SrcSpan' and the 'Value' returnthe 'ExpVal' held+-- by that 'Value' or throw an error.+valueToExpVal :: SrcSpan -> Value a -> ExpVal+valueToExpVal s val = case valueToExpVal' s val of+  Left  err  -> error err+  Right expr -> expr++-- | Given a non-logical 'ExpVal', convert that value to a logical+-- one or return a 'String' describing why this was impossible.+nonLogicalToLogical :: ExpVal -> Either String Bool+nonLogicalToLogical (Int  i) = Right $ i /= 0+nonLogicalToLogical (Real r) = Right $ r /= 0.0+nonLogicalToLogical (Str _) =+  Left "Cannot transform a string value to a logical value"+nonLogicalToLogical (Logical l) = Right l+nonLogicalToLogical (Boz     b) = nonLogicalToLogical $ bozToInt8 b++-- | Given a string representing a function call and a list of ExpVal+-- values holding inputs to the function, evaluate the function call+-- and return the result in a Right, or propagate the Left case if any+-- of the list elements are 'Lefts'.+intrinsicFunctionCall :: String -> [ExpVal] -> Either String ExpVal+intrinsicFunctionCall function es = case function of+  "ior"  -> ior' es+  "max"  -> max' es+  "char" -> char' es+  "not"  -> not' es+  "int"  -> int' es+  "int2" -> int' es+  _      -> invalidArg' ("intrinsicFunctionCall " ++ show function) es++ior' :: [ExpVal] -> Either String ExpVal+ior' [val1, val2] = case (val1, val2) of+  (Int a, Int b) -> Right $ Int $ (.|.) a b+  _              -> invalidArg' "ior" [val1, val2]+ior' vs = invalidArg' "ior" vs++max' :: [ExpVal] -> Either String ExpVal+max' [val1] = case val1 of+  Real a -> Right $ Real a+  Int  a -> Right $ Int a+  _      -> invalidArg' "max" [val1]+max' (v : vs) =+  let maxVs = max' vs+  in  case (v, maxVs) of+        (_      , Left l        ) -> Left l+        (Real r', Right (Int r) ) -> Right $ Real $ max r' (fromIntegral r)+        (Int  r', Right (Real r)) -> Right $ Real $ max (fromIntegral r') r+        (Real r', Right (Real r)) -> Right $ Real $ max r' r+        (Int  r', Right (Int r) ) -> Right $ Int $ max r' r+        _                         -> invalidArg' "max" (v : vs)+max' vs = invalidArg' "max" vs++char' :: [ExpVal] -> Either String ExpVal+char' [Int i] = Right $ Str [chr i]+char' vs      = invalidArg' "char" vs++-- https://docs.oracle.com/cd/E19957-01/805-4939/6j4m0vnc8/index.html+not' :: [ExpVal] -> Either String ExpVal+not' [Int i] = Right $ Int (complement i)+not' vs      = invalidArg' "not" vs++int' :: [ExpVal] -> Either String ExpVal+int' [Int  i] = Right $ Int i+int' [Real r] = Right $ Int (truncate r)+int' v@[(Boz boz), Int k] =+  if k `elem` [2, 4, 8] then Right $ bozToInt k boz else invalidArg' "int" v+int' vs = invalidArg' "int" vs++-- | Given a 'UnaryOp' and an 'ExpVal', either return the resulting+-- 'ExpVal' after applying the operation or a 'String' describing+-- why this couldn't be done+unaryOp' :: UnaryOp -> ExpVal -> Either String ExpVal+unaryOp' op v = case (op, v) of+  (Plus , Int a ) -> Right $ Int a+  (Plus , Real a) -> Right $ Real a+  (Minus, Int a ) -> Right $ Int (negate a)+  (Minus, Real a) -> Right $ Real (negate a)+  (Not, a) -> transformEither (Right . Logical . not) $ nonLogicalToLogical a+  _               -> invalidArg' (show op) [v]++-- | Given a 'UnaryOp' and an 'ExpVal', either return the resulting+-- 'ExpVal' after applying the operation or throw an error+unaryOp :: UnaryOp -> ExpVal -> ExpVal+unaryOp op v = case unaryOp' op v of+  Left  err  -> error err+  Right expr -> expr++-- | Given a 'BinaryOp' and two 'ExpVal's, either return the resulting+-- 'ExpVal' after applying the operation or a 'String' describing+-- why this couldn't be done+binaryOp' :: BinaryOp -> ExpVal -> ExpVal -> Either String ExpVal+binaryOp' op val1 val2 = case (op, val1, val2) of+  (Addition, Int a, Int b) -> Right $ Int (a + b)+  (Addition, Real a, Real b) -> Right $ Real (a + b)+  (Addition, Int a, Real b) -> Right $ Real (fromIntegral a + b)+  (Addition, Real a, Int b) -> Right $ Real (a + fromIntegral b)++  (Subtraction, Int a, Int b) -> Right $ Int (a - b)+  (Subtraction, Real a, Real b) -> Right $ Real (a - b)+  (Subtraction, Int a, Real b) -> Right $ Real (fromIntegral a - b)+  (Subtraction, Real a, Int b) -> Right $ Real (a - fromIntegral b)++  (Multiplication, Int a, Int b) -> Right $ Int (a * b)+  (Multiplication, Real a, Real b) -> Right $ Real (a * b)+  (Multiplication, Int a, Real b) -> Right $ Real (fromIntegral a * b)+  (Multiplication, Real a, Int b) -> Right $ Real (a * fromIntegral b)++  (Division, Int a, Int b) -> Right $ Int (div a b)+  (Division, Real a, Real b) -> Right $ Real (a / b)+  (Division, Int a, Real b) -> Right $ Real (fromIntegral a / b)+  (Division, Real a, Int b) -> Right $ Real (a / fromIntegral b)++  (Exponentiation, Int a, Int b) -> Right $ Int (a ^ b)+  (Exponentiation, Real a, Real b) -> Right $ Real (a ** b)+  (Exponentiation, Int a, Real b) -> Right $ Real (fromIntegral a ** b)+  (Exponentiation, Real a, Int b) -> Right $ Real (a ** fromIntegral b)++  (Concatenation, Str a, Str b) -> Right $ Str (a ++ b)++  (LT, Int a, Int b) -> Right $ Logical (a < b)+  (LT, Real a, Real b) -> Right $ Logical (a < b)+  (LT, Int a, Real b) -> Right $ Logical (fromIntegral a < b)+  (LT, Real a, Int b) -> Right $ Logical (a < fromIntegral b)+  (LT, Boz boz, b) -> binaryOp' LT (bozToInt8 boz) b+  (LT, a, Boz boz) -> binaryOp' LT a (bozToInt8 boz)++  (EQ, Int a, Real b) -> Right $ Logical (fromIntegral a == b)+  (EQ, Real a, Int b) -> Right $ Logical (a == fromIntegral b)+  (EQ, Boz boz, b) -> binaryOp' EQ (bozToInt8 boz) b+  (EQ, a, Boz boz) -> binaryOp' EQ a (bozToInt8 boz)+  (EQ, Logical True, Int b) -> Right $ Logical (1 == b)+  (EQ, Logical False, Int b) -> Right $ Logical (0 == b)+  (EQ, Int a, Logical True) -> Right $ Logical (a == 1)+  (EQ, Int a, Logical False) -> Right $ Logical (a == 0)+  (EQ, Logical True, Real b) -> Right $ Logical (1.0 == b)+  (EQ, Logical False, Real b) -> Right $ Logical (0.0 == b)+  (EQ, Real a, Logical True) -> Right $ Logical (a == 1.0)+  (EQ, Real a, Logical False) -> Right $ Logical (a == 0.0)+  (EQ, v1, v2) -> Right $ Logical (v1 == v2)+++  (GT, v1, v2) -> binaryOp' LT v2 v1+  (GTE, v1, v2) -> transformEither (unaryOp' Not) $ binaryOp' LT v2 v1+  (LTE, v1, v2) -> transformEither (unaryOp' Not) $ binaryOp' GT v2 v1++  (NE, v1, v2) -> transformEither (unaryOp' Not) $ binaryOp' EQ v1 v2++  (And, v1, v2) ->+    binaryTransformEither (\x -> Right . Logical . (x &&))+                          (nonLogicalToLogical v1)+      $ nonLogicalToLogical v2++  (Or, v1, v2) ->+    binaryTransformEither (\x -> Right . Logical . (x ||))+                          (nonLogicalToLogical v1)+      $ nonLogicalToLogical v2++  (XOr, Logical a, Logical b) -> Right $ Logical (a /= b)+  (Equivalent, Logical a, Logical b) -> Right $ Logical (a == b)+  (NotEquivalent, Logical a, Logical b) -> Right $ Logical (a /= b)+  _ -> invalidArg' (show op) [val1, val2]++-- | Given a 'BinaryOp' and two 'ExpVal's, either return the resulting+-- 'ExpVal' after applying the operation or throw an error+binaryOp :: BinaryOp -> ExpVal -> ExpVal -> ExpVal+binaryOp op val1 val2 = case binaryOp' op val1 val2 of+  Left  err  -> error err+  Right expr -> expr
+ src/Language/Fortran/Vars/Eval/FortranSrc.hs view
@@ -0,0 +1,68 @@+{- | fortran-vars-style expression evaluation which piggybacks off the evaluator+     in fortran-src.+-}++{-# LANGUAGE DerivingVia #-}++module Language.Fortran.Vars.Eval.FortranSrc+  ( module Language.Fortran.Vars.Eval.FortranSrc+  , module Language.Fortran.Vars.Eval.FortranSrc.Translate+  ) where++import Language.Fortran.Vars.Eval.FortranSrc.Translate++import Language.Fortran.Vars.Types.SymbolTable++import qualified Language.Fortran.Repr as FS.Rep+import qualified Language.Fortran.Repr.Eval.Common as FS.Eval+import qualified Language.Fortran.Repr.Eval.Value as FS.Eval++import Control.Monad.Reader+import Control.Monad.Except++import qualified Data.Map as Map++-- | Fortran expression evaluation monad, using 'SymbolTable' and reporting+--   fortran-src evaluator errors.+--+-- We use a newtype wrapper on this at 'Eval'. The type synonym assists some+-- boilerplate.+type Eval' = ExceptT FS.Eval.Error (Reader SymbolTable)++-- | Fortran expression evaluation monad, using 'SymbolTable' and reporting+--   fortran-src evaluator errors.+newtype Eval a = Eval { unEval :: Eval' a }+    deriving (Functor, Applicative, Monad) via Eval'+    deriving (MonadReader SymbolTable) via Eval'+    deriving (MonadError FS.Eval.Error) via Eval'++-- | Execute a program in the Fortran expression evaluation monad 'Eval'.+runEval :: SymbolTable -> Eval a -> Either FS.Eval.Error a+runEval symt = flip runReader symt . runExceptT . unEval++-- | Evaluate Fortran expressions to 'FS.FValue's.+--+-- We look up variables from a plain 'SymbolTable', but evaluate using+-- fortran-src's machinery. We must therefore translate 'SymbolTable' 'ExpVal's+-- to 'FS.FValue'. If we want to return fortran-vars-style types, we must+-- translate the other way after executing a program in this monad.+instance FS.Eval.MonadFEval Eval where+    type EvalTo Eval = FS.Rep.FValue++    lookupFVar name = do+        symt <- ask+        case Map.lookup name symt of+          Nothing -> return Nothing+          Just entry ->+            case entry of+              SParameter _ val ->+                return $ Just $ FS.Rep.MkFScalarValue $ translateExpVal val+              _ -> do+                FS.Eval.warn $+                    "found variable in SymbolTable, but wasn't an SParameter: "+                    <>name+                return Nothing++    -- | Ignore warnings. fortran-vars doesn't have a method to report warnings+    --   during evaluation.+    warn _ = pure ()
+ src/Language/Fortran/Vars/Eval/FortranSrc/Translate.hs view
@@ -0,0 +1,81 @@+{- | 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
src/Language/Fortran/Vars/Memory.hs view
@@ -39,6 +39,8 @@                                                 ) import           Language.Fortran.Vars.Kind     ( getTypeKind ) import           Language.Fortran.Vars.Union    ( union )+import           Language.Fortran.Analysis.SemanticTypes+                                                ( dimensionsToTuples )  -- | Given a 'SymbolTable' and an 'Expression', return the size of -- the variable represented by the expression@@ -55,14 +57,17 @@         _              -> error (symbol ++ " is not a VariableEntry.")  getTypeSize :: Type -> Int-getTypeSize = \case-  TArray ty dims ->-    fromMaybe (error "Can't calculate size of dynamic array")-      $   sizeOfStaticArray-      <$> getTypeKind ty-      <*> dims-  ty -> fromMaybe (error "Can't get size of dynamic variable") $ getTypeKind ty+getTypeSize =+    fromMaybe (error "Can't get size of dynamic variable") . getTypeSize' +getTypeSize' :: Type -> Maybe Int+getTypeSize' = \case+  TArray ty dims -> do+    dims' <- dimensionsToTuples dims+    kind <- getTypeKind ty+    pure $ sizeOfStaticArray kind dims'+  ty -> getTypeKind ty+ -- | Given a static array's 'kind' and 'dimension', calculate its size sizeOfStaticArray :: Int -> [(Int, Int)] -> Int sizeOfStaticArray kind' dimension' =@@ -78,12 +83,10 @@   f :: StorageTable -> Name -> SymbolTableEntry -> StorageTable   f storageTable symbol entry = case entry of     SVariable ty _ ->-      let size = case ty of-            TArray ty' dims -> sizeOfStaticArray <$> getTypeKind ty' <*> dims-            _               -> getTypeKind ty+      let mSize = getTypeSize' ty           block = MemoryBlock-            { blockSize    = size-            , storageClass = case size of+            { blockSize    = mSize+            , storageClass = case mSize of                                Nothing -> Automatic                                _       -> Unspecified             , variables    = [symbol]
src/Language/Fortran/Vars/MemoryLocation.hs view
@@ -5,6 +5,7 @@   ) where +import qualified Data.Foldable                 as Foldable import           Data.Data                      ( Data ) import           Data.List                      ( foldl' ) import qualified Data.Map                      as M@@ -28,9 +29,10 @@                                                 , Location                                                 , Offset                                                 , SymbolTable+                                                , Dim(..), Dimensions+                                                , dimensionsToTuples                                                 ) - isIxSingle :: Index a -> Bool isIxSingle IxSingle{} = True isIxSingle IxRange{}  = False@@ -56,10 +58,15 @@  -- | Given only single indices return the 'Range' in memory that -- these indices point to.-generateLinearizedIndexRange :: [Int] -> Int -> [(Int, Int)] -> Int -> Range+generateLinearizedIndexRange+    :: (Functor t, Foldable t) => [Int] -> Int -> t (Dim Int) -> Int -> Range generateLinearizedIndexRange intIndices start dims kind =-  let offset = linearizedIndex intIndices dims * kind+  let offset = linearizedIndex intIndices dims' * kind   in  (start + offset, start + offset + kind - 1)+  where+    -- TODO Ideally, we stay in our foldable for as long as possible. Shift this+    -- into 'linearizedIndex' and try.+    dims' = Foldable.toList $ fmap (\(Dim lb ub) -> (lb, ub)) dims  findBlockOffset :: SymbolTable -> Name -> Offset -> Location findBlockOffset symTable symbol offset = case M.lookup symbol symTable of@@ -79,20 +86,25 @@   let Just entry = M.lookup symbol symTable   in     case entry of-      SVariable (TArray ty (Just dims)) _ ->-        let-          ixSingles    = takeWhile isIxSingle indices-          Just kind    = getTypeKind ty-          arrayIndices = either (const Nothing) Just-            $ traverse toIndices ixSingles-           where-            toIndices (IxSingle _ _ _ expr) = toInt <$> eval' symTable expr-            toIndices _ = error "toIndices: unexpected input"-        in-          (\x -> linearizedIndex x dims * kind) <$> arrayIndices+      SVariable (TArray ty dims) _ ->+        case dimensionsToTuples dims of+          Nothing -> error "expected a static array, got dynamic"+          Just dims' ->+            let+              ixSingles    = takeWhile isIxSingle indices+              Just kind    = getTypeKind ty+              arrayIndices = either (const Nothing) Just+                $ traverse toIndices ixSingles+               where+                toIndices (IxSingle _ _ _ expr) = toInt <$> eval' symTable expr+                toIndices _ = error "toIndices: unexpected input"+            in+              (\x -> linearizedIndex x dims' * kind) <$> arrayIndices       _ -> error "Only array-typed VariableEntries are expected at this point"+ -- substring c(:5) calculateOffset _ _ (IxRange _ _ Nothing _ _ : _) = Just 0+ -- substring c(5:) calculateOffset symTable _ (IxRange _ _ (Just lowerIndex) _ _ : _) =   let val = eval' symTable lowerIndex
− src/Language/Fortran/Vars/Operation.hs
@@ -1,258 +0,0 @@-module Language.Fortran.Vars.Operation-  ( valueToExpVal'-  , valueToExpVal-  , transformEither-  , transformEitherList-  , binaryTransformEither-  , unaryOp'-  , unaryOp-  , binaryOp'-  , binaryOp-  , intrinsicFunctionCall-  , nonLogicalToLogical-  )-where--import           Prelude                 hiding ( GT-                                                , EQ-                                                , LT-                                                )-import           Data.Char                      ( chr )--import           Language.Fortran.AST           ( BinaryOp(..)-                                                , UnaryOp(..)-                                                , Value(..)-                                                )-import           Language.Fortran.AST.Literal.Real ( readRealLit )-import           Language.Fortran.Util.Position ( SrcSpan )---import           Language.Fortran.Vars.BozConstant-                                                ( bozToInt8-                                                , bozToInt-                                                )-import           Language.Fortran.Vars.Errors   ( invalidArg' )-import           Language.Fortran.Vars.Types    ( ExpVal(..) )--import           Data.Bits                      ( (.|.)-                                                , complement-                                                )---- | Given a function that returns an 'Either' and an 'Either' with--- the 'Right' case as the same type input to the function, return--- an either by possibly applying the function to the 'Right' value or--- propagating the 'Left' case-transformEither :: (a -> Either String b) -> Either String a -> Either String b-transformEither = either Left-{-# INLINABLE transformEither #-}---- | Given a function that takes two arguments of the same type and returns an--- 'Either' as well as two 'Either's whose 'Right' cases hold the inputs to the--- function, apply the function if possible. Otherwise propagate the 'Left' cases-binaryTransformEither-  :: (a -> a -> Either String b)-  -> Either String a-  -> Either String a-  -> Either String b-binaryTransformEither _ (Left e)   _          = Left e-binaryTransformEither _ _          (Left  e ) = Left e-binaryTransformEither t (Right v1) (Right v2) = t v1 v2---- | Given a function that takes a list of arguments of the same type and returns an--- 'Either' as well as a list of 'Either's whose 'Right' cases hold the inputs to the--- function, apply the function if possible. Otherwise propagate the 'Left' cases-transformEitherList-  :: ([a] -> Either String b) -> [Either String a] -> Either String b-transformEitherList t el = case eitherListToList el of-  Left  l  -> Left l-  Right rs -> t rs- where-  eitherListToList :: [Either String a] -> Either String [a]-  eitherListToList []             = Right []-  eitherListToList (Left  l : _ ) = Left l-  eitherListToList (Right r : rs) = case eitherListToList rs of-    Left  l   -> Left l-    Right rs' -> Right (r : rs')---- | Given a 'SrcSpan' and the 'Value' in that span either--- return a 'String' describing the issue or the 'ExpVal' held--- by that 'Value'.-valueToExpVal' :: SrcSpan -> Value a -> Either String ExpVal-valueToExpVal' s val = case val of-  ValInteger i _  -> Right $ Int $ read i-  ValReal    r _  -> Right $ Real $ readRealLit r-  ValLogical l _  -> Right $ Logical l-  ValString    s' -> Right $ Str s'-  ValHollerith h  -> Right $ Str h-  ValBoz       b  -> Right $ Boz b-  _               -> Left ("toExpVal: unsupported value at " ++ show s)---- | Given a 'SrcSpan' and the 'Value' returnthe 'ExpVal' held--- by that 'Value' or throw an error.-valueToExpVal :: SrcSpan -> Value a -> ExpVal-valueToExpVal s val = case valueToExpVal' s val of-  Left  err  -> error err-  Right expr -> expr---- | Given a non-logical 'ExpVal', convert that value to a logical--- one or return a 'String' describing why this was impossible.-nonLogicalToLogical :: ExpVal -> Either String Bool-nonLogicalToLogical (Int  i) = Right $ i /= 0-nonLogicalToLogical (Real r) = Right $ r /= 0.0-nonLogicalToLogical (Str _) =-  Left "Cannot transform a string value to a logical value"-nonLogicalToLogical (Logical l) = Right l-nonLogicalToLogical (Boz     b) = nonLogicalToLogical $ bozToInt8 b---- | Given a string representing a function call and a list of ExpVal--- values holding inputs to the function, evaluate the function call--- and return the result in a Right, or propagate the Left case if any--- of the list elements are 'Lefts'.-intrinsicFunctionCall :: String -> [ExpVal] -> Either String ExpVal-intrinsicFunctionCall function es = case function of-  "ior"  -> ior' es-  "max"  -> max' es-  "char" -> char' es-  "not"  -> not' es-  "int"  -> int' es-  "int2" -> int' es-  _      -> invalidArg' ("intrinsicFunctionCall " ++ show function) es--ior' :: [ExpVal] -> Either String ExpVal-ior' [val1, val2] = case (val1, val2) of-  (Int a, Int b) -> Right $ Int $ (.|.) a b-  _              -> invalidArg' "ior" [val1, val2]-ior' vs = invalidArg' "ior" vs--max' :: [ExpVal] -> Either String ExpVal-max' [val1] = case val1 of-  Real a -> Right $ Real a-  Int  a -> Right $ Int a-  _      -> invalidArg' "max" [val1]-max' (v : vs) =-  let maxVs = max' vs-  in  case (v, maxVs) of-        (_      , Left l        ) -> Left l-        (Real r', Right (Int r) ) -> Right $ Real $ max r' (fromIntegral r)-        (Int  r', Right (Real r)) -> Right $ Real $ max (fromIntegral r') r-        (Real r', Right (Real r)) -> Right $ Real $ max r' r-        (Int  r', Right (Int r) ) -> Right $ Int $ max r' r-        _                         -> invalidArg' "max" (v : vs)-max' vs = invalidArg' "max" vs--char' :: [ExpVal] -> Either String ExpVal-char' [Int i] = Right $ Str [chr i]-char' vs      = invalidArg' "char" vs---- https://docs.oracle.com/cd/E19957-01/805-4939/6j4m0vnc8/index.html-not' :: [ExpVal] -> Either String ExpVal-not' [Int i] = Right $ Int (complement i)-not' vs      = invalidArg' "not" vs--int' :: [ExpVal] -> Either String ExpVal-int' [Int  i] = Right $ Int i-int' [Real r] = Right $ Int (truncate r)-int' v@[(Boz boz), Int k] =-  if k `elem` [2, 4, 8] then Right $ bozToInt k boz else invalidArg' "int" v-int' vs = invalidArg' "int" vs---- | Given a 'UnaryOp' and an 'ExpVal', either return the resulting--- 'ExpVal' after applying the operation or a 'String' describing--- why this couldn't be done-unaryOp' :: UnaryOp -> ExpVal -> Either String ExpVal-unaryOp' op v = case (op, v) of-  (Plus , Int a ) -> Right $ Int a-  (Plus , Real a) -> Right $ Real a-  (Minus, Int a ) -> Right $ Int (negate a)-  (Minus, Real a) -> Right $ Real (negate a)-  (Not, a) -> transformEither (Right . Logical . not) $ nonLogicalToLogical a-  _               -> invalidArg' (show op) [v]---- | Given a 'UnaryOp' and an 'ExpVal', either return the resulting--- 'ExpVal' after applying the operation or throw an error-unaryOp :: UnaryOp -> ExpVal -> ExpVal-unaryOp op v = case unaryOp' op v of-  Left  err  -> error err-  Right expr -> expr---- | Given a 'BinaryOp' and two 'ExpVal's, either return the resulting--- 'ExpVal' after applying the operation or a 'String' describing--- why this couldn't be done-binaryOp' :: BinaryOp -> ExpVal -> ExpVal -> Either String ExpVal-binaryOp' op val1 val2 = case (op, val1, val2) of-  (Addition, Int a, Int b) -> Right $ Int (a + b)-  (Addition, Real a, Real b) -> Right $ Real (a + b)-  (Addition, Int a, Real b) -> Right $ Real (fromIntegral a + b)-  (Addition, Real a, Int b) -> Right $ Real (a + fromIntegral b)--  (Subtraction, Int a, Int b) -> Right $ Int (a - b)-  (Subtraction, Real a, Real b) -> Right $ Real (a - b)-  (Subtraction, Int a, Real b) -> Right $ Real (fromIntegral a - b)-  (Subtraction, Real a, Int b) -> Right $ Real (a - fromIntegral b)--  (Multiplication, Int a, Int b) -> Right $ Int (a * b)-  (Multiplication, Real a, Real b) -> Right $ Real (a * b)-  (Multiplication, Int a, Real b) -> Right $ Real (fromIntegral a * b)-  (Multiplication, Real a, Int b) -> Right $ Real (a * fromIntegral b)--  (Division, Int a, Int b) -> Right $ Int (div a b)-  (Division, Real a, Real b) -> Right $ Real (a / b)-  (Division, Int a, Real b) -> Right $ Real (fromIntegral a / b)-  (Division, Real a, Int b) -> Right $ Real (a / fromIntegral b)--  (Exponentiation, Int a, Int b) -> Right $ Int (a ^ b)-  (Exponentiation, Real a, Real b) -> Right $ Real (a ** b)-  (Exponentiation, Int a, Real b) -> Right $ Real (fromIntegral a ** b)-  (Exponentiation, Real a, Int b) -> Right $ Real (a ** fromIntegral b)--  (Concatenation, Str a, Str b) -> Right $ Str (a ++ b)--  (LT, Int a, Int b) -> Right $ Logical (a < b)-  (LT, Real a, Real b) -> Right $ Logical (a < b)-  (LT, Int a, Real b) -> Right $ Logical (fromIntegral a < b)-  (LT, Real a, Int b) -> Right $ Logical (a < fromIntegral b)-  (LT, Boz boz, b) -> binaryOp' LT (bozToInt8 boz) b-  (LT, a, Boz boz) -> binaryOp' LT a (bozToInt8 boz)--  (EQ, Int a, Real b) -> Right $ Logical (fromIntegral a == b)-  (EQ, Real a, Int b) -> Right $ Logical (a == fromIntegral b)-  (EQ, Boz boz, b) -> binaryOp' EQ (bozToInt8 boz) b-  (EQ, a, Boz boz) -> binaryOp' EQ a (bozToInt8 boz)-  (EQ, Logical True, Int b) -> Right $ Logical (1 == b)-  (EQ, Logical False, Int b) -> Right $ Logical (0 == b)-  (EQ, Int a, Logical True) -> Right $ Logical (a == 1)-  (EQ, Int a, Logical False) -> Right $ Logical (a == 0)-  (EQ, Logical True, Real b) -> Right $ Logical (1.0 == b)-  (EQ, Logical False, Real b) -> Right $ Logical (0.0 == b)-  (EQ, Real a, Logical True) -> Right $ Logical (a == 1.0)-  (EQ, Real a, Logical False) -> Right $ Logical (a == 0.0)-  (EQ, v1, v2) -> Right $ Logical (v1 == v2)---  (GT, v1, v2) -> binaryOp' LT v2 v1-  (GTE, v1, v2) -> transformEither (unaryOp' Not) $ binaryOp' LT v2 v1-  (LTE, v1, v2) -> transformEither (unaryOp' Not) $ binaryOp' GT v2 v1--  (NE, v1, v2) -> transformEither (unaryOp' Not) $ binaryOp' EQ v1 v2--  (And, v1, v2) ->-    binaryTransformEither (\x -> Right . Logical . (x &&))-                          (nonLogicalToLogical v1)-      $ nonLogicalToLogical v2--  (Or, v1, v2) ->-    binaryTransformEither (\x -> Right . Logical . (x ||))-                          (nonLogicalToLogical v1)-      $ nonLogicalToLogical v2--  (XOr, Logical a, Logical b) -> Right $ Logical (a /= b)-  (Equivalent, Logical a, Logical b) -> Right $ Logical (a == b)-  (NotEquivalent, Logical a, Logical b) -> Right $ Logical (a /= b)-  _ -> invalidArg' (show op) [val1, val2]---- | Given a 'BinaryOp' and two 'ExpVal's, either return the resulting--- 'ExpVal' after applying the operation or throw an error-binaryOp :: BinaryOp -> ExpVal -> ExpVal -> ExpVal-binaryOp op val1 val2 = case binaryOp' op val1 val2 of-  Left  err  -> error err-  Right expr -> expr
src/Language/Fortran/Vars/Orphans.hs view
@@ -1,14 +1,19 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+ module Language.Fortran.Vars.Orphans where  import Language.Fortran.AST import qualified Language.Fortran.AST.Literal.Boz as Boz import Language.Fortran.Util.Position import Language.Fortran.Analysis.SemanticTypes+import Language.Fortran.Extras.JSON.Analysis() -import Data.Aeson ( ToJSON, FromJSON )+import Data.Aeson ( ToJSON, FromJSON, ToJSONKey, FromJSONKey )  -- TODO temporary solution instance   ToJSON SemType+instance FromJSON (Dim (Maybe Int))+instance FromJSON Dimensions instance FromJSON SemType instance   ToJSON CharacterLen instance FromJSON CharacterLen@@ -19,3 +24,9 @@ instance FromJSON Boz.Boz instance FromJSON Boz.BozPrefix instance FromJSON Boz.Conforming++-- TODO move these to common+instance ToJSON ProgramUnitName+instance ToJSONKey ProgramUnitName+instance FromJSON ProgramUnitName+instance FromJSONKey ProgramUnitName
+ src/Language/Fortran/Vars/Rep.hs view
@@ -0,0 +1,45 @@+-- | Definitions for representing Fortran values and types.++module Language.Fortran.Vars.Rep+  (+  -- * Types+    F.SemType(..)+  , F.Kind+  , F.CharacterLen(..)+  , F.Dimensions, F.Dim(..), F.Dims(..)++  -- ** Compatibility+  , F.dimensionsToTuples+  , Type++  -- * Values+  , ExpVal(..)+  ) where++import qualified Language.Fortran.Analysis.SemanticTypes as F+import qualified Language.Fortran.AST.Literal.Boz as F+import Language.Fortran.Extras.JSON.Literals()++import Language.Fortran.Vars.Orphans()++import Data.Aeson ( ToJSON, FromJSON )+import Control.DeepSeq ( NFData )+import GHC.Generics ( Generic )+import Data.Data ( Data )++-- TODO raehik 2023-05-15: consider deprecating. GHC is very gradually changing+-- the kind of concrete types from @*@ to @Type@. Language extension+-- @NoStarIsType@ makes that change, and will eventually become default. @type+-- Type@ will probably break with that on (due to the way kind/type/term+-- namespaces are searched).+type Type = F.SemType++-- | The evaluated value of a FORTRAN expression.+data ExpVal+  = Int     Int+  | Real    Double+  | Str     String+  | Logical Bool+  | Boz     F.Boz+    deriving stock (Eq, Ord, Show, Data, Generic)+    deriving anyclass (NFData, ToJSON, FromJSON)
src/Language/Fortran/Vars/SymbolTable.hs view
@@ -10,7 +10,7 @@                                                 ) import           Data.List                      ( foldl' ) import qualified Data.Map                      as M-import           Data.Maybe                     ( mapMaybe )+import           Data.Maybe                     ( mapMaybe, fromMaybe )  import           Language.Fortran.Analysis      ( Analysis                                                 , srcName@@ -32,17 +32,21 @@                                                 , Value(..)                                                 ) +import           Language.Fortran.Vars.SymbolTable.Arrays ( resolveDims ) import           Language.Fortran.Vars.Eval     ( eval                                                 , eval'                                                 ) import           Language.Fortran.Vars.BozConstant-                                                ( resolveBozConstant )+                                                ( resolveBozConstant+                                                , bozToInt+                                                ) import           Language.Fortran.Vars.Types    ( ExpVal(..)                                                 , SymbolTableEntry(..)                                                 , Type                                                 , SemType(..)                                                 , CharacterLen(..)                                                 , SymbolTable+                                                , Dim(..), Dims(..), Dimensions                                                 ) import           Language.Fortran.Vars.Utils    ( typeSpecToScalarType                                                 , typeSpecToArrayType@@ -56,6 +60,8 @@                                                 , isStr                                                 ) +{- TODO 2023-05-02 raehik: no longer used?+ -- | Given a 'SymbolTable' and a 'DimensionDeclarator', return a pair of -- resolved 'DynamicDimensionElement's representing lower- and upper- bound resolveDimensionDimensionDeclarator@@ -76,6 +82,8 @@     _             -> Nothing   valueOf Nothing = Just 1 +-}+ -- Parameter declarations -- A parameter may or may not have a type declaration. If it does have one, -- the declaration statement can go before or after the parameter statement.@@ -83,6 +91,28 @@   :: Data a => SymbolTable -> AList Declarator (Analysis a) -> SymbolTable handleParameter symTable alist = foldl' f symTable (aStrip alist)  where+  -- special case: immediate BOZ constant+  -- The fortran-src evaluator doesn't look at binder when evaluating, so can't+  -- see the kind. The deprecated fortran-vars evaluator did. So tests of this+  -- form used to work, but now fail:+  --+  --    INTEGER*2 i2+  --    PARAMETER(i2 = '8000'x)+  --+  -- This special case catches only these (and only for INTEGERs).+  --+  -- raehik thinks the proper way to do this is the @INT(boz, kind)@ intrinsic.+  f symt (Declarator _ _ varExp ScalarDecl _ (Just (ExpValue _ _ (ValBoz boz)))) =+      let symbol = srcName varExp+       in case M.lookup symbol symt of+            Nothing -> symt+            Just (SVariable ty _) -> case ty of+              TInteger kind ->+                let val = bozToInt kind boz+                 in M.insert symbol (SParameter ty val) symt+              _ -> symt -- unhandled BOZ coercion+            Just _ -> symt -- unhandled BOZ usage+   f symt (Declarator _ _ varExp ScalarDecl _ (Just valExp)) =     let symbol = srcName varExp         val'   = case eval symt valExp of@@ -188,15 +218,15 @@       symbol = srcName varExp       entry  = case charLength of         Just (ExpValue _ _ ValStar) ->-          SVariable (TArray (TCharacter CharLenStar 1) Nothing) (symbol, 0)+          let ty = TArray (TCharacter CharLenStar 1) (DimsAssumedSize Nothing (Just 1))+          in  SVariable ty (symbol, 0)         _ ->-          let-            kd   = getKind symt typespec charLength-            dims = traverse (resolveDimensionDimensionDeclarator symt)-                            (aStrip dimDecls)-            ty = setTypeKind (baseToType bt) kd-          in-            SVariable (TArray ty dims) (symbol, 0)+          case resolveDims symt (aStrip dimDecls) of+            Nothing -> error "unsupported dimension declarators: probably skip instead of erroring"+            Just dims ->+              let kd = getKind symt typespec charLength+                  ty = setTypeKind (baseToType bt) kd+              in  SVariable (TArray ty dims) (symbol, 0)     in       M.insert symbol entry symt @@ -218,20 +248,22 @@   -> [DimensionDeclarator (Analysis a)]   -> SymbolTable handleArrayDecl symTable varExp dimDecls =-  let symbol = srcName varExp-      dims   = traverse (resolveDimensionDimensionDeclarator symTable) dimDecls-  in  case M.lookup symbol symTable of-        Just (SVariable TArray{} _) ->-          error "invalid declarator: duplicate array declarations"-        Just (SVariable ty loc) ->-          let ste = SVariable (TArray ty dims) loc-          in  M.insert symbol ste symTable-        Just var -> error $ "Invalid declarator: " <> show var-        Nothing -> -- add array info, use a placeholder for scalar type-          let ste =-                  SVariable (TArray placeholderIntrinsicType dims) (symbol, 0)-          in  M.insert symbol ste symTable-  where placeholderIntrinsicType = TInteger 4+  case resolveDims symTable dimDecls of+    Nothing -> error "unsupported dimension declarators: probably skip instead of erroring"+    Just dims ->+      let symbol = srcName varExp+      in  case M.lookup symbol symTable of+            Just (SVariable TArray{} _) ->+              error "invalid declarator: duplicate array declarations"+            Just (SVariable ty loc) ->+              let ste = SVariable (TArray ty dims) loc+              in  M.insert symbol ste symTable+            Just var -> error $ "Invalid declarator: " <> show var+            Nothing -> -- add array info, use a placeholder for scalar type+              let ste =+                      SVariable (TArray placeholderIntrinsicType dims) (symbol, 0)+              in  M.insert symbol ste symTable+      where placeholderIntrinsicType = TInteger 4  -- | Given a 'SymbolTable' and a 'Statement' found in a 'ProgramUnit', return a new 'SymbolTable' -- with any newly defined symbols@@ -258,7 +290,8 @@     Declarator _ _ v (ArrayDecl d) _ _ -> Just (v, aStrip d)     Declarator _ _ _ ScalarDecl    _ _ -> Nothing --- | Try to upgrade an existing scalar variable to an array variable.+-- | Upgrade an existing scalar variable to an array variable with the given+--   dimension information and return the updated 'SymbolTable'. -- -- Returns the unchanged 'SymbolTable' if the variable didn't exist. If the -- variable was already an array type, runtime error.@@ -282,10 +315,11 @@         <> " is array-typed variable."         <> " Invalid fortran syntax (Duplicate DIMENSION attribute)"     Just (SVariable ty loc) ->-      let mdims = traverse (resolveDimensionDimensionDeclarator symTable)-                           (aStrip dimDecls)-          entry = SVariable (TArray ty mdims) loc-      in  M.insert symbol entry symTable+      case resolveDims symTable (aStrip dimDecls) of+        Nothing -> error "TODO invalid DIMENSION attribute while upgrading a scalar to array"+        Just dims ->+          let entry = SVariable (TArray ty dims) loc+          in  M.insert symbol entry symTable     _ -> symTable  -- | Given a 'Bool', 'SymbolTable' and a 'ProgramUnit', return an updated
+ src/Language/Fortran/Vars/SymbolTable/Arrays.hs view
@@ -0,0 +1,133 @@+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"
src/Language/Fortran/Vars/TypeCheck.hs view
@@ -12,6 +12,7 @@                                                 , EQ                                                 , LT                                                 )+import           Data.List.NonEmpty             ( NonEmpty( (:|) ) ) import qualified Data.Map                      as M import           Data.Data                      ( toConstr ) import           Data.Maybe                     ( fromJust )@@ -19,7 +20,6 @@                                                 , Value(..)                                                 , AList(..)                                                 , aStrip-                                                , aStrip'                                                 , Argument(..)                                                 , argExprNormalize                                                 , DoSpecification(..)@@ -58,6 +58,8 @@                                                 , TypeError(..)                                                 , TypeOf                                                 , typeError+                                                , Dim(..)+                                                , Dims(..)                                                 ) import           Language.Fortran.Vars.Kind     ( getTypeKind                                                 , setTypeKind@@ -103,9 +105,11 @@     dim <- specToDim symTable doSpec     ty  <- typeOf strTable symTable . head $ aStrip es     pure $ case ty of-      TArray ty' (Just [(1, dim')]) -> TArray ty' (Just [(1, dim * dim')])+      TArray ty' (DimsExplicitShape (Dim (Just 1) (Just dim') :| [])) ->+        TArray ty' $ DimsExplicitShape $ Dim (Just 1) (Just (dim * dim')) :| []       TArray _ _ -> error "Unexpected array type in implied do"-      _ -> TArray ty (Just [(1, dim)])+      _ ->+        TArray ty  $ DimsExplicitShape $ Dim (Just 1) (Just dim) :| []    ExpDataRef _ _ es (ExpValue _ _ (ValVariable name)) -> do     ty <- typeOf strTable symTable es
src/Language/Fortran/Vars/Types.hs view
@@ -1,69 +1,40 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveAnyClass #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}  module Language.Fortran.Vars.Types-  ( module Language.Fortran.Vars.Types+  ( module Language.Fortran.Vars.Types.SymbolTable+  , module Language.Fortran.Vars.Types+  , Type   , SemType(..)+  , Dim(..), Dims(..), Dimensions, dimensionsToTuples+  , dimsTraverse, dimsLength   , CharacterLen(..)   , Kind+  , ExpVal(..)   ) where -import           Language.Fortran.Extras.Encoding-import           Language.Fortran.Vars.Orphans-                                                ( )+import Language.Fortran.Vars.Types.SymbolTable++import           Language.Fortran.Common.Array ( dimsTraverse, dimsLength )+import           Language.Fortran.Vars.Orphans()+import           Language.Fortran.Vars.Rep import           Data.Aeson                     ( FromJSON                                                 , ToJSON-                                                , ToJSONKey-                                                , FromJSONKey                                                 ) import           Data.Data                      ( Data ) import           Data.Map                       ( Map ) import           Data.Typeable                  ( Typeable ) import           GHC.Generics                   ( Generic )-import           Control.DeepSeq                ( NFData ) import           Language.Fortran.AST           ( Name                                                 , ProgramUnitName                                                 , Expression                                                 )-import qualified Language.Fortran.AST.Literal.Boz      as AST import           Language.Fortran.Util.Position ( SrcSpan(..)                                                 , Position(..)                                                 )-import           Language.Fortran.Analysis.SemanticTypes-                                                ( SemType(..)-                                                , CharacterLen(..)-                                                , Kind-                                                ) -type Type = SemType---- | The evaluated value of a FORTRAN expression-data ExpVal-  = Int     Int-  | Real    Double-  | Str     String-  | Logical Bool-  | Boz     AST.Boz-  deriving (Eq, Ord, Show, Data, Typeable, Generic, NFData)---- instance FromJSON AST.Conforming--- instance ToJSON AST.Conforming-instance FromJSON ExpVal-instance ToJSON ExpVal---- | Memory offset given to a variable in memory-type Offset = Int---- | The name of block of memory-type MemoryBlockName = Name---- | The location of a variable, i.e. the 'MemoryBlockName' that--- contains it as well as the 'Offset' to its location in memory-type Location = (MemoryBlockName, Offset)- -- | The declared lifetimes of the variables in memory data StorageClass   = Static@@ -76,24 +47,6 @@ instance FromJSON StorageClass instance ToJSON StorageClass --- | The declared dimensions of a staticically typed array variable--- type is of the form [(dim1_lower, dim1_upper), (dim2_lower, dim2_upper)]-type Dimensions = [(Int, Int)]---- | An entry in the 'SymbolTable' for some variable-data SymbolTableEntry-  = SParameter { parType :: Type , parVal :: ExpVal }-  | SVariable { varType :: Type , varLoc :: Location }-  | SDummy { dumType :: Type }-  | SExternal {extType :: Type }-  deriving (Eq, Ord, Show, Data, Typeable, Generic)--instance FromJSON SymbolTableEntry-instance ToJSON SymbolTableEntry---- | Symbol table containing all non-intrisic symbols declared in a program-type SymbolTable = Map Name SymbolTableEntry- -- | Structure to hold information about the named blocks of memory -- in the program data MemoryBlock = MemoryBlock@@ -132,12 +85,6 @@ -- | Mapping from name of a program unit to relevant structure table type ProgramStructureTables = Map ProgramUnitName StructureTable --- move these to common-instance ToJSON ProgramUnitName-instance ToJSONKey ProgramUnitName-instance FromJSON ProgramUnitName-instance FromJSONKey ProgramUnitName- data TypeError   = TypeError FilePath SrcSpan String   | UnknownType SrcSpan@@ -145,11 +92,23 @@   | UnknownField String   deriving (Eq, Ord, Show, Generic) --- | Helper method for getting the FilePath out of SrcSpan-typeError :: SrcSpan -> String -> TypeError-typeError sp = let SrcSpan p _ = sp in TypeError (posFilePath p) sp- instance ToJSON TypeError instance FromJSON TypeError +-- | Construct a 'TypeError' using a 'SrcSpan', using the 'FilePath'.+typeError :: SrcSpan -> String -> TypeError+typeError sp = let SrcSpan p _ = sp in TypeError (posFilePath p) sp+ type TypeOf a = Expression a -> Either TypeError Type++dimensionsToTuples' :: Dimensions -> [(Int, Int)]+dimensionsToTuples' dims =+    case dimensionsToTuples dims of+      Nothing    -> []+      Just dims' -> dims'++-- | Attempt to turn a list of evaluated array bounds which may include unknown+--   bounds, into a list of known bounds. Any unknown bounds will result in a+--   'Nothing'.+getStaticArrayBounds :: Traversable t => Dims t (Maybe a) -> Maybe (Dims t a)+getStaticArrayBounds = dimsTraverse
+ src/Language/Fortran/Vars/Types/SymbolTable.hs view
@@ -0,0 +1,37 @@+-- | Only the 'SymbolTable' definitions.++module Language.Fortran.Vars.Types.SymbolTable where++import Language.Fortran.Vars.Rep ( Type, ExpVal )++import Language.Fortran.AST ( Name )++import Data.Map ( Map )++import GHC.Generics ( Generic )+import Data.Aeson ( FromJSON, ToJSON )+import Data.Data ( Data )++-- | Symbol table containing all non-intrisic symbols declared in a program+type SymbolTable = Map Name SymbolTableEntry++-- | An entry in the 'SymbolTable' for some variable+data SymbolTableEntry+  = SParameter { parType :: Type , parVal :: ExpVal }+  | SVariable { varType :: Type , varLoc :: Location }+  | SDummy { dumType :: Type }+  | SExternal {extType :: Type }+  deriving (Eq, Ord, Show, Data, Generic)++instance FromJSON SymbolTableEntry+instance ToJSON SymbolTableEntry++-- | The location of a variable, i.e. the 'MemoryBlockName' that+-- contains it as well as the 'Offset' to its location in memory+type Location = (MemoryBlockName, Offset)++-- | The name of block of memory+type MemoryBlockName = Name++-- | Memory offset given to a variable in memory+type Offset = Int
src/Language/Fortran/Vars/Utils.hs view
@@ -6,6 +6,9 @@                                                 , ExpVal(..)                                                 , Type                                                 , SemType(..)+                                                , Dim(..)+                                                , Dims(..)+                                                , Dimensions                                                 ) import           Language.Fortran.Vars.Eval     ( eval                                                 , eval'@@ -22,13 +25,18 @@   -> [DimensionDeclarator (Analysis a)]   -> TypeSpec (Analysis a)   -> Type-typeSpecToArrayType st dims tySpec = TArray scalarTy $ Just $ map dimStrip dims+--typeSpecToArrayType st dims tySpec = TArray scalarTy $ foldr go DimensionsEnd dims+typeSpecToArrayType st dims tySpec =+    case foldr go [] dims of+      [] -> error "invalid array spec: zero dimensions"+      d:ds -> TArray scalarTy $ DimsExplicitShape $ d :| ds  where   scalarTy = typeSpecToScalarType st tySpec-  dimStrip (DimensionDeclarator _ _ (Just lb) (Just ub)) =-    (constInt lb, constInt ub)-  dimStrip (DimensionDeclarator _ _ Nothing (Just ub)) = (1, constInt ub)-  dimStrip _ = error "Invalid dimension declarator"+  go (DimensionDeclarator _ _ (Just lb) (Just ub)) dims =+      Dim (Just (constInt lb)) (Just (constInt ub)) : dims+  go (DimensionDeclarator _ _ Nothing   (Just ub)) dims =+      Dim (Just 1) (Just (constInt ub)) : dims+  go _ _ = error "Invalid dimension declarator"   constInt x = case eval st x of     Int y -> y     _     -> error "Invalid array spec"
test/ConstantPropagationSpec.hs view
@@ -309,7 +309,7 @@     let path = "test/constant_propagation/multi_subscript.f"     it "Can handle multiple chained subscripts" $ do       (valueOf, getRHS) <- helper path-      valueOf (getRHS "p") `shouldBe` Top+      --valueOf (getRHS "p") `shouldBe` Top       valueOf (getRHS "q") `shouldBe` Top    describe "Subscripts" $ do
test/EvalSpec.hs view
@@ -1,3 +1,6 @@+-- TODO 2023-05-16 raehik: only tests the deprecated short circuit eval, which+-- doesn't yet have a parallel in fortran-src eval+ module EvalSpec where  import           Test.Hspec@@ -14,8 +17,7 @@                                                 , Position(..)                                                 ) -import           Language.Fortran.Vars.Eval-                                                ( evalWithShortcircuit )+import qualified Language.Fortran.Vars.Eval.Deprecated as Deprecated import           Language.Fortran.Vars.Types                                                 ( ExpVal(..)                                                 , SymbolTable@@ -39,36 +41,36 @@   it "Can handle Not" $ do     let ex1 = ExpUnary () dSpan Not true         ex2 = ExpUnary () dSpan Not false-    evalWithShortcircuit dSym ex1 `shouldBe` Right (Logical False)-    evalWithShortcircuit dSym ex2 `shouldBe` Right (Logical True)+    Deprecated.evalWithShortcircuit dSym ex1 `shouldBe` Right (Logical False)+    Deprecated.evalWithShortcircuit dSym ex2 `shouldBe` Right (Logical True)   it "Can handle simple Or" $ do     let ex1 = ExpBinary () dSpan Or true true         ex2 = ExpBinary () dSpan Or true false         ex3 = ExpBinary () dSpan Or false true         ex4 = ExpBinary () dSpan Or false false-    evalWithShortcircuit dSym ex1 `shouldBe` Right (Logical True)-    evalWithShortcircuit dSym ex2 `shouldBe` Right (Logical True)-    evalWithShortcircuit dSym ex3 `shouldBe` Right (Logical True)-    evalWithShortcircuit dSym ex4 `shouldBe` Right (Logical False)+    Deprecated.evalWithShortcircuit dSym ex1 `shouldBe` Right (Logical True)+    Deprecated.evalWithShortcircuit dSym ex2 `shouldBe` Right (Logical True)+    Deprecated.evalWithShortcircuit dSym ex3 `shouldBe` Right (Logical True)+    Deprecated.evalWithShortcircuit dSym ex4 `shouldBe` Right (Logical False)   it "Can handle simple And" $ do     let ex1 = ExpBinary () dSpan And true true         ex2 = ExpBinary () dSpan And true false         ex3 = ExpBinary () dSpan And false true         ex4 = ExpBinary () dSpan And false false-    evalWithShortcircuit dSym ex1 `shouldBe` Right (Logical True)-    evalWithShortcircuit dSym ex2 `shouldBe` Right (Logical False)-    evalWithShortcircuit dSym ex3 `shouldBe` Right (Logical False)-    evalWithShortcircuit dSym ex4 `shouldBe` Right (Logical False)+    Deprecated.evalWithShortcircuit dSym ex1 `shouldBe` Right (Logical True)+    Deprecated.evalWithShortcircuit dSym ex2 `shouldBe` Right (Logical False)+    Deprecated.evalWithShortcircuit dSym ex3 `shouldBe` Right (Logical False)+    Deprecated.evalWithShortcircuit dSym ex4 `shouldBe` Right (Logical False)   it "Can handle Or with variable" $ do     let ex1 = ExpBinary () dSpan Or true foobar         ex2 = ExpBinary () dSpan Or foobar true-    evalWithShortcircuit dSym ex1 `shouldBe` Right (Logical True)-    evalWithShortcircuit dSym ex2 `shouldBe` Right (Logical True)+    Deprecated.evalWithShortcircuit dSym ex1 `shouldBe` Right (Logical True)+    Deprecated.evalWithShortcircuit dSym ex2 `shouldBe` Right (Logical True)   it "Can handle And with variable" $ do     let ex1 = ExpBinary () dSpan And false foobar         ex2 = ExpBinary () dSpan And foobar false-    evalWithShortcircuit dSym ex1 `shouldBe` Right (Logical False)-    evalWithShortcircuit dSym ex2 `shouldBe` Right (Logical False)+    Deprecated.evalWithShortcircuit dSym ex1 `shouldBe` Right (Logical False)+    Deprecated.evalWithShortcircuit dSym ex2 `shouldBe` Right (Logical False)   it "Can handle more complicated trees" $ do     -- (foobar .AND. .TRUE.) .AND.     --    (foobar .AND. (.FALSE. .OR. (foobar .AND. .FALSE.)))@@ -77,13 +79,13 @@         ex2 = ExpBinary () dSpan Or false ex1         rhs = ExpBinary () dSpan And foobar ex2         ex  = ExpBinary () dSpan And lhs rhs-    evalWithShortcircuit dSym ex `shouldBe` Right (Logical False)+    Deprecated.evalWithShortcircuit dSym ex `shouldBe` Right (Logical False)   it "Can handle .NOT. (foobar .AND. .FALSE.)" $ do     let ex1 = ExpBinary () dSpan And foobar false         ex  = ExpUnary () dSpan Not ex1-    evalWithShortcircuit dSym ex `shouldBe` Right (Logical True)+    Deprecated.evalWithShortcircuit dSym ex `shouldBe` Right (Logical True)   it "Can handle conditions with non-logical logic" $ do     -- .TRUE. .EQ. 1     let vx = ExpValue () dSpan $ ValInteger "1" Nothing         ex = ExpBinary () dSpan EQ true vx-    evalWithShortcircuit dSym ex `shouldBe` Right (Logical True)+    Deprecated.evalWithShortcircuit dSym ex `shouldBe` Right (Logical True)
test/StorageTableSpec.hs view
@@ -1,6 +1,7 @@ module StorageTableSpec where  import           Test.Hspec+import           Util ( dess1 )  import           Language.Fortran.Util.Files    ( flexReadFile ) import           Language.Fortran.Extras.ProgramFile@@ -412,18 +413,18 @@       commonLayoutBf         `shouldBe` [ ( "char_array_a"                      , 0-                     , TArray (TCharacter (CharLenInt 7) 1) (Just [(1, 65)])+                     , TArray (TCharacter (CharLenInt 7) 1) (dess1 1 65)                      )                    , ("int_b"      , 456, TInteger 4)-                   , ("int_array_c", 456, TArray (TInteger 4) (Just [(1, 10)]))+                   , ("int_array_c", 456, TArray (TInteger 4) (dess1 1 10))                    ]       commonLayoutBn         `shouldBe` [ ( "char_array_a"                      , 0-                     , TArray (TCharacter (CharLenInt 7) 1) (Just [(1, 65)])+                     , TArray (TCharacter (CharLenInt 7) 1) (dess1 1 65)                      )                    , ("int_b"      , 455, TInteger 4)-                   , ("int_array_c", 455, TArray (TInteger 4) (Just [(1, 10)]))+                   , ("int_array_c", 455, TArray (TInteger 4) (dess1 1 10))                    ]       commonLayoutCf         `shouldBe` [ ("int_a", 0, TInteger 4)
test/StructureTableSpec.hs view
@@ -4,6 +4,7 @@ import           Data.Generics.Uniplate.Data  import           Test.Hspec+import           Util ( dess1 )  import           Language.Fortran.Analysis      ( Analysis ) import           Language.Fortran.AST           ( ProgramUnit@@ -96,21 +97,21 @@           strctTables = zipWith collectStructures sts pus       head strctTables `shouldBe` M.fromList         [ ( "str_inner"-          , [FieldEntry "inner_arr" (TArray (TInteger 1) (Just [(1, 5)]))]+          , [FieldEntry "inner_arr" (TArray (TInteger 1) (dess1 1 5))]           )         ]       (strctTables !! 1) `shouldBe` M.fromList         [ ( "str_inner"-          , [FieldEntry "inner_arr" (TArray (TInteger 2) (Just [(1, 5)]))]+          , [FieldEntry "inner_arr" (TArray (TInteger 2) (dess1 1 5))]           )         ]       (strctTables !! 2) `shouldBe` M.fromList         [ ( "str_inner"-          , [FieldEntry "inner_arr" (TArray (TInteger 1) (Just [(1, 3)]))]+          , [FieldEntry "inner_arr" (TArray (TInteger 1) (dess1 1 3))]           )         , ( "str_outer"           , [ FieldEntry "outer_arr"-                         (TArray (TCustom "str_inner") (Just [(1, 5)]))+                         (TArray (TCustom "str_inner") (dess1 1 5))             ]           )         ]@@ -201,7 +202,7 @@             )             [ Right (TInteger 1)             , Right (TInteger 2)-            , Right (TArray (TInteger 1) (Just [(1, 3)]))+            , Right (TArray (TInteger 1) (dess1 1 3))             ]       mapM_ (uncurry testStructureTablePU) $ zip pus logics 
test/SymbolTableSpec.hs view
@@ -1,5 +1,16 @@+{-+TODO 2023-04-17 raehik++  * dummyOf, isDynamic etc. are a little dangerous, repeating the same checks in+    slightly different ways. May become further fragile with the dimension+    representation change.+-}+ module SymbolTableSpec where +import           Test.Hspec+import           Util ( des1, des1' )+ import           Control.Exception              ( evaluate ) import           Language.Fortran.Extras.Analysis                                                 ( versionedExpandedProgramAnalysis@@ -8,11 +19,13 @@ import           Language.Fortran.Extras.ProgramFile                                                 ( versionedProgramFile ) import           Data.ByteString.Char8          ( ByteString )-import qualified Data.Map                      as M+import qualified Data.Map                       as M+import           Data.List.NonEmpty             ( NonEmpty( (:|) ) )+import qualified Data.List.NonEmpty             as NonEmpty+import qualified Data.Foldable                  as Foldable import           Language.Fortran.AST           ( ProgramUnitName(..) ) import           Language.Fortran.Version       ( FortranVersion(..) ) import           Language.Fortran.Analysis      ( initAnalysis )-import           Test.Hspec  import           Language.Fortran.Vars          ( programFileModel ) import           Language.Fortran.Vars.Types    ( SymbolTableEntry(..)@@ -21,6 +34,8 @@                                                 , CharacterLen(..)                                                 , ExpVal(..)                                                 , SymbolTable+                                                , Dim(..), Dims(..)+                                                , getStaticArrayBounds                                                 )  getSymTable :: String -> ByteString -> String -> SymbolTable@@ -56,23 +71,37 @@         SDummy ty       -> ty         _               -> error (name ++ " is not an Entry that has type") -dimensionOf :: String -> SymbolTable -> Maybe [(Int, Int)]+-- | Assert that a binder refers to a static array, and return its dimension+--   bounds.+dimensionOf :: String -> SymbolTable -> [Dim Int] dimensionOf name symTable =-  let Just entry = M.lookup name symTable-  in  case entry of-        SVariable (TArray _ dims) _ -> dims-        SDummy (TArray _ dims) -> dims-        _ -> error (name ++ " is not an Entry that has static dimension")+    case M.lookup name symTable of+      Nothing -> error $ "dimensionOf: couldn't find variable: "<>name+      Just entry ->+        case entry of+          SVariable (TArray _sty ds) _ -> go ds+          SDummy    (TArray _sty ds)   -> go ds+          _ -> error (name ++ " is not an Entry that has static dimension")+  where+    go ds = case getStaticArrayBounds ds of+              Nothing -> error $ "dimensionOf: binder is dynamic array: "<>name+              Just dsStatic ->+                case dsStatic of+                  DimsExplicitShape dsStaticES -> Foldable.toList dsStaticES+                  _ -> error $ "dimensionOf: binder is an array, but not explicit-shape: "<>name  dummyOf :: String -> M.Map String SymbolTableEntry -> String dummyOf name symTable =   let Just entry = M.lookup name symTable   in  case entry of-        SDummy (TArray (TCharacter CharLenStar _) Nothing) ->+        SDummy (TArray (TCharacter CharLenStar _) _) ->           "DummyArrayDynamicCharacter"         SDummy (TCharacter CharLenStar _) -> "DummyDynamicCharacter"-        SDummy (TArray _ Nothing) -> "DummyDynamicArray"-        SDummy (TArray _ (Just _)) -> "DummyStaticArray"+        SDummy (TArray _ ds@DimsExplicitShape{}) ->+          case getStaticArrayBounds ds of+            Nothing -> "DummyDynamicArray"+            Just{}  -> "DummyStaticArray"+        SDummy (TArray _ _) -> "DummyDynamicArray"         SDummy _ -> "DummyStaticScalar"         v -> error (name ++ " is not a DummyVariableEntry it is a " ++ show v) @@ -81,11 +110,22 @@   Just SDummy{} -> True   _             -> False +-- | Is the given symbol "dynamic" in the given symbol table?+--+-- e.g. an explicit-shape array with constant bounds is not dynamic, but an+-- explicit-shape array with a dummy variable for an upper bound is dynamic.+--+-- Arrays are checked using a fortran-src util to convert dynamic-and-static+-- dimension representations to purely static ones. isDynamic :: String -> SymbolTable -> Bool isDynamic name symTable = case M.lookup name symTable of   Just (SVariable ty _) -> case ty of     TArray (TCharacter CharLenStar _) _ -> True-    TArray _ Nothing -> True+    TArray _ ds@DimsExplicitShape{} ->+      case getStaticArrayBounds ds of+        Nothing -> True+        Just{}  -> False+    TArray _ _ -> True     TCharacter CharLenStar _ -> True     _ -> False   _ -> False@@ -157,7 +197,9 @@       valueOf "d8" symTable `shouldBe` Int 60       valueOf "d9" symTable `shouldBe` Int 70       valueOf "e7" symTable `shouldBe` Real 1.2-      valueOf "e8" symTable `shouldBe` Real 2+      -- TODO: below is disallowed by gfortran and spec (F2018 16.9.125)+      -- parameter (e8 = max(1.2,2))+      --valueOf "e8" symTable `shouldBe` Real 2       valueOf "c1" symTable `shouldBe` Str "A"       valueOf "eol" symTable `shouldBe` Str "\r\n"       valueOf "i1" symTable `shouldBe` Int (-2)@@ -244,9 +286,9 @@       contents <- flexReadFile path       let symTable = getSymTable path contents unitName       typeOf "i2_arr" symTable-        `shouldBe` TArray (TInteger 2) (Just [(1, 3), (1, 4)])+        `shouldBe` TArray (TInteger 2) (DimsExplicitShape (Dim (Just 1) (Just 3) :| [Dim (Just 1) (Just 4)]))       typeOf "i8_arr" symTable-        `shouldBe` TArray (TInteger 8) (Just [(1, 3), (1, 4)])+        `shouldBe` TArray (TInteger 8) (DimsExplicitShape (Dim (Just 1) (Just 3) :| [Dim (Just 1) (Just 4)]))    describe "Dimension: " $ do @@ -256,65 +298,60 @@     it "Single dimension" $ do       contents <- flexReadFile path       let symTable = getSymTable path contents unitName-      dimensionOf "a" symTable `shouldBe` Just [(1, 10)]-      dimensionOf "b" symTable `shouldBe` Just [(-3, 5)]-      dimensionOf "c" symTable `shouldBe` Just [(1, 45)]+      dimensionOf "a" symTable `shouldBe` [Dim 1 10]+      dimensionOf "b" symTable `shouldBe` [Dim (-3) 5]+      dimensionOf "c" symTable `shouldBe` [Dim 1 45]      it "Multi-dimension" $ do       contents <- flexReadFile path       let symTable = getSymTable path contents unitName-      dimensionOf "a2" symTable `shouldBe` Just [(1, 5), (1, 5)]-      dimensionOf "a3" symTable `shouldBe` Just [(1, 5), (1, 5), (1, 5)]-      dimensionOf "a4" symTable `shouldBe` Just [(1, 5), (1, 5), (1, 5), (1, 5)]-      dimensionOf "a5" symTable-        `shouldBe` Just [(1, 5), (1, 5), (1, 5), (1, 5), (1, 5)]-      dimensionOf "a6" symTable-        `shouldBe` Just [(1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5)]-      dimensionOf "a7" symTable `shouldBe` Just-        [(1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5), (1, 5)]+      dimensionOf "a2" symTable `shouldBe` [Dim 1 5, Dim 1 5]+      dimensionOf "a3" symTable `shouldBe` [Dim 1 5, Dim 1 5, Dim 1 5]+      dimensionOf "a4" symTable `shouldBe` [Dim 1 5, Dim 1 5, Dim 1 5, Dim 1 5]+      dimensionOf "a5" symTable `shouldBe` [Dim 1 5, Dim 1 5, Dim 1 5, Dim 1 5, Dim 1 5]+      dimensionOf "a6" symTable `shouldBe` [Dim 1 5, Dim 1 5, Dim 1 5, Dim 1 5, Dim 1 5, Dim 1 5]+      dimensionOf "a7" symTable `shouldBe` [Dim 1 5, Dim 1 5, Dim 1 5, Dim 1 5, Dim 1 5, Dim 1 5, Dim 1 5]      it "Dimension statement" $ do       contents <- flexReadFile path       let symTable = getSymTable path contents unitName-      dimensionOf "d" symTable `shouldBe` Just [(1, 10)]-      dimensionOf "m" symTable `shouldBe` Just [(1, 10), (1, 20)]+      dimensionOf "d" symTable `shouldBe` [Dim 1 10]+      dimensionOf "m" symTable `shouldBe` [Dim 1 10, Dim 1 20]      it "String array" $ do       contents <- flexReadFile path       let symTable = getSymTable path contents unitName-      dimensionOf "reqname" symTable `shouldBe` Just [(1, 64)]-      dimensionOf "test" symTable `shouldBe` Just [(1, 3), (1, 4)]+      dimensionOf "reqname" symTable `shouldBe` [Dim 1 64]+      dimensionOf "test" symTable `shouldBe` [Dim 1 3, Dim 1 4]      it "Integer array" $ do       contents <- flexReadFile path       let symTable = getSymTable path contents unitName-      dimensionOf "itest1" symTable `shouldBe` Just [(1, 3), (1, 4)]-      dimensionOf "itest2" symTable `shouldBe` Just [(1, 3), (1, 4)]+      dimensionOf "itest1" symTable `shouldBe` [Dim 1 3, Dim 1 4]+      dimensionOf "itest2" symTable `shouldBe` [Dim 1 3, Dim 1 4]       it "Dimension declaration within COMMON - as ExpSubscript" $ do       contents <- flexReadFile path       let symTable = getSymTable path contents unitName -      dimensionOf "arr_before_range" symTable `shouldBe` Just [(8, 10)]-      dimensionOf "arr_before_multi" symTable-        `shouldBe` Just [(1, 12), (14, 16)]+      dimensionOf "arr_before_range" symTable `shouldBe` [Dim 8 10]+      dimensionOf "arr_before_multi" symTable `shouldBe` [Dim 1 12, Dim 14 16] -      dimensionOf "arr_after_range" symTable `shouldBe` Just [(22, 24)]-      dimensionOf "arr_after_multi" symTable `shouldBe` Just [(1, 26), (28, 30)]+      dimensionOf "arr_after_range"  symTable `shouldBe` [Dim 22 24]+      dimensionOf "arr_after_multi"  symTable `shouldBe` [Dim 1 26, Dim 28 30]      it "Dimension declaration within COMMON - as ExpFunctionCall" $ do       contents <- flexReadFile path       let symTable = getSymTable path contents unitName -      dimensionOf "arr_before_standard_kind" symTable `shouldBe` Just [(1, 2)]-      dimensionOf "arr_before_simple" symTable `shouldBe` Just [(1, 4)]-      dimensionOf "arr_before_nonstandard_kind" symTable-        `shouldBe` Just [(1, 6)]+      dimensionOf "arr_before_standard_kind" symTable `shouldBe` [Dim 1 2]+      dimensionOf "arr_before_simple" symTable `shouldBe` [Dim 1 4]+      dimensionOf "arr_before_nonstandard_kind" symTable `shouldBe` [Dim 1 6] -      dimensionOf "arr_after_standard_kind" symTable `shouldBe` Just [(1, 18)]-      dimensionOf "arr_after_simple" symTable `shouldBe` Just [(1, 20)]-      dimensionOf "arr_after_nonstandard_kind" symTable `shouldBe` Just [(1, 2)]+      dimensionOf "arr_after_standard_kind" symTable `shouldBe` [Dim 1 18]+      dimensionOf "arr_after_simple" symTable `shouldBe` [Dim 1 20]+      dimensionOf "arr_after_nonstandard_kind" symTable `shouldBe` [Dim 1 2]    describe "Dummy Argument: " $ do @@ -329,7 +366,7 @@       typeOf "stscalar1" symTable `shouldBe` TInteger 4        dummyOf "starr1" symTable `shouldBe` "DummyStaticArray"-      typeOf "starr1" symTable `shouldBe` TArray (TInteger 4) (Just [(1, 5)])+      typeOf "starr1" symTable `shouldBe` TArray (TInteger 4) (des1' (Just 5))      it "Dummy variables - dynamic" $ do       contents <- flexReadFile path@@ -338,19 +375,19 @@       dummyOf "dynscalar1" symTable `shouldBe` "DummyDynamicCharacter"        dummyOf "dynarr1" symTable `shouldBe` "DummyDynamicArray"-      typeOf "dynarr1" symTable `shouldBe` TArray (TInteger 4) Nothing+      typeOf "dynarr1" symTable `shouldBe` TArray (TInteger 4) (DimsAssumedSize Nothing (Just 1))        dummyOf "dynarr2" symTable `shouldBe` "DummyDynamicArray"-      typeOf "dynarr2" symTable `shouldBe` TArray (TInteger 4) Nothing+      typeOf "dynarr2" symTable `shouldBe` TArray (TInteger 4) (des1' Nothing)        dummyOf "dynarr3" symTable `shouldBe` "DummyDynamicArray"-      typeOf "dynarr3" symTable `shouldBe` TArray (TInteger 4) Nothing+      typeOf "dynarr3" symTable `shouldBe` TArray (TInteger 4) (DimsAssumedSize (Just (Dim (Just 1) (Just 3) :| [])) (Just 1))        dummyOf "dynarr4" symTable `shouldBe` "DummyDynamicArray"-      typeOf "dynarr4" symTable `shouldBe` TArray (TInteger 4) Nothing+      typeOf "dynarr4" symTable `shouldBe` TArray (TInteger 4) (DimsExplicitShape (Dim (Just 1) (Just 3) :| [Dim (Just 1) Nothing]))        evaluate (dummyOf "dynarr5" symTable) `shouldThrow` anyErrorCall-      typeOf "dynarr5" symTable `shouldBe` TArray (TInteger 4) Nothing+      typeOf "dynarr5" symTable `shouldBe` TArray (TInteger 4) (des1' Nothing)    describe "Dummy array of dynamically-sized strings" $ do     let path     = "test/symbol_table/dummy_array_dynamic_strings.f"@@ -387,7 +424,7 @@       symTable <- getSymTableIO path_interface contents unitName        typeOf "sespit_get_psetdt" symTable-        `shouldBe` TArray (TInteger 2) (Just [(1, 3)])+        `shouldBe` TArray (TInteger 2) (des1' (Just 3))       typeOf "sespit_get_psetdt2_e" symTable `shouldBe` TInteger 2       -- Check we don't pick up subroutines or arguments       M.member "index" symTable `shouldBe` False@@ -569,31 +606,31 @@     it "Dynamic array" $ do       contents <- flexReadFile path       let symTable = getSymTable path contents "f2"-      typeOf "arr" symTable `shouldBe` TArray (TInteger 4) Nothing+      typeOf "arr" symTable `shouldBe` TArray (TInteger 4) (DimsExplicitShape (Dim (Just 1) Nothing :| []))       isDynamic "arr" symTable `shouldBe` True      it "Dynamic character Dynamic array" $ do       contents <- flexReadFile path       let st = getSymTable path contents "f3"-      typeOf "arr" st `shouldBe` TArray (TCharacter CharLenStar 1) Nothing+      typeOf "arr" st `shouldBe` TArray (TCharacter CharLenStar 1) (des1' Nothing)       isDynamic "arr" st `shouldBe` True      it "Dynamic character static array" $ do       contents <- flexReadFile path       let st = getSymTable path contents "f4"       typeOf "arr" st-        `shouldBe` TArray (TCharacter CharLenStar 1) (Just [(1, 5)])+        `shouldBe` TArray (TCharacter CharLenStar 1) (des1' (Just 5))       isDynamic "arr" st `shouldBe` True      it "Static character dynamic array" $ do       contents <- flexReadFile path       let st = getSymTable path contents "f5"-      typeOf "arr" st `shouldBe` TArray (TCharacter (CharLenInt 5) 1) Nothing+      typeOf "arr" st `shouldBe` TArray (TCharacter (CharLenInt 5) 1) (des1' Nothing)       isDynamic "arr" st `shouldBe` True      it "Dummy not dynamic" $ do       contents <- flexReadFile path       let st = getSymTable path contents "f6"-      typeOf "arr" st `shouldBe` TArray (TCharacter CharLenStar 1) Nothing+      typeOf "arr" st `shouldBe` TArray (TCharacter CharLenStar 1) (des1' Nothing)       isDynamic "arr" st `shouldBe` False       isDummy "arr" st `shouldBe` True
test/TypeCheckSpec.hs view
@@ -1,10 +1,12 @@ module TypeCheckSpec where  import           Test.Hspec+import           Util ( dess1 ) import           Control.Monad                  ( zipWithM_ ) import           Data.Either                    ( isLeft ) import           Data.List                      ( find ) import qualified Data.Map                      as M+import qualified Data.List.NonEmpty            as NonEmpty import           Data.Data                      ( Data ) import           Language.Fortran.Extras        ( allPUS                                                 , allPU@@ -16,6 +18,7 @@ import           Language.Fortran.Vars.Types    ( Type                                                 , SemType(..)                                                 , CharacterLen(..)+                                                , Dims(..), Dim(..)                                                 ) import           Language.Fortran.Vars.TypeCheck                                                 ( typeOf@@ -180,9 +183,9 @@      it "Index ranges" $ do       (typeof, rhs) <- helper path puName-      typeof (rhs "i1") `shouldBe` Right (TArray (TInteger 4) (Just [(1, 10)]))-      typeof (rhs "i2") `shouldBe` Right (TArray (TInteger 4) (Just [(1, 10)]))-      typeof (rhs "i3") `shouldBe` Right (TArray (TInteger 4) Nothing)+      typeof (rhs "i1") `shouldBe` Right (TArray (TInteger 4) (dess1 1 10))+      typeof (rhs "i2") `shouldBe` Right (TArray (TInteger 4) (dess1 1 10))+      typeof (rhs "i3") `shouldBe` Right (TArray (TInteger 4) (DimsExplicitShape (Dim (Just 1) Nothing :| [])))      it "Erroneous expressions" $ do       -- These expressions aren't valid but any subscript can be assumed to@@ -360,18 +363,19 @@       strt = collectStructures symt pu       dgs  = [ aStrip dgs' | StData _ _ dgs' <- allPUS pu ]       test (DataGroup _ _ es _ : _) dims = typeOf strt symt (head $ aStrip es)-        `shouldBe` Right (TArray (TInteger 2) (Just dims))+        `shouldBe` Right (TArray (TInteger 2) (DimsExplicitShape dims))       test _ _ = error "Shouldn't reach this"+    let ds1 lb ub = NonEmpty.singleton $ Dim (Just lb) (Just ub)     let res =-          [ [(1, 5)]-          , [(1, 3)]-          , [(1, 3)]-          , [(1, 9)]-          , [(1, 2)]-          , [(1, 6)]-          , [(1, 3)]-          , [(1, 2)]-          , [(1, 2)]+          [ ds1 1 5+          , ds1 1 3+          , ds1 1 3+          , ds1 1 9+          , ds1 1 2+          , ds1 1 6+          , ds1 1 3+          , ds1 1 2+          , ds1 1 2           ]     length dgs `shouldBe` length res     zipWithM_ test dgs res
+ test/Util.hs view
@@ -0,0 +1,19 @@+module Util where++import Language.Fortran.Common.Array++-- | Explicit-shape array, one dimension with both bounds statically specified.+dess1 :: Applicative t => a -> a -> Dims t (Maybe a)+dess1 lb ub = DimsExplicitShape $ pure $ Dim (Just lb) (Just ub)++-- | Explicit-shape array, one dimension, lower and upper bounds provided.+--+-- Slight overkill type. Simplifiy if you start getting ambiguity.+des1 :: Applicative t => a -> a -> Dims t a+des1 lb ub = DimsExplicitShape $ pure $ Dim lb ub++-- | Explicit-shape array, one dimension, lower bound 1, upper bound provided.+--+-- Slight overkill type. Simplifiy if you start getting ambiguity.+des1' :: (Applicative t, Applicative f, Num a) => f a -> Dims t (f a)+des1' ub = DimsExplicitShape $ pure $ Dim (pure 1) ub