packages feed

fortran-src 0.4.3 → 0.5.0

raw patch · 25 files changed

+881/−258 lines, 25 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Language.Fortran.AST: CharLenColon :: CharacterLen
- Language.Fortran.AST: CharLenExp :: CharacterLen
- Language.Fortran.AST: CharLenInt :: Int -> CharacterLen
- Language.Fortran.AST: CharLenStar :: CharacterLen
- Language.Fortran.AST: charLenSelector :: Maybe (Selector a) -> (Maybe CharacterLen, Maybe String)
- Language.Fortran.AST: data CharacterLen
- Language.Fortran.AST: instance Control.DeepSeq.NFData Language.Fortran.AST.CharacterLen
- Language.Fortran.AST: instance Data.Binary.Class.Binary Language.Fortran.AST.CharacterLen
- Language.Fortran.AST: instance Data.Data.Data Language.Fortran.AST.CharacterLen
- Language.Fortran.AST: instance GHC.Classes.Eq Language.Fortran.AST.CharacterLen
- Language.Fortran.AST: instance GHC.Classes.Ord Language.Fortran.AST.CharacterLen
- Language.Fortran.AST: instance GHC.Generics.Generic Language.Fortran.AST.CharacterLen
- Language.Fortran.AST: instance GHC.Show.Show Language.Fortran.AST.CharacterLen
- Language.Fortran.AST: instance Text.PrettyPrint.GenericPretty.Out Language.Fortran.AST.CharacterLen
- Language.Fortran.Analysis: ClassCustom :: String -> BaseType
- Language.Fortran.Analysis: ClassStar :: BaseType
- Language.Fortran.Analysis: TypeByte :: BaseType
- Language.Fortran.Analysis: TypeCharacter :: Maybe CharacterLen -> Maybe String -> BaseType
- Language.Fortran.Analysis: TypeComplex :: BaseType
- Language.Fortran.Analysis: TypeCustom :: String -> BaseType
- Language.Fortran.Analysis: TypeDoubleComplex :: BaseType
- Language.Fortran.Analysis: TypeDoublePrecision :: BaseType
- Language.Fortran.Analysis: TypeInteger :: BaseType
- Language.Fortran.Analysis: TypeLogical :: BaseType
- Language.Fortran.Analysis: TypeReal :: BaseType
- Language.Fortran.Analysis: data BaseType
- Language.Fortran.PrettyPrint: instance Language.Fortran.PrettyPrint.Pretty Language.Fortran.AST.CharacterLen
+ Language.Fortran.AST: type Kind = Int
+ Language.Fortran.Analysis.SemanticTypes: CharLenColon :: CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: CharLenExp :: CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: CharLenInt :: Int -> CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: CharLenStar :: CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: TArray :: SemType -> Maybe Dimensions -> SemType
+ Language.Fortran.Analysis.SemanticTypes: TByte :: Kind -> SemType
+ Language.Fortran.Analysis.SemanticTypes: TCharacter :: CharacterLen -> Kind -> SemType
+ Language.Fortran.Analysis.SemanticTypes: TComplex :: Kind -> SemType
+ Language.Fortran.Analysis.SemanticTypes: TCustom :: String -> SemType
+ Language.Fortran.Analysis.SemanticTypes: TInteger :: Kind -> SemType
+ Language.Fortran.Analysis.SemanticTypes: TLogical :: Kind -> SemType
+ Language.Fortran.Analysis.SemanticTypes: TReal :: Kind -> SemType
+ Language.Fortran.Analysis.SemanticTypes: charLenConcat :: CharacterLen -> CharacterLen -> CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: charLenSelector :: Maybe (Selector a) -> (Maybe CharacterLen, Maybe String)
+ Language.Fortran.Analysis.SemanticTypes: charLenSelector' :: Expression a -> CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: charLenToValue :: CharacterLen -> Maybe (Value a)
+ Language.Fortran.Analysis.SemanticTypes: data CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: data SemType
+ Language.Fortran.Analysis.SemanticTypes: getTypeKind :: SemType -> Kind
+ Language.Fortran.Analysis.SemanticTypes: getTypeSize :: SemType -> Maybe Int
+ Language.Fortran.Analysis.SemanticTypes: instance Control.DeepSeq.NFData Language.Fortran.Analysis.SemanticTypes.CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: instance Data.Binary.Class.Binary Language.Fortran.Analysis.SemanticTypes.CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: instance Data.Binary.Class.Binary Language.Fortran.Analysis.SemanticTypes.SemType
+ Language.Fortran.Analysis.SemanticTypes: instance Data.Data.Data Language.Fortran.Analysis.SemanticTypes.CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: instance Data.Data.Data Language.Fortran.Analysis.SemanticTypes.SemType
+ Language.Fortran.Analysis.SemanticTypes: instance GHC.Classes.Eq Language.Fortran.Analysis.SemanticTypes.CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: instance GHC.Classes.Eq Language.Fortran.Analysis.SemanticTypes.SemType
+ Language.Fortran.Analysis.SemanticTypes: instance GHC.Classes.Ord Language.Fortran.Analysis.SemanticTypes.CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: instance GHC.Classes.Ord Language.Fortran.Analysis.SemanticTypes.SemType
+ Language.Fortran.Analysis.SemanticTypes: instance GHC.Generics.Generic Language.Fortran.Analysis.SemanticTypes.CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: instance GHC.Generics.Generic Language.Fortran.Analysis.SemanticTypes.SemType
+ Language.Fortran.Analysis.SemanticTypes: instance GHC.Show.Show Language.Fortran.Analysis.SemanticTypes.CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: instance GHC.Show.Show Language.Fortran.Analysis.SemanticTypes.SemType
+ Language.Fortran.Analysis.SemanticTypes: instance Language.Fortran.PrettyPrint.Pretty Language.Fortran.Analysis.SemanticTypes.SemType
+ Language.Fortran.Analysis.SemanticTypes: instance Text.PrettyPrint.GenericPretty.Out Language.Fortran.Analysis.SemanticTypes.CharacterLen
+ Language.Fortran.Analysis.SemanticTypes: instance Text.PrettyPrint.GenericPretty.Out Language.Fortran.Analysis.SemanticTypes.SemType
+ Language.Fortran.Analysis.SemanticTypes: kindOfBaseType :: BaseType -> Int
+ Language.Fortran.Analysis.SemanticTypes: recoverSemTypeTypeSpec :: forall a. a -> SrcSpan -> FortranVersion -> SemType -> TypeSpec a
+ Language.Fortran.Analysis.SemanticTypes: setTypeKind :: SemType -> Kind -> SemType
+ Language.Fortran.Analysis.SemanticTypes: setTypeSize :: SemType -> Maybe Int -> SemType
+ Language.Fortran.Analysis.SemanticTypes: type Dimensions = [(Int, Int)]
+ Language.Fortran.Analysis.Types: deriveSemTypeFromBaseType :: BaseType -> SemType
+ Language.Fortran.Analysis.Types: deriveSemTypeFromDeclaration :: SrcSpan -> SrcSpan -> TypeSpec a -> Maybe (Expression a) -> Infer SemType
+ Language.Fortran.Analysis.Types: deriveSemTypeFromTypeSpec :: TypeSpec a -> Infer SemType
+ Language.Fortran.Analysis.Types: inferState0 :: FortranVersion -> InferState
+ Language.Fortran.Analysis.Types: runInfer :: FortranVersion -> TypeEnv -> State InferState a -> (a, InferState)
+ Language.Fortran.Parser.Utils: ExpLetterD :: ExponentLetter
+ Language.Fortran.Parser.Utils: ExpLetterE :: ExponentLetter
+ Language.Fortran.Parser.Utils: Exponent :: ExponentLetter -> Maybe NumSign -> Int -> Exponent
+ Language.Fortran.Parser.Utils: RealLit :: String -> Maybe Exponent -> Maybe KindParam -> RealLit
+ Language.Fortran.Parser.Utils: SignNeg :: NumSign
+ Language.Fortran.Parser.Utils: SignPos :: NumSign
+ Language.Fortran.Parser.Utils: [expLetter] :: Exponent -> ExponentLetter
+ Language.Fortran.Parser.Utils: [expNum] :: Exponent -> Int
+ Language.Fortran.Parser.Utils: [expSign] :: Exponent -> Maybe NumSign
+ Language.Fortran.Parser.Utils: [realLitExponent] :: RealLit -> Maybe Exponent
+ Language.Fortran.Parser.Utils: [realLitKindParam] :: RealLit -> Maybe KindParam
+ Language.Fortran.Parser.Utils: [realLitValue] :: RealLit -> String
+ Language.Fortran.Parser.Utils: data Exponent
+ Language.Fortran.Parser.Utils: data ExponentLetter
+ Language.Fortran.Parser.Utils: data NumSign
+ Language.Fortran.Parser.Utils: data RealLit
+ Language.Fortran.Parser.Utils: instance GHC.Classes.Eq Language.Fortran.Parser.Utils.Exponent
+ Language.Fortran.Parser.Utils: instance GHC.Classes.Eq Language.Fortran.Parser.Utils.ExponentLetter
+ Language.Fortran.Parser.Utils: instance GHC.Classes.Eq Language.Fortran.Parser.Utils.NumSign
+ Language.Fortran.Parser.Utils: instance GHC.Classes.Eq Language.Fortran.Parser.Utils.RealLit
+ Language.Fortran.Parser.Utils: instance GHC.Classes.Ord Language.Fortran.Parser.Utils.Exponent
+ Language.Fortran.Parser.Utils: instance GHC.Classes.Ord Language.Fortran.Parser.Utils.ExponentLetter
+ Language.Fortran.Parser.Utils: instance GHC.Classes.Ord Language.Fortran.Parser.Utils.NumSign
+ Language.Fortran.Parser.Utils: instance GHC.Classes.Ord Language.Fortran.Parser.Utils.RealLit
+ Language.Fortran.Parser.Utils: instance GHC.Show.Show Language.Fortran.Parser.Utils.Exponent
+ Language.Fortran.Parser.Utils: instance GHC.Show.Show Language.Fortran.Parser.Utils.ExponentLetter
+ Language.Fortran.Parser.Utils: instance GHC.Show.Show Language.Fortran.Parser.Utils.NumSign
+ Language.Fortran.Parser.Utils: instance GHC.Show.Show Language.Fortran.Parser.Utils.RealLit
+ Language.Fortran.Parser.Utils: parseRealLiteral :: String -> RealLit
- Language.Fortran.AST: TypeCharacter :: Maybe CharacterLen -> Maybe String -> BaseType
+ Language.Fortran.AST: TypeCharacter :: BaseType
- Language.Fortran.Analysis: IDType :: Maybe BaseType -> Maybe ConstructType -> IDType
+ Language.Fortran.Analysis: IDType :: Maybe SemType -> Maybe ConstructType -> IDType
- Language.Fortran.Analysis: [idVType] :: IDType -> Maybe BaseType
+ Language.Fortran.Analysis: [idVType] :: IDType -> Maybe SemType
- Language.Fortran.Analysis: genVar :: Analysis a -> SrcSpan -> String -> Expression (Analysis a)
+ Language.Fortran.Analysis: genVar :: Analysis a -> SrcSpan -> Name -> Expression (Analysis a)
- Language.Fortran.Analysis: lvSrcName :: LValue (Analysis a) -> String
+ Language.Fortran.Analysis: lvSrcName :: LValue (Analysis a) -> Name
- Language.Fortran.Analysis: lvVarName :: LValue (Analysis a) -> String
+ Language.Fortran.Analysis: lvVarName :: LValue (Analysis a) -> Name
- Language.Fortran.Analysis: srcName :: Expression (Analysis a) -> String
+ Language.Fortran.Analysis: srcName :: Expression (Analysis a) -> Name
- Language.Fortran.Analysis: varName :: Expression (Analysis a) -> String
+ Language.Fortran.Analysis: varName :: Expression (Analysis a) -> Name

Files

CHANGELOG.md view
@@ -1,3 +1,21 @@+### 0.5.0 (Jun 30, 2021)+  * Introduce a second-stage type representation including kind info alongside+    types, and resolving some types to semantic type with preset kinds (e.g.+    `DOUBLE PRECISION` -> `REAL(8)`).+    * Module is at Language.Fortran.Analysis.SemanticTypes . Includes utils and+      instances.+    * The type analysis in Language.Fortran.Analysis.Types uses this+      representation now (`IDType` stores a `SemType` instead of a `BaseType`).+  * Move `CharacterLen` from parsing to type analysis.+    * This makes `BaseType` now a plain tag/enum with no extra info.+  * Add extended Fortran 90 real literal parser (parses kind info).+  * Export some infer monad utils (potentially useful for running just parts of+    type analysis)+  * Parser & lexer tweaks+    * Fortran 77 parser should no longer attempt to parse kind selectors for+      `DOUBLE` types+    * Fix an edge case with the fixed form lexer (#150)+ ### 0.4.3 (May 25, 2021)    * Add Haddock documentation to AST module. Many parts of the AST now have
fortran-src.cabal view
@@ -1,13 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.33.0.+-- This file has been generated from package.yaml by hpack version 0.34.4. -- -- see: https://github.com/sol/hpack------ hash: f5d7e99716015530592de9c1b2546f0d2ad31a230d0574adb8385118e8bdba1f  name:           fortran-src-version:        0.4.3+version:        0.5.0 synopsis:       Parsers and analyses for Fortran standards 66, 77, 90 and 95. description:    Provides lexing, parsing, and basic analyses of Fortran code covering standards: FORTRAN 66, FORTRAN 77, Fortran 90, and Fortran 95 and some legacy extensions. Includes data flow and basic block analysis, a renamer, and type analysis. For example usage, see the 'camfort' project, which uses fortran-src as its front end. category:       Language@@ -28,6 +26,7 @@  library   exposed-modules:+      Language.Fortran.Analysis.SemanticTypes       Language.Fortran.Analysis       Language.Fortran.Analysis.Renaming       Language.Fortran.Analysis.ModGraph@@ -70,15 +69,15 @@     , happy >=1.19   build-depends:       GenericPretty >=1.2.2 && <2-    , array >=0.5 && <0.6+    , array ==0.5.*     , base >=4.6 && <5     , binary >=0.8.3.0 && <0.11     , bytestring >=0.10 && <0.12     , containers >=0.5 && <0.7-    , deepseq >=1.4 && <1.5+    , deepseq ==1.4.*     , directory >=1.2 && <2-    , fgl >=5 && <6-    , filepath >=1.4 && <1.5+    , fgl ==5.*+    , filepath ==1.4.*     , mtl >=2.2 && <3     , pretty >=1.1 && <2     , temporary >=1.2 && <1.4@@ -93,15 +92,15 @@   ghc-options: -Wall -fno-warn-tabs   build-depends:       GenericPretty >=1.2.2 && <2-    , array >=0.5 && <0.6+    , array ==0.5.*     , base >=4.6 && <5     , binary >=0.8.3.0 && <0.11     , bytestring >=0.10 && <0.12     , containers >=0.5 && <0.7-    , deepseq >=1.4 && <1.5+    , deepseq ==1.4.*     , directory >=1.2 && <2-    , fgl >=5 && <6-    , filepath >=1.4 && <1.5+    , fgl ==5.*+    , filepath ==1.4.*     , fortran-src     , mtl >=2.2 && <3     , pretty >=1.1 && <2@@ -117,6 +116,7 @@       Language.Fortran.Analysis.BBlocksSpec       Language.Fortran.Analysis.DataFlowSpec       Language.Fortran.Analysis.RenamingSpec+      Language.Fortran.Analysis.SemanticTypesSpec       Language.Fortran.Analysis.TypesSpec       Language.Fortran.AnalysisSpec       Language.Fortran.Lexer.FixedFormSpec@@ -146,15 +146,15 @@       hspec-discover:hspec-discover   build-depends:       GenericPretty >=1.2.2 && <2-    , array >=0.5 && <0.6+    , array ==0.5.*     , base >=4.6 && <5     , binary >=0.8.3.0 && <0.11     , bytestring >=0.10 && <0.12     , containers >=0.5 && <0.7-    , deepseq >=1.4 && <1.5+    , deepseq ==1.4.*     , directory >=1.2 && <2-    , fgl >=5 && <6-    , filepath >=1.4 && <1.5+    , fgl ==5.*+    , filepath ==1.4.*     , fortran-src     , hspec >=2.2 && <3     , mtl >=2.2 && <3
src/Language/Fortran/AST.hs view
@@ -6,6 +6,8 @@ {-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE FlexibleContexts #-} +-- |+-- -- This module holds the data types used to represent Fortran code of various -- versions. --@@ -25,8 +27,8 @@ -- (The Fortran 66 ANSI standard lacks detail, and isn't as useful as the later -- standards for implementing the language.) ----- /Some comments aren't reflected in the Haddock documentation, so you may also--- wish to view this file's source./+-- /Note:/ some comments aren't reflected in the Haddock documentation, so you+-- may also wish to view this file's source.  module Language.Fortran.AST   (@@ -45,7 +47,6 @@   -- ** Types and declarations   , Name   , BaseType(..)-  , CharacterLen(..)   , TypeSpec(..)   , Declarator(..)   , Selector(..)@@ -84,6 +85,7 @@   , FlushSpec(..)   , DoSpecification(..)   , ProgramUnitName(..)+  , Kind    -- * Node annotations & related typeclasses   , A0@@ -93,7 +95,6 @@   , Named(..)    -- * Helpers-  , charLenSelector   , validPrefixSuffix   , emptyPrefixes   , emptySuffixes@@ -156,7 +157,7 @@   | TypeComplex   | TypeDoubleComplex   | TypeLogical-  | TypeCharacter (Maybe CharacterLen) (Maybe String) -- ^ len and kind, if specified+  | TypeCharacter   | TypeCustom String   | ClassStar   | ClassCustom String@@ -165,29 +166,6 @@  instance Binary BaseType -data CharacterLen = CharLenStar    -- ^ specified with a *-                  | CharLenColon   -- ^ specified with a : (Fortran2003)-                    -- FIXME, possibly, with a more robust const-exp:-                  | CharLenExp     -- ^ specified with a non-trivial expression-                  | CharLenInt Int -- ^ specified with a constant integer-  deriving (Ord, Eq, Show, Data, Typeable, Generic)--instance Binary CharacterLen--charLenSelector :: Maybe (Selector a) -> (Maybe CharacterLen, Maybe String)-charLenSelector Nothing                          = (Nothing, Nothing)-charLenSelector (Just (Selector _ _ mlen mkind)) = (l, k)-  where-    l | Just (ExpValue _ _ ValStar) <- mlen        = Just CharLenStar-      | Just (ExpValue _ _ ValColon) <- mlen       = Just CharLenColon-      | Just (ExpValue _ _ (ValInteger i)) <- mlen = Just $ CharLenInt (read i)-      | Nothing <- mlen                            = Nothing-      | otherwise                                  = Just CharLenExp-    k | Just (ExpValue _ _ (ValInteger i)) <- mkind  = Just i-      | Just (ExpValue _ _ (ValVariable s)) <- mkind = Just s-      -- FIXME: some references refer to things like kind=kanji but I can't find any spec for it-      | otherwise                                    = Nothing- -- | The type specification of a declaration statement, containing the syntactic --   type name and kind selector. --@@ -211,6 +189,8 @@   Selector a SrcSpan (Maybe (Expression a)) (Maybe (Expression a))   deriving (Eq, Show, Data, Typeable, Generic, Functor) +type Kind = Int+ data MetaInfo = MetaInfo { miVersion :: FortranVersion, miFilename :: String }   deriving (Eq, Show, Data, Typeable, Generic) @@ -968,7 +948,6 @@ instance Out a => Out (Value a) instance Out a => Out (TypeSpec a) instance Out a => Out (Selector a)-instance Out CharacterLen instance Out BaseType instance Out a => Out (Declarator a) instance Out a => Out (DimensionDeclarator a)@@ -1064,7 +1043,6 @@ instance NFData a => NFData (StructureItem a) instance NFData a => NFData (UnionMap a) instance NFData MetaInfo-instance NFData CharacterLen instance NFData BaseType instance NFData UnaryOp instance NFData BinaryOp
src/Language/Fortran/Analysis.hs view
@@ -7,7 +7,7 @@   ( initAnalysis, stripAnalysis, Analysis(..), Constant(..)   , varName, srcName, lvVarName, lvSrcName, isNamedExpression   , genVar, puName, puSrcName, blockRhsExprs, rhsExprs-  , ModEnv, NameType(..), IDType(..), ConstructType(..), BaseType(..)+  , ModEnv, NameType(..), IDType(..), ConstructType(..)   , lhsExprs, isLExpr, allVars, analyseAllLhsVars, analyseAllLhsVars1, allLhsVars   , blockVarUses, blockVarDefs   , BB, BBNode, BBGr(..), bbgrMap, bbgrMapM, bbgrEmpty@@ -30,6 +30,8 @@ import Language.Fortran.Intrinsics (getIntrinsicDefsUses, allIntrinsics) import Data.Bifunctor (first) +import           Language.Fortran.Analysis.SemanticTypes (SemType(..))+ --------------------------------------------------  -- | Basic block@@ -97,7 +99,7 @@ instance Binary ConstructType  data IDType = IDType-  { idVType :: Maybe BaseType+  { idVType :: Maybe SemType   , idCType :: Maybe ConstructType }   deriving (Ord, Eq, Show, Data, Typeable, Generic) @@ -169,7 +171,7 @@ isNamedExpression _                               = False  -- | Obtain either uniqueName or source name from an ExpValue variable.-varName :: Expression (Analysis a) -> String+varName :: Expression (Analysis a) -> Name varName (ExpValue Analysis { uniqueName = Just n } _ ValVariable{})  = n varName (ExpValue Analysis { sourceName = Just n } _ ValVariable{})  = n varName (ExpValue _ _ (ValVariable n))                               = n@@ -179,7 +181,7 @@ varName _                                                            = error "Use of varName on non-variable."  -- | Obtain the source name from an ExpValue variable.-srcName :: Expression (Analysis a) -> String+srcName :: Expression (Analysis a) -> Name srcName (ExpValue Analysis { sourceName = Just n } _ ValVariable{})  = n srcName (ExpValue _ _ (ValVariable n))                               = n srcName (ExpValue Analysis { sourceName = Just n } _ ValIntrinsic{}) = n@@ -187,20 +189,20 @@ srcName _                                                            = error "Use of srcName on non-variable."  -- | Obtain either uniqueName or source name from an LvSimpleVar variable.-lvVarName :: LValue (Analysis a) -> String+lvVarName :: LValue (Analysis a) -> Name lvVarName (LvSimpleVar Analysis { uniqueName = Just n } _ _)  = n lvVarName (LvSimpleVar Analysis { sourceName = Just n } _ _)  = n lvVarName (LvSimpleVar _ _ n)                                 = n lvVarName _                                                   = error "Use of lvVarName on non-variable."  -- | Obtain the source name from an LvSimpleVar variable.-lvSrcName :: LValue (Analysis a) -> String+lvSrcName :: LValue (Analysis a) -> Name lvSrcName (LvSimpleVar Analysis { sourceName = Just n } _ _) = n lvSrcName (LvSimpleVar _ _ n) = n lvSrcName _ = error "Use of lvSrcName on a non-variable"  -- | Generate an ExpValue variable with its source name == to its uniqueName.-genVar :: Analysis a -> SrcSpan -> String -> Expression (Analysis a)+genVar :: Analysis a -> SrcSpan -> Name -> Expression (Analysis a) genVar a s n = ExpValue (a { uniqueName = Just n, sourceName = Just n }) s v   where     v | Just CTIntrinsic <- idCType =<< idType a = ValIntrinsic n
src/Language/Fortran/Analysis/BBlocks.hs view
@@ -884,21 +884,11 @@ showBaseType TypeComplex         = "complex" showBaseType TypeDoubleComplex   = "doublecomplex" showBaseType TypeLogical         = "logical"-showBaseType (TypeCharacter l k) = case (l, k) of-  (Just cl, Just ki) -> "character(" ++ showCharLen cl ++ "," ++ ki ++ ")"-  (Just cl, Nothing) -> "character(" ++ showCharLen cl ++ ")"-  (Nothing, Just ki) -> "character(kind=" ++ ki ++ ")"-  (Nothing, Nothing) -> "character"+showBaseType TypeCharacter       = "character" showBaseType (TypeCustom s)      = "type(" ++ s ++ ")" showBaseType TypeByte            = "byte" showBaseType ClassStar           = "class(*)" showBaseType (ClassCustom s)     = "class(" ++ s ++ ")"--showCharLen :: CharacterLen -> String-showCharLen CharLenStar = "*"-showCharLen CharLenColon = ":"-showCharLen CharLenExp  = "*" -- FIXME, possibly, with a more robust const-exp-showCharLen (CharLenInt i) = show i  showDecl :: Declarator a -> String showDecl (DeclArray _ _ e adims length' initial) =
+ src/Language/Fortran/Analysis/SemanticTypes.hs view
@@ -0,0 +1,239 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Language.Fortran.Analysis.SemanticTypes where++import           Data.Data                      ( Data, Typeable )+import           Control.DeepSeq                ( NFData )+import           GHC.Generics                   ( Generic )+import           Language.Fortran.AST           ( BaseType(..)+                                                , Kind+                                                , Expression(..)+                                                , Value(..)+                                                , TypeSpec(..)+                                                , Selector(..) )+import           Language.Fortran.Util.Position ( SrcSpan(..) )+import           Language.Fortran.Version       ( FortranVersion(..) )+import           Data.Binary                    ( Binary )+import           Text.PrettyPrint.GenericPretty ( Out(..) )+import           Text.PrettyPrint               ( (<+>), parens )+import           Language.Fortran.PrettyPrint   ( Pretty(..) )++-- | Semantic type assigned to variables.+--+-- 'BaseType' stores the "type tag" given in syntax. 'SemType's add metadata+-- (kind and length), and resolve some "simple" types to a core type with a+-- preset kind (e.g. `DOUBLE PRECISION` -> `REAL(8)`).+--+-- Fortran 90 (and beyond) features may not be well supported.+data SemType+  = TInteger Kind+  | TReal Kind+  | TComplex Kind+  | TLogical Kind+  | TByte Kind+  | TCharacter CharacterLen Kind+  | TArray SemType (Maybe Dimensions) -- ^ Nothing denotes dynamic dimensions+  | TCustom String                    -- use for F77 structures, F90 DDTs+  deriving (Eq, Ord, Show, Data, Typeable, Generic)++instance Binary SemType+instance Out    SemType++-- TODO placeholder, not final or tested+-- should really attempt to print with kind info, and change to DOUBLE PRECISION+-- etc. for <F90. Maybe cheat, use 'recoverSemTypeTypeSpec' and print resulting+-- TypeSpec?+instance Pretty SemType where+  pprint' v = \case+    TInteger k -> "integer"+    TReal k    -> "real"+    TComplex k -> "complex"+    TLogical k -> "logical"+    TByte k    -> "byte"+    TCharacter len k -> "character"+    TArray st dims -> pprint' v st <+> parens "(A)"+    TCustom str -> pprint' v (TypeCustom str)++-- | 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)]++--------------------------------------------------------------------------------++data CharacterLen = CharLenStar    -- ^ specified with a *+                  | CharLenColon   -- ^ specified with a : (Fortran2003)+                    -- FIXME, possibly, with a more robust const-exp:+                  | CharLenExp     -- ^ specified with a non-trivial expression+                  | CharLenInt Int -- ^ specified with a constant integer+  deriving (Ord, Eq, Show, Data, Typeable, Generic)++instance Binary CharacterLen+instance Out    CharacterLen+instance NFData CharacterLen++charLenSelector :: Maybe (Selector a) -> (Maybe CharacterLen, Maybe String)+charLenSelector Nothing                          = (Nothing, Nothing)+charLenSelector (Just (Selector _ _ mlen mkind)) = (l, k)+  where+    l = charLenSelector' <$> mlen+    k | Just (ExpValue _ _ (ValInteger i)) <- mkind  = Just i+      | Just (ExpValue _ _ (ValVariable s)) <- mkind = Just s+      -- FIXME: some references refer to things like kind=kanji but I can't find any spec for it+      | otherwise                                    = Nothing++charLenSelector' :: Expression a -> CharacterLen+charLenSelector' = \case+  ExpValue _ _ ValStar        -> CharLenStar+  ExpValue _ _ ValColon       -> CharLenColon+  ExpValue _ _ (ValInteger i) -> CharLenInt (read i)+  _                           -> CharLenExp++-- | Attempt to recover the 'Value' that generated the given 'CharacterLen'.+charLenToValue :: CharacterLen -> Maybe (Value a)+charLenToValue = \case+  CharLenStar  -> Just ValStar+  CharLenColon -> Just ValColon+  CharLenInt i -> Just (ValInteger (show i))+  CharLenExp   -> Nothing++getTypeKind :: SemType -> Kind+getTypeKind = \case+  TInteger   k -> k+  TReal      k -> k+  TComplex   k -> k+  TLogical   k -> k+  TByte      k -> k+  TCharacter _ k -> k+  TCustom    _ -> error "TCustom does not have a kind"+  TArray t _   -> getTypeKind t++setTypeKind :: SemType -> Kind -> SemType+setTypeKind st k = case st of+  TInteger   _ -> TInteger   k+  TReal      _ -> TReal      k+  TComplex   _ -> TComplex   k+  TLogical   _ -> TLogical   k+  TByte      _ -> TByte      k+  TCharacter charLen _ -> TCharacter charLen k+  TCustom    _ -> error "can't set kind of TCustom"+  TArray _ _   -> error "can't set kind of TArray"++charLenConcat :: CharacterLen -> CharacterLen -> CharacterLen+charLenConcat l1 l2 = case (l1, l2) of+  (CharLenExp    , _             ) -> CharLenExp+  (_             , CharLenExp    ) -> CharLenExp+  (CharLenStar   , _             ) -> CharLenStar+  (_             , CharLenStar   ) -> CharLenStar+  (CharLenColon  , _             ) -> CharLenColon+  (_             , CharLenColon  ) -> CharLenColon+  (CharLenInt i1 , CharLenInt i2 ) -> CharLenInt (i1 + i2)++-- | Recover the most appropriate 'TypeSpec' for the given 'SemType', depending+--   on the given 'FortranVersion'.+--+-- Kinds weren't formalized as a syntactic feature until Fortran 90, so we ask+-- for a context. If possible (>=F90), we prefer the more explicit+-- representation e.g. @REAL(8)@. For older versions, for specific type-kind+-- combinations, @DOUBLE PRECISION@ and @DOUBLE COMPLEX@ are used instead.+-- However, we otherwise don't shy away from adding kind info regardless of+-- theoretical version support.+--+-- Array types don't work properly, due to array type info being in a parent+-- node that holds individual elements.+recoverSemTypeTypeSpec :: forall a. a -> SrcSpan+                       -> FortranVersion -> SemType -> TypeSpec a+recoverSemTypeTypeSpec a ss v = \case+  TInteger k -> wrapBaseAndKind TypeInteger k+  TLogical k -> wrapBaseAndKind TypeLogical k+  TByte    k -> wrapBaseAndKind TypeByte k++  TCustom str -> ts (TypeCustom str) Nothing++  TArray     st  _   -> recoverSemTypeTypeSpec a ss v st++  TReal    k ->+      if k == 8 && v < Fortran90+    then ts TypeDoublePrecision Nothing+    else wrapBaseAndKind TypeReal k+  TComplex k ->+      if k == 16 && v < Fortran90+    then ts TypeDoubleComplex Nothing+    else wrapBaseAndKind TypeComplex k++  TCharacter len k   ->+    -- TODO can improve, use no selector if len=1, kind=1+    -- only include kind if != 1+    let sel = Selector a ss (ExpValue a ss <$> charLenToValue len) (if k == 1 then Nothing else Just (intValExpr k))+     in ts TypeCharacter (Just sel)++  where+    ts = TypeSpec a ss+    intValExpr :: Int -> Expression a+    intValExpr x = ExpValue a ss (ValInteger (show x))++    -- | Wraps 'BaseType' and 'Kind' into 'TypeSpec'. If the kind is the+    --   'BaseType''s default kind, it is omitted.+    wrapBaseAndKind :: BaseType -> Kind -> TypeSpec a+    wrapBaseAndKind bt k = ts bt sel+      where+        sel =   if k == kindOfBaseType bt+              then Nothing+              else Just $ Selector a ss Nothing (Just (intValExpr k))++--------------------------------------------------------------------------------++-- | Given a 'BaseType' infer the "default" kind (or size of the+-- variable in memory).+--+-- Useful when you need a default kind, but gives you an unwrapped type.+-- Consider using Analysis.deriveSemTypeFromBaseType also.+--+-- Further documentation:+-- https://docs.oracle.com/cd/E19957-01/805-4939/c400041360f5/index.html+kindOfBaseType :: BaseType -> Int+kindOfBaseType = \case+  TypeInteger         -> 4+  TypeReal            -> 4+  TypeDoublePrecision -> 8+  TypeComplex         -> 8+  TypeDoubleComplex   -> 16+  TypeLogical         -> 4+  TypeCharacter{}     -> 1+  TypeByte            -> 1++  -- arbitrary values (>F77 is not tested/used)+  TypeCustom{}        -> 1+  ClassStar           -> 1+  ClassCustom{}       -> 1++getTypeSize :: SemType -> Maybe Int+getTypeSize = \case+  TInteger      k   -> Just k+  TReal         k   -> Just k+  TComplex      k   -> Just k+  TLogical      k   -> Just k+  TByte         k   -> Just k+  TArray     ty _   -> getTypeSize ty+  TCustom       _   -> Just 1+  -- char: treat length as "kind" (but also use recorded kind)+  TCharacter (CharLenInt l) k -> Just (l * k)+  TCharacter _              _ -> Nothing++setTypeSize :: SemType -> Maybe Int -> SemType+setTypeSize ty mk = case (mk, ty) of+  (Just k, TInteger _  ) -> TInteger k+  (Just k, TReal _     ) -> TReal k+  (Just k, TComplex _  ) -> TComplex k+  (Just k, TLogical _  ) -> TLogical k+  (Just k, TByte _     ) -> TByte k+  (_     , TCustom s   ) -> TCustom s+  -- char: treat length as "kind"+  (Just l, TCharacter _ k) ->+    TCharacter (CharLenInt l) k+  (Nothing, TCharacter _ k) ->+    TCharacter CharLenStar k+  _ -> error $ "Tried to set invalid kind for type " <> show ty
src/Language/Fortran/Analysis/Types.hs view
@@ -1,7 +1,19 @@ {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE LambdaCase          #-}+ module Language.Fortran.Analysis.Types-  ( analyseTypes, analyseTypesWithEnv, analyseAndCheckTypesWithEnv, extractTypeEnv, TypeEnv, TypeError )-where+  ( analyseTypes+  , analyseTypesWithEnv+  , analyseAndCheckTypesWithEnv+  , extractTypeEnv+  , TypeEnv+  , TypeError+  , deriveSemTypeFromDeclaration+  , deriveSemTypeFromTypeSpec+  , deriveSemTypeFromBaseType+  , runInfer+  , inferState0+  ) where  import Language.Fortran.AST @@ -15,10 +27,11 @@ import Data.Data import Data.Functor.Identity (Identity ()) import Language.Fortran.Analysis+import Language.Fortran.Analysis.SemanticTypes import Language.Fortran.Intrinsics import Language.Fortran.Util.Position-import Language.Fortran.ParserMonad (FortranVersion(..))-+import Language.Fortran.Version (FortranVersion(..))+import Language.Fortran.Parser.Utils  -------------------------------------------------- @@ -77,7 +90,7 @@    -- Gather types for known entry points.   eps <- gets (M.toList . entryPoints)-  _ <- forM eps $ \ (eName, (fName, mRetName)) -> do+  forM_ eps $ \ (eName, (fName, mRetName)) -> do     mFType <- getRecordedType fName     case mFType of       Just (IDType fVType fCType) -> do@@ -125,8 +138,12 @@     -- record some type information that we can glean     recordCType CTFunction n     case (mRetType, mRetVar) of-      (Just (TypeSpec _ _ baseType _), Just v) -> recordBaseType baseType n >> recordBaseType baseType (varName v)-      (Just (TypeSpec _ _ baseType _), _)      -> recordBaseType baseType n+      (Just ts@(TypeSpec _ _ _ _), Just v) -> do+        semType <- deriveSemTypeFromTypeSpec ts+        recordSemType semType n >> recordSemType semType (varName v)+      (Just ts@(TypeSpec _ _ _ _), _)      -> do+        semType <- deriveSemTypeFromTypeSpec ts+        recordSemType semType n       _                                        -> return ()     -- record entry points for later annotation     forM_ blocks $ \ block ->@@ -151,8 +168,8 @@                                                  return $ read i ]  statement :: Data a => InferFunc (Statement (Analysis a))--- maybe FIXME: should Kind Selectors be part of types?-statement (StDeclaration _ _ (TypeSpec _ _ baseType _) mAttrAList declAList)++statement (StDeclaration _ stmtSs ts@(TypeSpec _ _ _ _) mAttrAList declAList)   | mAttrs  <- maybe [] aStrip mAttrAList   , attrDim <- find isAttrDimension mAttrs   , isParam <- any isAttrParameter mAttrs@@ -165,16 +182,14 @@                 | Just (IDType _ (Just ct)) <- M.lookup n env                 , ct /= CTIntrinsic                           = ct                 | otherwise                                   = CTVariable-    let charLen (ExpValue _ _ (ValInteger i)) = CharLenInt (read i)-        charLen (ExpValue _ _ ValStar)        = CharLenStar-        charLen _                             = CharLenExp-    let bType (Just e)-          | TypeCharacter _ kind <- baseType = TypeCharacter (Just $ charLen e) kind-          | otherwise                        = TypeCharacter (Just $ charLen e) Nothing-        bType Nothing  = baseType     forM_ decls $ \ decl -> case decl of-      DeclArray _ _ v ddAList e _ -> recordType (bType e) (CTArray $ dimDeclarator ddAList) (varName v)-      DeclVariable _ _ v e _      -> recordType (bType e) (cType n) n where n = varName v+        DeclArray _ declSs v ddAList mLenExpr _ -> do+            let ct = CTArray $ dimDeclarator ddAList+            st <- deriveSemTypeFromDeclaration stmtSs declSs ts mLenExpr+            recordType st ct (varName v)+        DeclVariable _ declSs v mLenExpr _      -> do+            st <- deriveSemTypeFromDeclaration stmtSs declSs ts mLenExpr+            recordType st (cType n) n where n = varName v  statement (StExternal _ _ varAList) = do   let vars = aStrip varAList@@ -204,12 +219,23 @@ statement _ = return ()  annotateExpression :: Data a => Expression (Analysis a) -> Infer (Expression (Analysis a))++-- handle the various literals annotateExpression e@(ExpValue _ _ (ValVariable _))    = maybe e (`setIDType` e) `fmap` getRecordedType (varName e) annotateExpression e@(ExpValue _ _ (ValIntrinsic _))   = maybe e (`setIDType` e) `fmap` getRecordedType (varName e)-annotateExpression e@(ExpValue _ _ (ValReal r))        = return $ realLiteralType r `setIDType` e-annotateExpression e@(ExpValue _ _ (ValComplex e1 e2)) = return $ complexLiteralType e1 e2 `setIDType` e-annotateExpression e@(ExpValue _ _ (ValInteger _))     = return $ IDType (Just TypeInteger) Nothing `setIDType` e-annotateExpression e@(ExpValue _ _ (ValLogical _))     = return $ IDType (Just TypeLogical) Nothing `setIDType` e+annotateExpression e@(ExpValue _ ss (ValReal r))        = do+    k <- deriveRealLiteralKind ss r+    return $ setSemType (TReal k) e+annotateExpression e@(ExpValue _ ss (ValComplex e1 e2)) = do+    st <- complexLiteralType ss e1 e2+    return $ setSemType st e+annotateExpression e@(ExpValue _ _ (ValInteger _))     =+    -- FIXME: in >F90, int lits can have kind info on end @_8@, same as real+    -- lits. We do parse this into the lit string, it is available to us.+    return $ setSemType (deriveSemTypeFromBaseType TypeInteger) e+annotateExpression e@(ExpValue _ _ (ValLogical _))     =+    return $ setSemType (deriveSemTypeFromBaseType TypeLogical) e+ annotateExpression e@(ExpBinary _ _ op e1 e2)          = flip setIDType e `fmap` binaryOpType (getSpan e) op e1 e2 annotateExpression e@(ExpUnary _ _ op e1)              = flip setIDType e `fmap` unaryOpType (getSpan e1) op e1 annotateExpression e@(ExpSubscript _ _ e1 idxAList)    = flip setIDType e `fmap` subscriptType (getSpan e) e1 idxAList@@ -220,80 +246,118 @@ annotateProgramUnit pu | Named n <- puName pu = maybe pu (`setIDType` pu) `fmap` getRecordedType n annotateProgramUnit pu                        = return pu -realLiteralType :: String -> IDType-realLiteralType r | 'd' `elem` r = IDType (Just TypeDoublePrecision) Nothing-                  | otherwise    = IDType (Just TypeReal) Nothing+-- | Derive the kind of a REAL literal constant.+--+-- Logic taken from HP's F90 reference pg.33, written to gfortran's behaviour.+-- Stays in the 'Infer' monad so it can report type errors+deriveRealLiteralKind :: SrcSpan -> String -> Infer Kind+deriveRealLiteralKind ss r =+    case realLitKindParam realLit of+      Nothing -> return kindFromExpOrDefault+      Just k  ->+        case realLitExponent realLit of+          Nothing  -> return k  -- no exponent, use kind param+          Just expo ->+            -- can only use kind param with 'e' or no exponent+            case expLetter expo of+              ExpLetterE -> return k+              _          -> do+                -- badly formed literal, but we'll allow and use the provided+                -- kind param (with no doubling or anything)+                typeError "only real literals with exponent letter 'e' can specify explicit kind parameter" ss+                return k+  where+    realLit = parseRealLiteral r+    kindFromExpOrDefault =+        case realLitExponent realLit of+          -- no exponent: select default real kind+          Nothing             -> 4+          Just expo           ->+            case expLetter expo of+              ExpLetterE -> 4+              ExpLetterD -> 8 -complexLiteralType :: Expression a -> Expression a -> IDType-complexLiteralType (ExpValue _ _ (ValReal r)) _- | IDType (Just TypeDoublePrecision) _ <- realLiteralType r = IDType (Just TypeDoubleComplex) Nothing- | otherwise                                                = IDType (Just TypeComplex) Nothing-complexLiteralType _ _ = IDType (Just TypeComplex) Nothing+-- | Get the type of a COMPLEX literal constant.+--+-- The kind is derived only from the first expression, the second is ignored.+complexLiteralType :: SrcSpan -> Expression a -> Expression a -> Infer SemType+complexLiteralType ss (ExpValue _ _ (ValReal r)) _ = do+    k1 <- deriveRealLiteralKind ss r+    return $ TComplex k1+complexLiteralType _ _ _ = return $ deriveSemTypeFromBaseType TypeComplex  binaryOpType :: Data a => SrcSpan -> BinaryOp -> Expression (Analysis a) -> Expression (Analysis a) -> Infer IDType binaryOpType ss op e1 e2 = do-  mbt1 <- case getIDType e1 of-            Just (IDType (Just bt) _) -> return $ Just bt+  mst1 <- case getIDType e1 of+            Just (IDType (Just st) _) -> return $ Just st             _ -> typeError "Unable to obtain type for first operand" (getSpan e1) >> return Nothing-  mbt2 <- case getIDType e2 of-            Just (IDType (Just bt) _) -> return $ Just bt+  mst2 <- case getIDType e2 of+            Just (IDType (Just st) _) -> return $ Just st             _ -> typeError "Unable to obtain type for second operand" (getSpan e2) >> return Nothing-  case (mbt1, mbt2) of+  case (mst1, mst2) of     (_, Nothing) -> return emptyType     (Nothing, _) -> return emptyType-    (Just bt1, Just bt2) -> do-      mbt <- case (bt1, bt2) of-        (_                   , TypeDoubleComplex   ) -> return . Just $ TypeDoubleComplex-        (TypeDoubleComplex   , _                   ) -> return . Just $ TypeDoubleComplex-        (_                   , TypeComplex         ) -> return . Just $ TypeComplex-        (TypeComplex         , _                   ) -> return . Just $ TypeComplex-        (_                   , TypeDoublePrecision ) -> return . Just $ TypeDoublePrecision-        (TypeDoublePrecision , _                   ) -> return . Just $ TypeDoublePrecision-        (_                   , TypeReal            ) -> return . Just $ TypeReal-        (TypeReal            , _                   ) -> return . Just $ TypeReal-        (_                   , TypeInteger         ) -> return . Just $ TypeInteger-        (TypeInteger         , _                   ) -> return . Just $ TypeInteger-        (TypeByte            , TypeByte            ) -> return . Just $ TypeByte-        (TypeLogical         , TypeLogical         ) -> return . Just $ TypeLogical-        (TypeCustom _        , TypeCustom _        ) -> do-          typeError "custom types / binary op not supported" ss-          return Nothing-        (TypeCharacter l1 k1 , TypeCharacter l2 _ )-          | op == Concatenation -> return . Just $ TypeCharacter (liftM2 charLenConcat l1 l2) k1-          | op `elem` [EQ, NE]  -> return $ Just TypeLogical-          | otherwise -> do typeError "Invalid op on character strings" ss-                            return Nothing-        _ -> do typeError "Type error between operands of binary operator" ss-                return Nothing-      mbt' <- case mbt of-        Just bt+    (Just st1, Just st2) -> do+      mst  <- binopSimpleCombineSemTypes ss op st1 st2+      mst' <- case mst of+        Just st           | op `elem` [ Addition, Subtraction, Multiplication, Division-                      , Exponentiation, Concatenation, Or, XOr, And ]       -> return $ Just bt-          | op `elem` [GT, GTE, LT, LTE, EQ, NE, Equivalent, NotEquivalent] -> return $ Just TypeLogical+                      , Exponentiation, Concatenation, Or, XOr, And ]       -> return $ Just st+          | op `elem` [GT, GTE, LT, LTE, EQ, NE, Equivalent, NotEquivalent] -> return $ Just (deriveSemTypeFromBaseType TypeLogical)           | BinCustom{} <- op -> typeError "custom binary ops not supported" ss >> return Nothing         _ -> return Nothing -      return $ IDType mbt' Nothing+      return $ IDType mst' Nothing -- FIXME: might have to check kinds of each operand +-- | Combine two 'SemType's with a 'BinaryOp'.+--+-- No real work done here, no kind combining, just selection.+binopSimpleCombineSemTypes :: SrcSpan -> BinaryOp -> SemType -> SemType -> Infer (Maybe SemType)+binopSimpleCombineSemTypes ss op st1 st2 = do+    case (st1, st2) of+      (_           , TComplex k2) -> ret $ TComplex k2+      (TComplex k1, _           ) -> ret $ TComplex k1+      (_           , TReal    k2) -> ret $ TReal k2+      (TReal    k1, _           ) -> ret $ TReal k1+      (_           , TInteger k2) -> ret $ TInteger k2+      (TInteger k1, _           ) -> ret $ TInteger k1+      (TByte    k1, TByte     _ ) -> ret $ TByte k1+      (TLogical k1, TLogical  _ ) -> ret $ TLogical k1+      (TCustom  _, TCustom   _) -> do+        typeError "custom types / binary op not supported" ss+        return Nothing+      (TCharacter l1 k1, TCharacter l2 k2)+        | k1 /= k2 -> do typeError "operation on character strings of different kinds" ss+                         return Nothing+        | op == Concatenation -> ret $ TCharacter (charLenConcat l1 l2) k1+        | op `elem` [EQ, NE]  -> ret $ deriveSemTypeFromBaseType TypeLogical+        | otherwise -> do typeError "Invalid op on character strings" ss+                          return Nothing+      _ -> do typeError "Type error between operands of binary operator" ss+              return Nothing+  where+    ret = return . Just+ unaryOpType :: Data a => SrcSpan -> UnaryOp -> Expression (Analysis a) -> Infer IDType unaryOpType ss op e = do-  mbt <- case getIDType e of-           Just (IDType (Just bt) _) -> return $ Just bt+  mst <- case getIDType e of+           Just (IDType (Just st) _) -> return $ Just st            _ -> typeError "Unable to obtain type for" (getSpan e) >> return Nothing-  mbt' <- case (mbt, op) of+  mst' <- case (mst, op) of     (Nothing, _)               -> return Nothing-    (Just TypeCustom{}, _)     -> typeError "custom types / unary ops not supported" ss >> return Nothing+    (Just TCustom{}, _)        -> typeError "custom types / unary ops not supported" ss >> return Nothing     (_, UnCustom{})            -> typeError "custom unary ops not supported" ss >> return Nothing-    (Just TypeLogical, Not)    -> return $ Just TypeLogical-    (Just bt, _)+    (Just st@(TLogical _), Not)    -> return $ Just st+    (Just st, _)       | op `elem` [Plus, Minus] &&-        bt `elem` numericTypes -> return $ Just bt+        isNumericType st -> return $ Just st     _ -> typeError "Type error for unary operator" ss >> return Nothing-  return $ IDType mbt' Nothing+  return $ IDType mst' Nothing -- FIXME: might have to check kind of operand  subscriptType :: Data a => SrcSpan -> Expression (Analysis a) -> AList Index (Analysis a) -> Infer IDType subscriptType ss e1 (AList _ _ idxs) = do-  let isInteger ie | Just (IDType (Just TypeInteger) _) <- getIDType ie = True | otherwise = False+  let isInteger ie | Just (IDType (Just (TInteger _)) _) <- getIDType ie = True+                   | otherwise = False   forM_ idxs $ \ idx -> case idx of     IxSingle _ _ _ ie       | not (isInteger ie) -> typeError "Invalid or unknown type for index" (getSpan ie)@@ -303,11 +367,11 @@       | Just ie3 <- mie3, not (isInteger ie3) -> typeError "Invalid or unknown type for index" (getSpan ie3)     _ -> return ()   case getIDType e1 of-    Just ty@(IDType mbt (Just (CTArray dds))) -> do+    Just ty@(IDType mst (Just (CTArray dds))) -> do       when (length idxs /= length dds) $ typeError "Length of indices does not match rank of array." ss       let isSingle (IxSingle{}) = True; isSingle _ = False       if all isSingle idxs-        then return $ IDType mbt Nothing+        then return $ IDType mst Nothing         else return ty     _ -> return emptyType @@ -318,37 +382,36 @@   case mRetType of     Nothing -> return emptyType     Just retType -> do-      mbt <- case retType of-            ITReal      -> return $ Just TypeReal-            ITInteger   -> return $ Just TypeInteger-            ITComplex   -> return $ Just TypeComplex-            ITDouble    -> return $ Just TypeDoublePrecision-            ITLogical   -> return $ Just TypeLogical-            ITCharacter -> return . Just $ TypeCharacter Nothing Nothing+      mst <- case retType of+            ITReal      -> wrapBaseType TypeReal+            ITInteger   -> wrapBaseType TypeInteger+            ITComplex   -> wrapBaseType TypeComplex+            ITDouble    -> wrapBaseType TypeDoublePrecision+            ITLogical   -> wrapBaseType TypeLogical+            ITCharacter -> wrapBaseType TypeCharacter             ITParam i               | length params >= i, Argument _ _ _ e <- params !! (i-1)                 -> return $ idVType =<< getIDType e               | otherwise -> typeError ("Invalid parameter list to intrinsic '" ++ n ++ "'") ss >> return Nothing-      case mbt of+      case mst of         Nothing -> return emptyType-        Just _ -> return $ IDType mbt Nothing+        Just _ -> return $ IDType mst Nothing+  where+    wrapBaseType :: Monad m => BaseType -> m (Maybe SemType)+    wrapBaseType = return . Just . deriveSemTypeFromBaseType+ functionCallType ss e1 _ = case getIDType e1 of-  Just (IDType (Just bt) (Just CTFunction)) -> return $ IDType (Just bt) Nothing-  Just (IDType (Just bt) (Just CTExternal)) -> return $ IDType (Just bt) Nothing+  Just (IDType (Just st) (Just CTFunction)) -> return $ IDType (Just st) Nothing+  Just (IDType (Just st) (Just CTExternal)) -> return $ IDType (Just st) Nothing   _ -> typeError "non-function invoked by call" ss >> return emptyType -charLenConcat :: CharacterLen -> CharacterLen -> CharacterLen-charLenConcat l1 l2 = case (l1, l2) of-  (CharLenExp    , _             ) -> CharLenExp-  (_             , CharLenExp    ) -> CharLenExp-  (CharLenStar   , _             ) -> CharLenStar-  (_             , CharLenStar   ) -> CharLenStar-  (CharLenColon  , _             ) -> CharLenColon-  (_             , CharLenColon  ) -> CharLenColon-  (CharLenInt i1 , CharLenInt i2 ) -> CharLenInt (i1 + i2)--numericTypes :: [BaseType]-numericTypes = [TypeDoubleComplex, TypeComplex, TypeDoublePrecision, TypeReal, TypeInteger, TypeByte]+isNumericType :: SemType -> Bool+isNumericType = \case+  TComplex{} -> True+  TReal{}    -> True+  TInteger{} -> True+  TByte{}    -> True+  _            -> False  -------------------------------------------------- -- Monadic helper combinators.@@ -366,22 +429,22 @@ emptyType = IDType Nothing Nothing  -- Record the type of the given name.-recordType :: BaseType -> ConstructType -> Name -> Infer ()-recordType bt ct n = modify $ \ s -> s { environ = insert n (IDType (Just bt) (Just ct)) (environ s) }+recordType :: SemType -> ConstructType -> Name -> Infer ()+recordType st ct n = modify $ \ s -> s { environ = insert n (IDType (Just st) (Just ct)) (environ s) }  -- Record the type (maybe) of the given name.-recordMType :: Maybe BaseType -> Maybe ConstructType -> Name -> Infer ()-recordMType bt ct n = modify $ \ s -> s { environ = insert n (IDType bt ct) (environ s) }+recordMType :: Maybe SemType -> Maybe ConstructType -> Name -> Infer ()+recordMType st ct n = modify $ \ s -> s { environ = insert n (IDType st ct) (environ s) }  -- Record the CType of the given name. recordCType :: ConstructType -> Name -> Infer () recordCType ct n = modify $ \ s -> s { environ = M.alter changeFunc n (environ s) }   where changeFunc mIDType = Just (IDType (mIDType >>= idVType) (Just ct)) --- Record the BaseType of the given name.-recordBaseType :: BaseType -> Name -> Infer ()-recordBaseType bt n = modify $ \ s -> s { environ = M.alter changeFunc n (environ s) }-  where changeFunc mIDType = Just (IDType (Just bt) (mIDType >>= idCType))+-- Record the SemType of the given name.+recordSemType :: SemType -> Name -> Infer ()+recordSemType st n = modify $ \ s -> s { environ = M.alter changeFunc n (environ s) }+  where changeFunc mIDType = Just (IDType (Just st) (mIDType >>= idCType))  recordEntryPoint :: Name -> Name -> Maybe Name -> Infer () recordEntryPoint fn en mRetName = modify $ \ s -> s { entryPoints = M.insert en (fn, mRetName) (entryPoints s) }@@ -393,12 +456,25 @@ setIDType :: Annotated f => IDType -> f (Analysis a) -> f (Analysis a) setIDType ty x   | a@Analysis {} <- getAnnotation x = setAnnotation (a { idType = Just ty }) x-  | otherwise                          = x+  | otherwise                        = x  -- Get the idType annotation getIDType :: (Annotated f, Data a) => f (Analysis a) -> Maybe IDType getIDType x = idType (getAnnotation x) +-- | For all types holding an 'IDType' (in an 'Analysis'), set the 'SemType'+--   field of the 'IDType'.+setSemType :: (Annotated f, Data a) => SemType -> f (Analysis a) -> f (Analysis a)+setSemType st x =+    let anno  = getAnnotation x+        idt   = idType anno+        anno' = anno { idType = Just (setIDTypeSemType idt) }+     in setAnnotation anno' x+  where+    setIDTypeSemType :: Maybe IDType -> IDType+    setIDTypeSemType (Just (IDType _ mCt)) = IDType (Just st) mCt+    setIDTypeSemType Nothing               = IDType (Just st) Nothing+ -- Set the CType part of idType annotation --setCType :: (Annotated f, Data a) => ConstructType -> f (Analysis a) -> f (Analysis a) --setCType ct x@@ -425,15 +501,161 @@  isAttrParameter :: Attribute a -> Bool isAttrParameter AttrParameter {} = True-isAttrParameter _                  = False+isAttrParameter _                = False  isAttrExternal :: Attribute a -> Bool isAttrExternal AttrExternal {} = True-isAttrExternal _                 = False+isAttrExternal _               = False  isIxSingle :: Index a -> Bool isIxSingle IxSingle {} = True-isIxSingle _             = False+isIxSingle _           = False++--------------------------------------------------++-- Most, but not all deriving functions can report type errors. So most of these+-- functions are in the Infer monad.++-- | Attempt to derive the 'SemType' of a variable from the relevant parts of+--   its surrounding 'StDeclaration'.+--+-- This is an example of a simple declaration:+--+--     INTEGER(8) :: var_name+--+-- A declaration holds a 'TypeSpec' (left of the double colon; LHS) and a list+-- of 'Declarator's (right of the double colon; RHS). However, CHARACTER+-- variable are allowed to specify their length via special syntax on the RHS:+--+--     CHARACTER :: string*10+--+-- so to handle that, this function takes that length as a Maybe Expression (as+-- provided in 'StDeclaration').+--+-- If a length was defined on both sides, the declaration length (RHS) is used.+-- This matches gfortran's behaviour, though even with -Wall they don't warn on+-- this rather confusing syntax usage. We report a (soft) type error.+deriveSemTypeFromDeclaration+    :: SrcSpan -> SrcSpan -> TypeSpec a -> Maybe (Expression a) -> Infer SemType+deriveSemTypeFromDeclaration stmtSs declSs ts@(TypeSpec _ _ bt mSel) mLenExpr =+    case mLenExpr of+      Nothing ->+        -- no RHS length, can continue with regular deriving+        deriveSemTypeFromTypeSpec ts++      Just lenExpr ->+        -- we got a RHS length; only CHARACTERs permit this+        case bt of+          TypeCharacter -> deriveCharWithLen lenExpr+          _ -> do+            -- can't use RHS @var*length = x@ syntax on non-CHARACTER: complain,+            -- continue regular deriving without length+            flip typeError declSs $+                "non-CHARACTER variable at declaration "+             <> show stmtSs+             <> " given a length"+            deriveSemTypeFromTypeSpec ts+  where+    -- Function called when we have a TypeCharacter and a RHS declarator length.+    -- (no function signature due to type variable scoping)+    --deriveCharWithLen :: Expression a -> Infer SemType+    deriveCharWithLen lenExpr =+        case mSel of+          Just (Selector selA selSs mSelLenExpr mKindExpr) -> do+            _ <- case mSelLenExpr of+                   Just _ -> do+                      -- both LHS & RHS lengths: surprising syntax, notify user+                      -- Ben has seen this IRL: a high-ranking Fortran+                      -- tutorial site uses it (2021-04-30):+                      -- http://web.archive.org/web/20210118202503/https://www.tutorialspoint.com/fortran/fortran_strings.htm+                     flip typeError declSs $+                         "warning: CHARACTER variable at declaration "+                      <> show stmtSs+                      <> " has length in LHS type spec and RHS declarator"+                      <> " -- specific RHS declarator overrides"+                   _ -> return ()+            -- overwrite the Selector with RHS length expr & continue+            let sel' = Selector selA selSs (Just lenExpr) mKindExpr+            deriveSemTypeFromBaseTypeAndSelector TypeCharacter sel'+          Nothing ->+            -- got RHS len, no Selector (e.g. @CHARACTER :: x*3 = "sup"@)+            -- naughty let binding to avoid re-hardcoding default char kind+            let (TCharacter _ k) = deriveSemTypeFromBaseType TypeCharacter+             in return $ TCharacter (charLenSelector' lenExpr) k++-- | Attempt to derive a 'SemType' from a 'TypeSpec'.+deriveSemTypeFromTypeSpec :: TypeSpec a -> Infer SemType+deriveSemTypeFromTypeSpec (TypeSpec _ _ bt mSel) =+    case mSel of+      -- Selector present: we might have kind/other info provided+      Just sel -> deriveSemTypeFromBaseTypeAndSelector bt sel+      -- no Selector: derive using default kinds etc.+      Nothing  -> return $ deriveSemTypeFromBaseType bt++-- | Attempt to derive a SemType from a 'BaseType' and a 'Selector'.+deriveSemTypeFromBaseTypeAndSelector :: BaseType -> Selector a -> Infer SemType+deriveSemTypeFromBaseTypeAndSelector bt (Selector _ ss mLen mKindExpr) = do+    st <- deriveFromBaseTypeAndKindExpr mKindExpr+    case mLen of+      Nothing      -> return st+      Just lenExpr ->+        case st of+          TCharacter _ kind ->+            let charLen = charLenSelector' lenExpr+             in return $ TCharacter charLen kind+          _ -> do+            -- (unreachable code path in correct parser operation)+            typeError "only CHARACTER types can specify length (separate to kind)" ss+            return st+  where+    deriveFromBaseTypeAndKindExpr :: Maybe (Expression a) -> Infer SemType+    deriveFromBaseTypeAndKindExpr = \case+      Nothing -> defaultSemType+      Just kindExpr ->+        case kindExpr of+          -- FIXME: only support integer kind selectors for now, no params/exprs+          -- (would require a wide change across codebase)+          ExpValue _ _ (ValInteger k) ->+            deriveSemTypeFromBaseTypeAndKind bt (read k)+          _ -> do+            typeError "unsupported or invalid kind selector, only literal integers allowed" (getSpan kindExpr)+            defaultSemType+    defaultSemType = return $ deriveSemTypeFromBaseType bt++-- | Derive 'SemType' directly from 'BaseType', using relevant default kinds.+deriveSemTypeFromBaseType :: BaseType -> SemType+deriveSemTypeFromBaseType = \case+  TypeInteger         -> TInteger 4+  TypeReal            -> TReal    4+  TypeComplex         -> TComplex 4+  TypeLogical         -> TLogical 4++  -- Fortran specs & compilers seem to agree on equating these intrinsic types+  -- to others with a larger kind, so we drop the extra syntactic info here.+  TypeDoublePrecision -> TReal    8+  TypeDoubleComplex   -> TComplex 8++  -- BYTE: HP's Fortran 90 reference says that BYTE is an HP extension, equates+  -- it to INTEGER(1), and indicates that it doesn't take a kind selector.+  -- Don't know how BYTEs are used in the wild. I wonder if we could safely+  -- equate BYTE to (TInteger 1)?+  TypeByte            -> TByte    noKind++  -- CHARACTERs default to len=1, kind=1 (non-1 is rare)+  TypeCharacter       -> TCharacter (CharLenInt 1) 1++  -- FIXME: this is where Fortran specs diverge, and fortran-vars doesn't+  -- support beyond F77e. Sticking with what passes the fortran-vars tests.+  ClassStar           -> TCustom "ClassStar"+  TypeCustom    str   -> TCustom str+  ClassCustom   str   -> TCustom str++noKind :: Kind+noKind = -1++deriveSemTypeFromBaseTypeAndKind :: BaseType -> Kind -> Infer SemType+deriveSemTypeFromBaseTypeAndKind bt k =+    return $ setTypeKind (deriveSemTypeFromBaseType bt) k  -------------------------------------------------- 
src/Language/Fortran/Lexer/FreeForm.x view
@@ -1144,6 +1144,7 @@   | TComment            SrcSpan String   | TString             SrcSpan String   | TIntegerLiteral     SrcSpan String+  -- | TRealLiteral        SrcSpan String (Maybe RealExponent) (Maybe KindParam)   | TRealLiteral        SrcSpan String   | TBozLiteral         SrcSpan String   | TComma              SrcSpan
src/Language/Fortran/Parser/Fortran2003.y view
@@ -1012,9 +1012,9 @@ TYPE_SPEC :: { TypeSpec A0 } : integer KIND_SELECTOR   { TypeSpec () (getSpan ($1, $2)) TypeInteger $2 } | real    KIND_SELECTOR   { TypeSpec () (getSpan ($1, $2)) TypeReal $2 }-| doublePrecision { TypeSpec () (getSpan $1) TypeDoublePrecision Nothing }+| doublePrecision         { TypeSpec () (getSpan $1)       TypeDoublePrecision Nothing } | complex KIND_SELECTOR   { TypeSpec () (getSpan ($1, $2)) TypeComplex $2 }-| character CHAR_SELECTOR { TypeSpec () (getSpan ($1, $2)) (uncurry TypeCharacter $ charLenSelector $2) $2 }+| character CHAR_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeCharacter $2 } | logical KIND_SELECTOR   { TypeSpec () (getSpan ($1, $2)) TypeLogical $2 } | type '(' id ')'   { let TId _ id = $3
src/Language/Fortran/Parser/Fortran77.y view
@@ -1020,17 +1020,15 @@  TYPE_SPEC :: { TypeSpec A0 } TYPE_SPEC-: integer KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeInteger $2 }-| real KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeReal $2  }-| doublePrecision KIND_SELECTOR-  { TypeSpec () (getSpan ($1, $2)) TypeDoublePrecision $2 }-| logical KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeLogical $2 }-| complex KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeComplex $2 }-| doubleComplex KIND_SELECTOR-  { TypeSpec () (getSpan ($1, $2)) TypeDoubleComplex $2 }-| character CHAR_SELECTOR { TypeSpec () (getSpan ($1, $2)) (uncurry TypeCharacter $ charLenSelector $2) $2 }-| byte KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeByte $2 }-| record '/' NAME '/' { TypeSpec () (getSpan ($1, $4)) (TypeCustom $3) Nothing }+: integer   KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeInteger $2 }+| real      KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeReal $2  }+| doublePrecision         { TypeSpec () (getSpan $1)       TypeDoublePrecision Nothing}+| logical   KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeLogical $2 }+| complex   KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeComplex $2 }+| doubleComplex           { TypeSpec () (getSpan $1)       TypeDoubleComplex Nothing}+| character CHAR_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeCharacter $2 }+| byte      KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeByte $2 }+| record    '/' NAME '/'  { TypeSpec () (getSpan ($1, $4)) (TypeCustom $3) Nothing }  KIND_SELECTOR :: { Maybe (Selector A0) } KIND_SELECTOR
src/Language/Fortran/Parser/Fortran90.y view
@@ -868,13 +868,13 @@     in DimensionDeclarator () span Nothing Nothing }  TYPE_SPEC :: { TypeSpec A0 }-: integer KIND_SELECTOR   { TypeSpec () (getSpan ($1, $2)) TypeInteger $2 }-| real    KIND_SELECTOR   { TypeSpec () (getSpan ($1, $2)) TypeReal $2 }-| doublePrecision { TypeSpec () (getSpan $1) TypeDoublePrecision Nothing }-| complex KIND_SELECTOR   { TypeSpec () (getSpan ($1, $2)) TypeComplex $2 }-| character CHAR_SELECTOR { TypeSpec () (getSpan ($1, $2)) (uncurry TypeCharacter $ charLenSelector $2) $2 }-| logical KIND_SELECTOR   { TypeSpec () (getSpan ($1, $2)) TypeLogical $2 }-| type '(' id ')'+: integer   KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeInteger $2 }+| real      KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeReal $2 }+| doublePrecision         { TypeSpec () (getSpan $1)       TypeDoublePrecision Nothing }+| complex   KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeComplex $2 }+| character CHAR_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeCharacter $2 }+| logical   KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeLogical $2 }+| type      '(' id ')'   { let TId _ id = $3     in TypeSpec () (getTransSpan $1 $4) (TypeCustom id) Nothing } 
src/Language/Fortran/Parser/Fortran95.y view
@@ -881,13 +881,13 @@     in DimensionDeclarator () span Nothing Nothing }  TYPE_SPEC :: { TypeSpec A0 }-: integer KIND_SELECTOR   { TypeSpec () (getSpan ($1, $2)) TypeInteger $2 }-| real    KIND_SELECTOR   { TypeSpec () (getSpan ($1, $2)) TypeReal $2 }-| doublePrecision { TypeSpec () (getSpan $1) TypeDoublePrecision Nothing }-| complex KIND_SELECTOR   { TypeSpec () (getSpan ($1, $2)) TypeComplex $2 }-| character CHAR_SELECTOR { TypeSpec () (getSpan ($1, $2)) (uncurry TypeCharacter $ charLenSelector $2) $2 }-| logical KIND_SELECTOR   { TypeSpec () (getSpan ($1, $2)) TypeLogical $2 }-| type '(' id ')'+: integer   KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeInteger $2 }+| real      KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeReal $2 }+| doublePrecision         { TypeSpec () (getSpan $1)       TypeDoublePrecision Nothing }+| complex   KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeComplex $2 }+| character CHAR_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeCharacter $2 }+| logical   KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeLogical $2 }+| type      '(' id ')'   { let TId _ id = $3     in TypeSpec () (getTransSpan $1 $4) (TypeCustom id) Nothing } 
src/Language/Fortran/Parser/Utils.hs view
@@ -1,7 +1,21 @@+{-# LANGUAGE LambdaCase #-}+ {-| Simple module to provide functions that read Fortran literals -}-module Language.Fortran.Parser.Utils (readReal, readInteger) where+module Language.Fortran.Parser.Utils+  ( readReal+  , readInteger+  , parseRealLiteral+  , RealLit(..)+  , Exponent(..)+  , NumSign(..)+  , ExponentLetter(..)+  ) where++import Language.Fortran.AST (Kind)+ import Data.Char import Numeric+import Text.Read (readMaybe)  breakAtDot :: String -> (String, String) replaceDwithE :: Char -> Char@@ -41,3 +55,78 @@ readsToMaybe r = case r of   (x, _):_ -> Just x   _ -> Nothing++--------------------------------------------------------------------------------++-- TODO limitation+-- Kind params allow 'Name's as well (which are checked at compile time to be a+-- special type of constant expression). We limit ourselves to integer kind+-- params only, because currently we don't handle full kind params in the later+-- stages anyway.+type KindParam = Kind++-- | A REAL literal may have an optional exponent and kind.+--+-- The value can be retrieved as a 'Double' by using these parts.+data RealLit = RealLit+  { realLitValue     :: String -- xyz.abc, xyz, xyz., .abc+  , realLitExponent  :: Maybe Exponent+  , realLitKindParam :: Maybe KindParam+  } deriving (Eq, Ord, Show)++-- | An exponent is an exponent letter (E, D) and a value (with an optional+-- sign).+data Exponent = Exponent+  { expLetter :: ExponentLetter+  , expSign   :: Maybe NumSign+  , expNum    :: Int+  } deriving (Eq, Ord, Show)++-- Note: Some Fortran language references include extensions here. HP's F90+-- reference provides a Q exponent letter which sets kind to 16.+data ExponentLetter+  = ExpLetterD+  | ExpLetterE+    deriving (Eq, Ord, Show)++data NumSign+  = SignPos+  | SignNeg+    deriving (Eq, Ord, Show)++-- | Parse a Fortran literal real to its constituent parts.+parseRealLiteral :: String -> RealLit+parseRealLiteral r =+    RealLit { realLitValue     = takeWhile isValuePart r+            , realLitExponent  = parseRealLitExponent (dropWhile isValuePart r)+            , realLitKindParam = parseRealLitKindInt (dropWhile (/= '_') r)+            }+  where+    -- slightly ugly: we add the signs in here to allow -1.0 easily+    isValuePart :: Char -> Bool+    isValuePart ch+      | isDigit ch                 = True+      | ch `elem` ['.', '-', '+']  = True+      | otherwise                  = False+    parseRealLitKindInt :: String -> Maybe Kind+    parseRealLitKindInt = \case+      '_':chs -> readMaybe chs+      _       -> Nothing+    parseRealLitExponent :: String -> Maybe Exponent+    parseRealLitExponent "" = Nothing+    parseRealLitExponent (c:cs) = do+        letter <-+                case toLower c of+                  'e' -> Just ExpLetterE+                  'd' -> Just ExpLetterD+                  _   -> Nothing+        let (sign, cs'') =+                case cs of+                  ""       -> (Nothing, cs)+                  c':cs'  -> -- TODO: want to locally scope cs' but unsure how to??+                    case c' of+                      '-' -> (Just SignNeg, cs')+                      '+' -> (Just SignPos, cs')+                      _   -> (Nothing     , cs)+            digitStr = read (takeWhile isDigit cs'')+        return $ Exponent letter sign digitStr
src/Language/Fortran/PrettyPrint.hs view
@@ -12,7 +12,7 @@ import Prelude hiding (EQ,LT,GT,pred,exp,(<>))  import Language.Fortran.AST-import Language.Fortran.ParserMonad+import Language.Fortran.Version import Language.Fortran.Util.FirstParameter  import Text.PrettyPrint@@ -353,7 +353,7 @@       | v == Fortran77Extended = "double complex"       | otherwise = tooOld v "Double complex" Fortran77Extended     pprint' _ TypeLogical = "logical"-    pprint' v (TypeCharacter _ _)+    pprint' v TypeCharacter       | v >= Fortran77 = "character"       | otherwise = tooOld v "Character data type" Fortran77     pprint' v (TypeCustom str)@@ -369,12 +369,6 @@     pprint' v (ClassCustom str)       | v >= Fortran2003 = "class" <> parens (text str)       | otherwise = tooOld v "Class(spec)" Fortran2003--instance Pretty CharacterLen where-  pprint' _ CharLenStar = "*"-  pprint' _ CharLenColon = ":"-  pprint' _ CharLenExp  = "*" -- FIXME, possibly, with a more robust const-exp-  pprint' _ (CharLenInt i) = text (show i)  instance Pretty (TypeSpec a) where     pprint' v (TypeSpec _ _ baseType mSelector) =
src/Language/Fortran/Transformation/Disambiguation/Intrinsic.hs view
@@ -18,7 +18,7 @@     trans = transformBi :: Data a => TransFunc Expression ProgramFile a     expression (ExpValue a s (ValVariable v))       | Just (IDType _ (Just CTIntrinsic)) <- idType a = ExpValue a s (ValIntrinsic v)-    expression e                                      = e+    expression e                                         = e  -------------------------------------------------- 
src/Main.hs view
@@ -327,8 +327,10 @@ showModuleMap :: ModuleMap -> String showModuleMap = concatMap (\ (n, m) -> show n ++ ":\n" ++ (unlines . map ("  "++) . lines . showGenericMap $ m)) . M.toList showTypes :: TypeEnv -> String-showTypes tenv = flip concatMap (M.toList tenv) $ \ (name, IDType { idVType = vt, idCType = ct }) ->-    printf "%s\t\t%s %s\n" name (drop 4 $ maybe "  -" show vt) (drop 2 $ maybe "   " show ct)+showTypes tenv =+    flip concatMap (M.toList tenv) $+      \ (name, IDType { idVType = vt, idCType = ct }) ->+        printf "%s\t\t%s %s\n" name (drop 3 $ maybe "  -" show vt) (drop 2 $ maybe "   " show ct) printTypes :: TypeEnv -> IO () printTypes = putStrLn . showTypes showTypeErrors :: [TypeError] -> String
+ test/Language/Fortran/Analysis/SemanticTypesSpec.hs view
@@ -0,0 +1,31 @@+module Language.Fortran.Analysis.SemanticTypesSpec where++import Test.Hspec+import TestUtil++import Language.Fortran.Analysis.SemanticTypes+import Language.Fortran.AST+import Language.Fortran.Version++spec :: Spec+spec = do+  describe "Semantic types" $ do+    it "recovers DOUBLE PRECISION for REAL(8) in Fortran 77" $ do+      let semtype  = TReal 8+          typespec = TypeSpec () u TypeDoublePrecision Nothing+       in recoverSemTypeTypeSpec () u Fortran77 semtype `shouldBe` typespec++    it "recovers DOUBLE COMPLEX for COMPLEX(16) in Fortran 77" $ do+      let semtype  = TComplex 16+          typespec = TypeSpec () u TypeDoubleComplex Nothing+       in recoverSemTypeTypeSpec () u Fortran77 semtype `shouldBe` typespec++    it "recovers REAL(8) for REAL(8) in Fortran 90" $ do+      let semtype  = TReal 8+          typespec = TypeSpec () u TypeReal (Just (Selector () u Nothing (Just (ExpValue () u (ValInteger "8")))))+       in recoverSemTypeTypeSpec () u Fortran90 semtype `shouldBe` typespec++    it "recovers CHARACTER(*)" $ do+      let semtype  = TCharacter CharLenStar 1+          typespec = TypeSpec () u TypeCharacter (Just (Selector () u (Just (ExpValue () u ValStar)) Nothing))+       in recoverSemTypeTypeSpec () u Fortran90 semtype `shouldBe` typespec
test/Language/Fortran/Analysis/TypesSpec.hs view
@@ -8,9 +8,10 @@ import Data.Data import Data.Generics.Uniplate.Data import Language.Fortran.AST+import Language.Fortran.Analysis import Language.Fortran.Analysis.Types+import Language.Fortran.Analysis.SemanticTypes import Language.Fortran.Analysis.Renaming-import Language.Fortran.Analysis import qualified Language.Fortran.Parser.Fortran90 as F90 import Language.Fortran.ParserMonad import qualified Data.ByteString.Char8 as B@@ -27,16 +28,21 @@ uniExpr :: ProgramFile (Analysis A0) -> [Expression (Analysis A0)] uniExpr = universeBi +-- | Get the default 'SemType' for the given 'BaseType' (i.e. get its 'SemType'+--   and use the default kind).+defSTy :: BaseType -> SemType+defSTy = deriveSemTypeFromBaseType+ spec :: Spec spec = do   describe "Global type inference" $ do     it "types integer returning function" $ do       let entry = inferTable ex1 ! "f1"-      entry `shouldBe` IDType (Just TypeInteger) (Just CTFunction)+      entry `shouldBe` IDType (Just (defSTy TypeInteger)) (Just CTFunction)      it "types multiples program units" $ do       let mapping = inferTable ex2-      mapping ! "f1" `shouldBe` IDType (Just TypeInteger) (Just CTFunction)+      mapping ! "f1" `shouldBe` IDType (Just (defSTy TypeInteger)) (Just CTFunction)       mapping ! "s1" `shouldBe` IDType Nothing (Just CTSubroutine)      it "types ENTRY points within subprograms" $ do@@ -49,15 +55,14 @@     it "infers from type declarations" $ do       let mapping = inferTable ex4       let pf = typedProgramFile ex4-      mapping ! "x" `shouldBe` IDType (Just TypeInteger) (Just CTVariable)-      mapping ! "y" `shouldBe` IDType (Just TypeInteger) (Just $ CTArray [(Nothing, Just 10)])-      mapping ! "c" `shouldBe` IDType (Just $ TypeCharacter Nothing Nothing) (Just CTVariable)-      mapping ! "log" `shouldBe` IDType (Just TypeLogical) (Just CTVariable)+      mapping ! "y" `shouldBe` IDType (Just (defSTy TypeInteger)) (Just $ CTArray [(Nothing, Just 10)])+      mapping ! "c" `shouldBe` IDType (Just (defSTy TypeCharacter)) (Just CTVariable)+      mapping ! "log" `shouldBe` IDType (Just (defSTy TypeLogical)) (Just CTVariable)       [ () | ExpValue a _ (ValVariable "x") <- uniExpr pf-           , idType a == Just (IDType (Just TypeInteger) (Just CTVariable)) ]+           , idType a == Just (IDType (Just (defSTy TypeInteger)) (Just CTVariable)) ]         `shouldNotSatisfy` null       [ () | ExpValue a _ (ValVariable "y") <- uniExpr pf-           , idType a == Just (IDType (Just TypeInteger) (Just $ CTArray [(Nothing, Just 10)])) ]+           , idType a == Just (IDType (Just (defSTy TypeInteger)) (Just $ CTArray [(Nothing, Just 10)])) ]         `shouldNotSatisfy` null      it "infers from dimension declarations" $ do@@ -67,9 +72,9 @@      it "infers from function statements" $ do       let mapping = inferTable ex6-      mapping ! "a" `shouldBe` IDType (Just TypeInteger) (Just $ CTArray [(Nothing, Just 1)])-      mapping ! "b" `shouldBe` IDType (Just TypeInteger) (Just $ CTArray [(Nothing, Just 1)])-      mapping ! "c" `shouldBe` IDType (Just TypeInteger) (Just CTFunction)+      mapping ! "a" `shouldBe` IDType (Just (defSTy TypeInteger)) (Just $ CTArray [(Nothing, Just 1)])+      mapping ! "b" `shouldBe` IDType (Just (defSTy TypeInteger)) (Just $ CTArray [(Nothing, Just 1)])+      mapping ! "c" `shouldBe` IDType (Just (defSTy TypeInteger)) (Just CTFunction)       mapping ! "d" `shouldBe` IDType Nothing (Just CTFunction)      describe "Intrinsics type analysis" $ do@@ -77,7 +82,7 @@         let mapping = inferTable intrinsics1         let pf = typedProgramFile intrinsics1         [ () | ExpValue a _ (ValVariable "x") <- uniExpr pf-             , idType a == Just (IDType (Just TypeReal) (Just CTVariable)) ]+             , idType a == Just (IDType (Just (defSTy TypeReal)) (Just CTVariable)) ]           `shouldSatisfy` ((== 5) . length)          -- the following are true because dabs and cabs are defined as function and array in this program.@@ -94,7 +99,7 @@         -- abs is an actual intrinsic         idCType (mapping ! "abs") `shouldBe` Just CTIntrinsic         [ a | ExpFunctionCall a _ (ExpValue _ _ (ValIntrinsic "abs")) _ <- uniExpr pf-            , idType a == Just (IDType (Just TypeInteger) Nothing) ]+            , idType a == Just (IDType (Just (defSTy TypeInteger)) Nothing) ]           `shouldNotSatisfy` null        it "intrinsics and numeric types" $ do@@ -105,41 +110,42 @@         idCType (mapping ! "dabs") `shouldBe` Just CTIntrinsic         [ ty | ExpFunctionCall a _ (ExpValue _ _ (ValIntrinsic "abs")) _ <- uniExpr pf              , Just (IDType (Just ty) Nothing) <- [idType a] ]-          `shouldBe` [TypeDoublePrecision, TypeComplex]+          `shouldBe` [defSTy TypeDoublePrecision, defSTy TypeComplex]         [ a | ExpFunctionCall a _ (ExpValue _ _ (ValIntrinsic "cabs")) _ <- uniExpr pf-            , idType a == Just (IDType (Just TypeComplex) Nothing) ]+            , idType a == Just (IDType (Just (defSTy TypeComplex)) Nothing) ]           `shouldNotSatisfy` null         [ a | ExpFunctionCall a _ (ExpValue _ _ (ValIntrinsic "dabs")) _ <- uniExpr pf-            , idType a == Just (IDType (Just TypeDoublePrecision) Nothing) ]+            , idType a == Just (IDType (Just (defSTy TypeDoublePrecision)) Nothing) ]           `shouldNotSatisfy` null      describe "Numeric types" $ do       it "Widening / upgrading" $ do         let pf = typedProgramFile numerics1         [ a | ExpFunctionCall a _ (ExpValue _ _ (ValIntrinsic "abs")) _ <- uniExpr pf-            , idType a == Just (IDType (Just TypeReal) Nothing) ]+            , idType a == Just (IDType (Just (defSTy TypeReal)) Nothing) ]           `shouldNotSatisfy` null         [ a | ExpBinary a _ Addition (ExpValue _ _ (ValInteger "1")) _ <- uniExpr pf-            , idType a == Just (IDType (Just TypeComplex) Nothing) ]+            , idType a == Just (IDType (Just (defSTy TypeComplex)) Nothing) ]           `shouldNotSatisfy` null         [ a | ExpBinary a _ Addition (ExpValue _ _ (ValInteger "2")) _ <- uniExpr pf-            , idType a == Just (IDType (Just TypeDoublePrecision) Nothing) ]+            , idType a == Just (IDType (Just (TReal 8)) Nothing) ]           `shouldNotSatisfy` null      describe "Character string types" $       it "examples of various character variables" $ do         let mapping = inferTable teststrings1-        idVType (mapping ! "a") `shouldBe` Just (TypeCharacter (Just (CharLenInt 5)) (Just "1"))-        idVType (mapping ! "b") `shouldBe` Just (TypeCharacter (Just (CharLenInt 10)) Nothing)-        idVType (mapping ! "c") `shouldBe` Just (TypeCharacter (Just (CharLenInt 3)) (Just "1"))-        idVType (mapping ! "d") `shouldBe` Just (TypeCharacter (Just CharLenExp) Nothing)+        idVType (mapping ! "a") `shouldBe` Just (TCharacter (CharLenInt 5) 1)+        idVType (mapping ! "b") `shouldBe` Just (TCharacter (CharLenInt 10) 1)+        idVType (mapping ! "c") `shouldBe` Just (TCharacter (CharLenInt 3) 1)+        idVType (mapping ! "d") `shouldBe` Just (TCharacter CharLenExp 1)         idCType (mapping ! "d") `shouldBe` Just (CTArray [(Nothing, Just 10)])-        idVType (mapping ! "e") `shouldBe` Just (TypeCharacter (Just (CharLenInt 10)) Nothing)+        idVType (mapping ! "e") `shouldBe` Just (TCharacter (CharLenInt 10) 1)         idCType (mapping ! "e") `shouldBe` Just (CTArray [(Nothing, Just 20)])+        idVType (mapping ! "f") `shouldBe` Just (TCharacter (CharLenInt 1) 2)         let pf = typedProgramFile teststrings1         [ () | ExpValue a _ (ValVariable "e") <- uniExpr pf-             , idType a == Just (IDType (Just (TypeCharacter (Just (CharLenInt 10)) Nothing))-                                        (Just (CTArray [(Nothing, Just 20)]))) ]+             , idType a == Just (IDType (Just (TCharacter (CharLenInt 10) 1))+                                        (Just (CTArray [(Nothing, Just 20)])))]           `shouldNotSatisfy` null  ex1 :: ProgramFile ()@@ -173,7 +179,7 @@         [ DeclVariable () u (varGen "x") Nothing Nothing         , DeclArray () u (varGen "y")             (AList () u [ DimensionDeclarator () u Nothing (Just $ intGen 10) ]) Nothing Nothing ]))-  , BlStatement () u Nothing (StDeclaration () u (TypeSpec () u (TypeCharacter Nothing Nothing) Nothing) Nothing+  , BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeCharacter Nothing) Nothing       (AList () u [ DeclVariable () u (varGen "c") Nothing Nothing ]))   , BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeLogical Nothing) Nothing       (AList () u [ DeclVariable () u (varGen "log") Nothing Nothing ])) ]@@ -296,6 +302,7 @@   , "  integer, parameter :: k = 8"   , "  character(k), dimension(10) :: d"   , "  character :: e(20)*10"+  , "  character(kind=2) :: f"   , "end program teststrings"   ] 
test/Language/Fortran/Parser/Fortran2003Spec.hs view
@@ -122,14 +122,14 @@        it "parses allocate with type_spec" $ do         let sel = Selector () u (Just (ExpValue () u ValColon)) (Just (varGen "foo"))-        let ty = TypeSpec () u (TypeCharacter (Just $ CharLenColon) (Just "foo")) (Just sel)+        let ty = TypeSpec () u TypeCharacter (Just sel)         let decls = [DeclVariable () u (varGen "s") Nothing Nothing]         let st = StDeclaration () u ty (Just (AList () u [AttrAllocatable () u])) (AList () u decls)         sParser "character(len=:,kind=foo), allocatable :: s" `shouldBe'` st        it "parses allocate with type_spec" $ do         let sel = Selector () u (Just (intGen 3)) (Just (varGen "foo"))-        let ty = TypeSpec () u (TypeCharacter (Just $ CharLenInt 3) (Just "foo")) (Just sel)+        let ty = TypeSpec () u TypeCharacter (Just sel)         let st = StAllocate () u (Just ty) (AList () u [varGen "s"]) Nothing         sParser "allocate(character(len=3,kind=foo) :: s)" `shouldBe'` st 
test/Language/Fortran/Parser/Fortran77/ParserSpec.hs view
@@ -161,7 +161,7 @@       it "parses 'implicit character*30 (a, b, c), integer (a-z, l)" $ do         let impEls = [ImpCharacter () u "a", ImpCharacter () u "b", ImpCharacter () u "c"]             sel = Selector () u (Just (intGen 30)) Nothing-            imp1 = ImpList () u (TypeSpec () u (TypeCharacter (Just $ CharLenInt 30) Nothing) (Just sel)) $ AList () u impEls+            imp1 = ImpList () u (TypeSpec () u TypeCharacter (Just sel)) $ AList () u impEls             imp2 = ImpList () u (TypeSpec () u TypeInteger Nothing) $ AList () u [ImpRange () u "a" "z", ImpCharacter () u "l"]             st = StImplicit () u $ Just $ AList () u [imp1, imp2]         sParser "      implicit character*30 (a, b, c), integer (a-z, l)" `shouldBe'` st@@ -202,7 +202,7 @@      it "parses 'character a*8'" $ do       let decl = DeclVariable () u (varGen "a") (Just $ intGen 8) Nothing-          typeSpec = TypeSpec () u (TypeCharacter Nothing Nothing) Nothing+          typeSpec = TypeSpec () u TypeCharacter Nothing           st = StDeclaration () u typeSpec Nothing (AList () u [ decl ])       sParser "      character a*8" `shouldBe'` st @@ -210,7 +210,7 @@       let args = AList () u [ IxSingle () u Nothing (ExpValue () u (ValString "A")) ]           lenExpr = ExpSubscript () u (ExpValue () u (ValVariable "ichar")) args           decl = DeclVariable () u (varGen "c") (Just $ lenExpr) Nothing-          typeSpec = TypeSpec () u (TypeCharacter Nothing Nothing) Nothing+          typeSpec = TypeSpec () u TypeCharacter Nothing           st = StDeclaration () u typeSpec Nothing (AList () u [ decl ])       sParser "      character c*(ichar('A'))" `shouldBe'` st @@ -308,7 +308,7 @@        it "parses character declarations with unspecfied lengths" $ do         let src = "      character s*(*)"-            st = StDeclaration () u (TypeSpec () u (TypeCharacter Nothing Nothing) Nothing) Nothing $+            st = StDeclaration () u (TypeSpec () u TypeCharacter Nothing) Nothing $                  AList () u [DeclVariable () u                                (ExpValue () u (ValVariable "s"))                                (Just (ExpValue () u ValStar))@@ -328,7 +328,7 @@          let src1 = "      character xs(2)*5 / 'hello', 'world' /"             inits1 = [ExpValue () u (ValString "hello"), ExpValue () u (ValString "world")]-            st1 = StDeclaration () u (TypeSpec () u (TypeCharacter Nothing Nothing) Nothing) Nothing $+            st1 = StDeclaration () u (TypeSpec () u TypeCharacter Nothing) Nothing $                  AList () u [DeclArray () u                                (ExpValue () u (ValVariable "xs"))                                (AList () u [DimensionDeclarator () u Nothing (Just (ExpValue () u (ValInteger "2")))])@@ -338,7 +338,7 @@          let src2 = "      character xs*5(2) / 'hello', 'world' /"             inits2 = [ExpValue () u (ValString "hello"), ExpValue () u (ValString "world")]-            st2 = StDeclaration () u (TypeSpec () u (TypeCharacter Nothing Nothing) Nothing) Nothing $+            st2 = StDeclaration () u (TypeSpec () u TypeCharacter Nothing) Nothing $                  AList () u [DeclArray () u                                (ExpValue () u (ValVariable "xs"))                                (AList () u [DimensionDeclarator () u Nothing (Just (ExpValue () u (ValInteger "2")))])
test/Language/Fortran/Parser/Fortran90Spec.hs view
@@ -285,7 +285,7 @@           sParser "implicit none" `shouldBe'` st          it "parses implicit with single" $ do-          let typeSpec = TypeSpec () u (TypeCharacter Nothing Nothing) Nothing+          let typeSpec = TypeSpec () u TypeCharacter Nothing           let impEls = [ ImpCharacter () u "k" ]           let impLists = [ ImpList () u typeSpec (fromList () impEls) ]           let st = StImplicit () u (Just $ fromList () impLists)@@ -299,7 +299,7 @@           sParser "implicit logical (x-z)" `shouldBe'` st          it "parses implicit statement" $ do-          let typeSpec1 = TypeSpec () u (TypeCharacter Nothing Nothing) Nothing+          let typeSpec1 = TypeSpec () u TypeCharacter Nothing           let typeSpec2 = TypeSpec () u TypeInteger Nothing           let impEls1 = [ ImpCharacter () u "s", ImpCharacter () u "a" ]           let impEls2 = [ ImpRange () u "x" "z" ]
test/Language/Fortran/Parser/Fortran95Spec.hs view
@@ -337,7 +337,7 @@           sParser "implicit none" `shouldBe'` st          it "parses implicit with single" $ do-          let typeSpec = TypeSpec () u (TypeCharacter Nothing Nothing) Nothing+          let typeSpec = TypeSpec () u TypeCharacter Nothing               impEls = [ ImpCharacter () u "k" ]               impLists = [ ImpList () u typeSpec (fromList () impEls) ]               st = StImplicit () u (Just $ fromList () impLists)@@ -351,7 +351,7 @@           sParser "implicit logical (x-z)" `shouldBe'` st          it "parses implicit statement" $ do-          let typeSpec1 = TypeSpec () u (TypeCharacter Nothing Nothing) Nothing+          let typeSpec1 = TypeSpec () u TypeCharacter Nothing               typeSpec2 = TypeSpec () u TypeInteger Nothing               impEls1 = [ ImpCharacter () u "s", ImpCharacter () u "a" ]               impEls2 = [ ImpRange () u "x" "z" ]
test/Language/Fortran/Parser/UtilsSpec.hs view
@@ -7,7 +7,8 @@ spec :: Spec spec =   describe "Fortran Parser Utils" $ do-    describe "readReal" $++    describe "readReal" $ do       it "tests" $ do         readReal "+12"       `shouldBe` Just 12         readReal "-1.2"      `shouldBe` Just (-1.2)@@ -17,7 +18,8 @@         readReal ".12"       `shouldBe` Just 0.12         readReal "-.12"      `shouldBe` Just (-0.12)         readReal "1_f"       `shouldBe` Just 1-    describe "readInteger" $++    describe "readInteger" $ do       it "tests" $ do         readInteger "b'101'" `shouldBe` Just 5         readInteger "o'22'"  `shouldBe` Just 18@@ -25,3 +27,54 @@         readInteger "1_f"    `shouldBe` Just 1         readInteger "+123"   `shouldBe` Just 123         readInteger "-123"   `shouldBe` Just (-123)++    describe "parseRealLiteral" $ do+      it "parses various well-formed valid real literals" $ do+        prl "1"         `shouldBe` rl "1"    n n+        prl "1."        `shouldBe` rl "1."   n n+        prl ".0"        `shouldBe` rl ".0"   n n+        prl "1e0"       `shouldBe` rl "1"    (jExp expE n 0) n+        prl "1e0_4"     `shouldBe` rl "1"    (jExp expE n 0) (j 4)+        --prl "1e0_k"     `shouldBe` rl "1" _ _+        prl "1.0e0_4"   `shouldBe` rl "1.0"  (jExp expE n 0) (j 4)+        prl "+1.0e0_4"  `shouldBe` rl "+1.0" (jExp expE n 0) (j 4)+        prl "-1.0e0_4"  `shouldBe` rl "-1.0" (jExp expE n 0) (j 4)+        prl "-1.0e+0_4" `shouldBe` rl "-1.0" (jExp expE (j SignPos) 0) (j 4)+        prl "-1.0e-0_4" `shouldBe` rl "-1.0" (jExp expE (j SignNeg) 0) (j 4)+        prl "-1.0d-0_4" `shouldBe` rl "-1.0" (jExp expD (j SignNeg) 0) (j 4)++      -- Literals we gladly parse, but that most Fortran specs consider invalid.+      -- These will prompt an error during type analysis.+      it "parses various well-formed invalid real literals" $ do+        -- only exponent letter e allows kind param+        -- even if you use kind 8 (== what d sets), it should be considered+        -- invalid+        prl "1d0_8"   `shouldBe` rl "1" (jExp expD n 0) (j 8)+        prl "1d0_4"   `shouldBe` rl "1" (jExp expD n 0) (j 4)++      -- parseRealLiteral runtime errors on poorly-formed real literals because+      -- the parser should ensure we only ever receive well-formed ones.+      -- TODO: unable to test these while the parser uses 'error'+      it "fails to parse poorly-formed real literals" $ do+        pending+        {-+        -- exponent number can't be empty+        fails $ prl "1e"++        -- exponent number must be an integer+        fails $ prl "1ex"+        fails $ prl "1ex1"+        --fails $ prl "1e0.0"       -- not detected, we take the digits before+                                    -- the decimal point+        -}+++      where+        prl = parseRealLiteral+        rl = RealLit+        n = Nothing+        j = Just+        jExp a b c = Just (Exponent a b c)+        expE = ExpLetterE+        expD = ExpLetterD+        fails test = return test `shouldThrow` anyException
test/Language/Fortran/PrettyPrintSpec.hs view
@@ -106,7 +106,7 @@       describe "Declaration" $ do         it "prints 90 style with attributes" $ do           let sel = Selector () u (Just $ intGen 3) Nothing-          let typeSpec = TypeSpec () u (TypeCharacter Nothing Nothing) (Just sel)+          let typeSpec = TypeSpec () u TypeCharacter (Just sel)           let attrs = [ AttrIntent () u In , AttrPointer () u ]           let declList =                 [ DeclVariable () u (varGen "x") Nothing (Just $ intGen 42)@@ -254,7 +254,7 @@           it "prints allocate statement with type spec" $ do             let stat = AOStat () u (varGen "s")             let sel = Selector () u (Just (intGen 30)) Nothing-            let ty = TypeSpec () u (TypeCharacter (Just $ CharLenInt 30) Nothing) (Just sel)+            let ty = TypeSpec () u TypeCharacter (Just sel)             let st = StAllocate () u (Just ty) (AList () u [ varGen "x" ]) (Just (AList () u [stat]))             pprint Fortran2003 st Nothing `shouldBe` "allocate (character(len=30) :: x, stat=s)" 
test/Language/Fortran/Transformation/Disambiguation/FunctionSpec.hs view
@@ -3,7 +3,6 @@ import Test.Hspec import TestUtil -import Language.Fortran.Analysis import Language.Fortran.AST import Language.Fortran.Transformer