fortran-src 0.2.1.1 → 0.3.0
raw patch · 54 files changed
+5908/−2036 lines, 54 filesdep ~containersnew-uploaderPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: containers
API changes (from Hackage documentation)
- Language.Fortran.AST: Elemental :: a -> SrcSpan -> PUFunctionOpt a
- Language.Fortran.AST: None :: a -> SrcSpan -> IsRecursive -> PUFunctionOpt a
- Language.Fortran.AST: Pure :: a -> SrcSpan -> IsRecursive -> PUFunctionOpt a
- Language.Fortran.AST: buildPUFunctionOpt :: (PUFunctionOpt ()) -> (PUFunctionOpt ()) -> Either String (PUFunctionOpt ())
- Language.Fortran.AST: buildPUFunctionOpts :: [PUFunctionOpt ()] -> Either String (PUFunctionOpt ())
- Language.Fortran.AST: data PUFunctionOpt a
- Language.Fortran.AST: functionIsRecursive :: (PUFunctionOpt a) -> Bool
- Language.Fortran.AST: instance (Data.Data.Data (t a), Data.Data.Data a, Data.Typeable.Internal.Typeable t) => Data.Data.Data (Language.Fortran.AST.AList t a)
- Language.Fortran.AST: instance (GHC.Classes.Eq (t a), GHC.Classes.Eq a) => GHC.Classes.Eq (Language.Fortran.AST.AList t a)
- Language.Fortran.AST: instance (GHC.Show.Show (t a), GHC.Show.Show a) => GHC.Show.Show (Language.Fortran.AST.AList t a)
- Language.Fortran.AST: instance (Language.Fortran.Util.Position.Spanned a, Language.Fortran.Util.Position.Spanned b) => Language.Fortran.Util.Position.Spanned (GHC.Base.Maybe a, b)
- Language.Fortran.AST: instance (Language.Fortran.Util.Position.Spanned a, Language.Fortran.Util.Position.Spanned b) => Language.Fortran.Util.Position.Spanned (a, GHC.Base.Maybe b)
- Language.Fortran.AST: instance (Language.Fortran.Util.Position.Spanned a, Language.Fortran.Util.Position.Spanned b, Language.Fortran.Util.Position.Spanned c) => Language.Fortran.Util.Position.Spanned (GHC.Base.Maybe a, GHC.Base.Maybe b, GHC.Base.Maybe c)
- Language.Fortran.AST: instance (Language.Fortran.Util.Position.Spanned a, Language.Fortran.Util.Position.Spanned b, Language.Fortran.Util.Position.Spanned c) => Language.Fortran.Util.Position.Spanned (GHC.Base.Maybe a, b, c)
- Language.Fortran.AST: instance (Language.Fortran.Util.Position.Spanned a, Language.Fortran.Util.Position.Spanned b, Language.Fortran.Util.Position.Spanned c) => Language.Fortran.Util.Position.Spanned (a, GHC.Base.Maybe b, GHC.Base.Maybe c)
- Language.Fortran.AST: instance Data.Data.Data a => Data.Data.Data (Language.Fortran.AST.PUFunctionOpt a)
- Language.Fortran.AST: instance GHC.Base.Functor Language.Fortran.AST.PUFunctionOpt
- Language.Fortran.AST: instance GHC.Classes.Eq a => GHC.Classes.Eq (Language.Fortran.AST.PUFunctionOpt a)
- Language.Fortran.AST: instance GHC.Generics.Generic (Language.Fortran.AST.PUFunctionOpt a)
- Language.Fortran.AST: instance GHC.Show.Show a => GHC.Show.Show (Language.Fortran.AST.PUFunctionOpt a)
- Language.Fortran.AST: instance Language.Fortran.Util.FirstParameter.FirstParameter (Language.Fortran.AST.PUFunctionOpt a) a
- Language.Fortran.AST: instance Language.Fortran.Util.Position.Spanned (Language.Fortran.AST.PUFunctionOpt a)
- Language.Fortran.AST: instance Language.Fortran.Util.SecondParameter.SecondParameter (Language.Fortran.AST.PUFunctionOpt a) Language.Fortran.Util.Position.SrcSpan
- Language.Fortran.AST: instance Text.PrettyPrint.GenericPretty.Out a => Text.PrettyPrint.GenericPretty.Out (Language.Fortran.AST.PUFunctionOpt a)
- Language.Fortran.AST: type IsRecursive = Bool
- Language.Fortran.Analysis: type BBGr a = Gr (BB a) ()
- Language.Fortran.Analysis.BBlocks: superBBGrClusters :: SuperBBGr a -> IntMap ProgramUnitName
- Language.Fortran.Analysis.BBlocks: superBBGrEntries :: SuperBBGr a -> Map ProgramUnitName SuperNode
- Language.Fortran.Analysis.BBlocks: superBBGrGraph :: SuperBBGr a -> BBGr a
- Language.Fortran.Analysis.DataFlow: noPredNodes :: Graph g => g a b -> [Node]
- Language.Fortran.Lexer.FreeForm: alex_action_4 :: Parse AlexInput Token Maybe Token
- Language.Fortran.ParserMonad: instance (Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable b, GHC.Show.Show a, GHC.Show.Show b) => GHC.Exception.Exception (Language.Fortran.ParserMonad.ParseError a b)
- Language.Fortran.PrettyPrint: instance Language.Fortran.PrettyPrint.IndentablePretty a => Language.Fortran.PrettyPrint.IndentablePretty (GHC.Base.Maybe a)
- Language.Fortran.PrettyPrint: instance Language.Fortran.PrettyPrint.Pretty a => Language.Fortran.PrettyPrint.Pretty (GHC.Base.Maybe a)
+ Language.Fortran.AST: AOErrMsg :: a -> SrcSpan -> Expression a -> AllocOpt a
+ Language.Fortran.AST: AOSource :: a -> SrcSpan -> Expression a -> AllocOpt a
+ Language.Fortran.AST: AOStat :: a -> SrcSpan -> Expression a -> AllocOpt a
+ Language.Fortran.AST: AttrAsynchronous :: a -> SrcSpan -> Attribute a
+ Language.Fortran.AST: AttrProtected :: a -> SrcSpan -> Attribute a
+ Language.Fortran.AST: AttrSuffix :: a -> SrcSpan -> Suffix a -> Attribute a
+ Language.Fortran.AST: AttrValue :: a -> SrcSpan -> Attribute a
+ Language.Fortran.AST: AttrVolatile :: a -> SrcSpan -> Attribute a
+ Language.Fortran.AST: CharLenColon :: CharacterLen
+ Language.Fortran.AST: CharLenExp :: CharacterLen
+ Language.Fortran.AST: CharLenInt :: Int -> CharacterLen
+ Language.Fortran.AST: CharLenStar :: CharacterLen
+ Language.Fortran.AST: ClassCustom :: String -> BaseType
+ Language.Fortran.AST: ClassStar :: BaseType
+ Language.Fortran.AST: FSErr :: a -> SrcSpan -> Expression a -> FlushSpec a
+ Language.Fortran.AST: FSIOMsg :: a -> SrcSpan -> Expression a -> FlushSpec a
+ Language.Fortran.AST: FSIOStat :: a -> SrcSpan -> Expression a -> FlushSpec a
+ Language.Fortran.AST: FSUnit :: a -> SrcSpan -> Expression a -> FlushSpec a
+ Language.Fortran.AST: ModIntrinsic :: ModuleNature
+ Language.Fortran.AST: ModNonIntrinsic :: ModuleNature
+ Language.Fortran.AST: PfxElemental :: a -> SrcSpan -> Prefix a
+ Language.Fortran.AST: PfxPure :: a -> SrcSpan -> Prefix a
+ Language.Fortran.AST: PfxRecursive :: a -> SrcSpan -> Prefix a
+ Language.Fortran.AST: ProcDecl :: a -> SrcSpan -> Expression a -> Maybe (Expression a) -> ProcDecl a
+ Language.Fortran.AST: ProcInterfaceName :: a -> SrcSpan -> Expression a -> ProcInterface a
+ Language.Fortran.AST: ProcInterfaceType :: a -> SrcSpan -> TypeSpec a -> ProcInterface a
+ Language.Fortran.AST: SfxBind :: a -> SrcSpan -> Maybe (Expression a) -> Suffix a
+ Language.Fortran.AST: StAsynchronous :: a -> SrcSpan -> AList Declarator a -> Statement a
+ Language.Fortran.AST: StEndEnum :: a -> SrcSpan -> Statement a
+ Language.Fortran.AST: StEnum :: a -> SrcSpan -> Statement a
+ Language.Fortran.AST: StEnumerator :: a -> SrcSpan -> AList Declarator a -> Statement a
+ Language.Fortran.AST: StFlush :: a -> SrcSpan -> AList FlushSpec a -> Statement a
+ Language.Fortran.AST: StImport :: a -> SrcSpan -> AList Expression a -> Statement a
+ Language.Fortran.AST: StProcedure :: a -> SrcSpan -> Maybe (ProcInterface a) -> Maybe (Attribute a) -> AList ProcDecl a -> Statement a
+ Language.Fortran.AST: StProtected :: a -> SrcSpan -> Maybe (AList Expression a) -> Statement a
+ Language.Fortran.AST: StValue :: a -> SrcSpan -> AList Declarator a -> Statement a
+ Language.Fortran.AST: StVolatile :: a -> SrcSpan -> AList Declarator a -> Statement a
+ Language.Fortran.AST: ValColon :: Value a
+ Language.Fortran.AST: aStrip' :: Maybe (AList t a) -> [t a]
+ Language.Fortran.AST: charLenSelector :: Maybe (Selector a) -> (Maybe CharacterLen, Maybe String)
+ Language.Fortran.AST: data AllocOpt a
+ Language.Fortran.AST: data CharacterLen
+ Language.Fortran.AST: data FlushSpec a
+ Language.Fortran.AST: data ModuleNature
+ Language.Fortran.AST: data Prefix a
+ Language.Fortran.AST: data ProcDecl a
+ Language.Fortran.AST: data ProcInterface a
+ Language.Fortran.AST: data Suffix a
+ Language.Fortran.AST: emptyPrefixSuffix :: PrefixSuffix a
+ Language.Fortran.AST: emptyPrefixes :: Prefixes a
+ Language.Fortran.AST: emptySuffixes :: Suffixes a
+ Language.Fortran.AST: fromList' :: Spanned (t a) => a -> [t a] -> Maybe (AList t a)
+ Language.Fortran.AST: fromReverseList' :: Spanned (t ()) => [t ()] -> Maybe (AList t ())
+ Language.Fortran.AST: instance (Data.Typeable.Internal.Typeable t, Data.Data.Data a, Data.Data.Data (t a)) => Data.Data.Data (Language.Fortran.AST.AList t a)
+ Language.Fortran.AST: instance (GHC.Classes.Eq a, GHC.Classes.Eq (t a)) => GHC.Classes.Eq (Language.Fortran.AST.AList t a)
+ Language.Fortran.AST: instance (GHC.Show.Show a, GHC.Show.Show (t a)) => GHC.Show.Show (Language.Fortran.AST.AList t a)
+ Language.Fortran.AST: instance (Language.Fortran.Util.Position.Spanned a, Language.Fortran.Util.Position.Spanned b) => Language.Fortran.Util.Position.Spanned (Data.Either.Either a b)
+ Language.Fortran.AST: instance (Language.Fortran.Util.Position.Spanned a, Language.Fortran.Util.Position.Spanned b) => Language.Fortran.Util.Position.Spanned (GHC.Maybe.Maybe a, b)
+ Language.Fortran.AST: instance (Language.Fortran.Util.Position.Spanned a, Language.Fortran.Util.Position.Spanned b) => Language.Fortran.Util.Position.Spanned (a, GHC.Maybe.Maybe b)
+ Language.Fortran.AST: instance (Language.Fortran.Util.Position.Spanned a, Language.Fortran.Util.Position.Spanned b, Language.Fortran.Util.Position.Spanned c) => Language.Fortran.Util.Position.Spanned (GHC.Maybe.Maybe a, GHC.Maybe.Maybe b, GHC.Maybe.Maybe c)
+ Language.Fortran.AST: instance (Language.Fortran.Util.Position.Spanned a, Language.Fortran.Util.Position.Spanned b, Language.Fortran.Util.Position.Spanned c) => Language.Fortran.Util.Position.Spanned (GHC.Maybe.Maybe a, b, c)
+ Language.Fortran.AST: instance (Language.Fortran.Util.Position.Spanned a, Language.Fortran.Util.Position.Spanned b, Language.Fortran.Util.Position.Spanned c) => Language.Fortran.Util.Position.Spanned (a, GHC.Maybe.Maybe b, GHC.Maybe.Maybe c)
+ Language.Fortran.AST: instance Data.Binary.Class.Binary Language.Fortran.AST.BinaryOp
+ Language.Fortran.AST: instance Data.Binary.Class.Binary Language.Fortran.AST.CharacterLen
+ Language.Fortran.AST: instance Data.Binary.Class.Binary Language.Fortran.AST.UnaryOp
+ Language.Fortran.AST: instance Data.Data.Data Language.Fortran.AST.CharacterLen
+ Language.Fortran.AST: instance Data.Data.Data Language.Fortran.AST.ModuleNature
+ Language.Fortran.AST: instance Data.Data.Data a => Data.Data.Data (Language.Fortran.AST.AllocOpt a)
+ Language.Fortran.AST: instance Data.Data.Data a => Data.Data.Data (Language.Fortran.AST.FlushSpec a)
+ Language.Fortran.AST: instance Data.Data.Data a => Data.Data.Data (Language.Fortran.AST.Prefix a)
+ Language.Fortran.AST: instance Data.Data.Data a => Data.Data.Data (Language.Fortran.AST.ProcDecl a)
+ Language.Fortran.AST: instance Data.Data.Data a => Data.Data.Data (Language.Fortran.AST.ProcInterface a)
+ Language.Fortran.AST: instance Data.Data.Data a => Data.Data.Data (Language.Fortran.AST.Suffix a)
+ Language.Fortran.AST: instance GHC.Base.Functor Language.Fortran.AST.AllocOpt
+ Language.Fortran.AST: instance GHC.Base.Functor Language.Fortran.AST.FlushSpec
+ Language.Fortran.AST: instance GHC.Base.Functor Language.Fortran.AST.Prefix
+ Language.Fortran.AST: instance GHC.Base.Functor Language.Fortran.AST.ProcDecl
+ Language.Fortran.AST: instance GHC.Base.Functor Language.Fortran.AST.ProcInterface
+ Language.Fortran.AST: instance GHC.Base.Functor Language.Fortran.AST.Suffix
+ Language.Fortran.AST: instance GHC.Classes.Eq Language.Fortran.AST.CharacterLen
+ Language.Fortran.AST: instance GHC.Classes.Eq Language.Fortran.AST.ModuleNature
+ Language.Fortran.AST: instance GHC.Classes.Eq a => GHC.Classes.Eq (Language.Fortran.AST.AllocOpt a)
+ Language.Fortran.AST: instance GHC.Classes.Eq a => GHC.Classes.Eq (Language.Fortran.AST.FlushSpec a)
+ Language.Fortran.AST: instance GHC.Classes.Eq a => GHC.Classes.Eq (Language.Fortran.AST.Prefix a)
+ Language.Fortran.AST: instance GHC.Classes.Eq a => GHC.Classes.Eq (Language.Fortran.AST.ProcDecl a)
+ Language.Fortran.AST: instance GHC.Classes.Eq a => GHC.Classes.Eq (Language.Fortran.AST.ProcInterface a)
+ Language.Fortran.AST: instance GHC.Classes.Eq a => GHC.Classes.Eq (Language.Fortran.AST.Suffix a)
+ Language.Fortran.AST: instance GHC.Classes.Ord Language.Fortran.AST.BinaryOp
+ Language.Fortran.AST: instance GHC.Classes.Ord Language.Fortran.AST.CharacterLen
+ Language.Fortran.AST: instance GHC.Classes.Ord Language.Fortran.AST.UnaryOp
+ Language.Fortran.AST: instance GHC.Generics.Generic (Language.Fortran.AST.AllocOpt a)
+ Language.Fortran.AST: instance GHC.Generics.Generic (Language.Fortran.AST.FlushSpec a)
+ Language.Fortran.AST: instance GHC.Generics.Generic (Language.Fortran.AST.Prefix a)
+ Language.Fortran.AST: instance GHC.Generics.Generic (Language.Fortran.AST.ProcDecl a)
+ Language.Fortran.AST: instance GHC.Generics.Generic (Language.Fortran.AST.ProcInterface a)
+ Language.Fortran.AST: instance GHC.Generics.Generic (Language.Fortran.AST.Suffix a)
+ Language.Fortran.AST: instance GHC.Generics.Generic Language.Fortran.AST.CharacterLen
+ Language.Fortran.AST: instance GHC.Generics.Generic Language.Fortran.AST.ModuleNature
+ Language.Fortran.AST: instance GHC.Show.Show Language.Fortran.AST.CharacterLen
+ Language.Fortran.AST: instance GHC.Show.Show Language.Fortran.AST.ModuleNature
+ Language.Fortran.AST: instance GHC.Show.Show a => GHC.Show.Show (Language.Fortran.AST.AllocOpt a)
+ Language.Fortran.AST: instance GHC.Show.Show a => GHC.Show.Show (Language.Fortran.AST.FlushSpec a)
+ Language.Fortran.AST: instance GHC.Show.Show a => GHC.Show.Show (Language.Fortran.AST.Prefix a)
+ Language.Fortran.AST: instance GHC.Show.Show a => GHC.Show.Show (Language.Fortran.AST.ProcDecl a)
+ Language.Fortran.AST: instance GHC.Show.Show a => GHC.Show.Show (Language.Fortran.AST.ProcInterface a)
+ Language.Fortran.AST: instance GHC.Show.Show a => GHC.Show.Show (Language.Fortran.AST.Suffix a)
+ Language.Fortran.AST: instance Language.Fortran.AST.Annotated Language.Fortran.AST.AllocOpt
+ Language.Fortran.AST: instance Language.Fortran.AST.Annotated Language.Fortran.AST.FlushSpec
+ Language.Fortran.AST: instance Language.Fortran.AST.Annotated Language.Fortran.AST.ProcDecl
+ Language.Fortran.AST: instance Language.Fortran.AST.Annotated Language.Fortran.AST.ProcInterface
+ Language.Fortran.AST: instance Language.Fortran.Util.FirstParameter.FirstParameter (Language.Fortran.AST.AllocOpt a) a
+ Language.Fortran.AST: instance Language.Fortran.Util.FirstParameter.FirstParameter (Language.Fortran.AST.FlushSpec a) a
+ Language.Fortran.AST: instance Language.Fortran.Util.FirstParameter.FirstParameter (Language.Fortran.AST.Prefix a) a
+ Language.Fortran.AST: instance Language.Fortran.Util.FirstParameter.FirstParameter (Language.Fortran.AST.ProcDecl a) a
+ Language.Fortran.AST: instance Language.Fortran.Util.FirstParameter.FirstParameter (Language.Fortran.AST.ProcInterface a) a
+ Language.Fortran.AST: instance Language.Fortran.Util.FirstParameter.FirstParameter (Language.Fortran.AST.Suffix a) a
+ Language.Fortran.AST: instance Language.Fortran.Util.Position.Spanned (Language.Fortran.AST.AllocOpt a)
+ Language.Fortran.AST: instance Language.Fortran.Util.Position.Spanned (Language.Fortran.AST.FlushSpec a)
+ Language.Fortran.AST: instance Language.Fortran.Util.Position.Spanned (Language.Fortran.AST.Prefix a)
+ Language.Fortran.AST: instance Language.Fortran.Util.Position.Spanned (Language.Fortran.AST.ProcDecl a)
+ Language.Fortran.AST: instance Language.Fortran.Util.Position.Spanned (Language.Fortran.AST.ProcInterface a)
+ Language.Fortran.AST: instance Language.Fortran.Util.Position.Spanned (Language.Fortran.AST.Suffix a)
+ Language.Fortran.AST: instance Language.Fortran.Util.SecondParameter.SecondParameter (Language.Fortran.AST.AllocOpt a) Language.Fortran.Util.Position.SrcSpan
+ Language.Fortran.AST: instance Language.Fortran.Util.SecondParameter.SecondParameter (Language.Fortran.AST.FlushSpec a) Language.Fortran.Util.Position.SrcSpan
+ Language.Fortran.AST: instance Language.Fortran.Util.SecondParameter.SecondParameter (Language.Fortran.AST.Prefix a) Language.Fortran.Util.Position.SrcSpan
+ Language.Fortran.AST: instance Language.Fortran.Util.SecondParameter.SecondParameter (Language.Fortran.AST.ProcDecl a) Language.Fortran.Util.Position.SrcSpan
+ Language.Fortran.AST: instance Language.Fortran.Util.SecondParameter.SecondParameter (Language.Fortran.AST.ProcInterface a) Language.Fortran.Util.Position.SrcSpan
+ Language.Fortran.AST: instance Language.Fortran.Util.SecondParameter.SecondParameter (Language.Fortran.AST.Suffix a) Language.Fortran.Util.Position.SrcSpan
+ Language.Fortran.AST: instance Text.PrettyPrint.GenericPretty.Out Language.Fortran.AST.CharacterLen
+ Language.Fortran.AST: instance Text.PrettyPrint.GenericPretty.Out Language.Fortran.AST.ModuleNature
+ Language.Fortran.AST: instance Text.PrettyPrint.GenericPretty.Out a => Text.PrettyPrint.GenericPretty.Out (Language.Fortran.AST.AllocOpt a)
+ Language.Fortran.AST: instance Text.PrettyPrint.GenericPretty.Out a => Text.PrettyPrint.GenericPretty.Out (Language.Fortran.AST.FlushSpec a)
+ Language.Fortran.AST: instance Text.PrettyPrint.GenericPretty.Out a => Text.PrettyPrint.GenericPretty.Out (Language.Fortran.AST.Prefix a)
+ Language.Fortran.AST: instance Text.PrettyPrint.GenericPretty.Out a => Text.PrettyPrint.GenericPretty.Out (Language.Fortran.AST.ProcDecl a)
+ Language.Fortran.AST: instance Text.PrettyPrint.GenericPretty.Out a => Text.PrettyPrint.GenericPretty.Out (Language.Fortran.AST.ProcInterface a)
+ Language.Fortran.AST: instance Text.PrettyPrint.GenericPretty.Out a => Text.PrettyPrint.GenericPretty.Out (Language.Fortran.AST.Suffix a)
+ Language.Fortran.AST: type PrefixSuffix a = (Prefixes a, Suffixes a)
+ Language.Fortran.AST: type Prefixes a = Maybe (AList Prefix a)
+ Language.Fortran.AST: type Suffixes a = Maybe (AList Suffix a)
+ Language.Fortran.AST: validPrefixSuffix :: PrefixSuffix a -> Bool
+ Language.Fortran.Analysis: BBGr :: Gr (BB a) () -> [Node] -> [Node] -> BBGr a
+ Language.Fortran.Analysis: ClassCustom :: String -> BaseType
+ Language.Fortran.Analysis: ClassStar :: BaseType
+ Language.Fortran.Analysis: ConstBinary :: BinaryOp -> Constant -> Constant -> Constant
+ Language.Fortran.Analysis: ConstInt :: Integer -> Constant
+ Language.Fortran.Analysis: ConstUnary :: UnaryOp -> Constant -> Constant
+ Language.Fortran.Analysis: ConstUninterpInt :: String -> Constant
+ Language.Fortran.Analysis: ConstUninterpReal :: String -> Constant
+ Language.Fortran.Analysis: [bbgrEntries] :: BBGr a -> [Node]
+ Language.Fortran.Analysis: [bbgrExits] :: BBGr a -> [Node]
+ Language.Fortran.Analysis: [bbgrGr] :: BBGr a -> Gr (BB a) ()
+ Language.Fortran.Analysis: [constExp] :: Analysis a -> Maybe Constant
+ Language.Fortran.Analysis: bbgrEmpty :: BBGr a
+ Language.Fortran.Analysis: bbgrMap :: (Gr (BB a) () -> Gr (BB b) ()) -> BBGr a -> BBGr b
+ Language.Fortran.Analysis: bbgrMapM :: Monad m => (Gr (BB a1) () -> m (Gr (BB a2) ())) -> BBGr a1 -> m (BBGr a2)
+ Language.Fortran.Analysis: data BBGr a
+ Language.Fortran.Analysis: data Constant
+ Language.Fortran.Analysis: instance Data.Binary.Class.Binary Language.Fortran.Analysis.Constant
+ Language.Fortran.Analysis: instance Data.Data.Data Language.Fortran.Analysis.Constant
+ Language.Fortran.Analysis: instance Data.Data.Data a => Data.Data.Data (Language.Fortran.Analysis.BBGr a)
+ Language.Fortran.Analysis: instance GHC.Classes.Eq Language.Fortran.Analysis.Constant
+ Language.Fortran.Analysis: instance GHC.Classes.Eq a => GHC.Classes.Eq (Language.Fortran.Analysis.BBGr a)
+ Language.Fortran.Analysis: instance GHC.Classes.Ord Language.Fortran.Analysis.Constant
+ Language.Fortran.Analysis: instance GHC.Generics.Generic (Language.Fortran.Analysis.BBGr a)
+ Language.Fortran.Analysis: instance GHC.Generics.Generic Language.Fortran.Analysis.Constant
+ Language.Fortran.Analysis: instance GHC.Show.Show Language.Fortran.Analysis.Constant
+ Language.Fortran.Analysis: instance GHC.Show.Show a => GHC.Show.Show (Language.Fortran.Analysis.BBGr a)
+ Language.Fortran.Analysis: instance Text.PrettyPrint.GenericPretty.Out Language.Fortran.Analysis.Constant
+ Language.Fortran.Analysis: type BBNode = Int
+ Language.Fortran.Analysis.BBlocks: SuperBBGr :: BBGr a -> IntMap ProgramUnitName -> Map PUName SuperNode -> SuperBBGr a
+ Language.Fortran.Analysis.BBlocks: [superBBGrClusters] :: SuperBBGr a -> IntMap ProgramUnitName
+ Language.Fortran.Analysis.BBlocks: [superBBGrEntries] :: SuperBBGr a -> Map PUName SuperNode
+ Language.Fortran.Analysis.BBlocks: [superBBGrGraph] :: SuperBBGr a -> BBGr a
+ Language.Fortran.Analysis.BBlocks: showBlock :: Block a -> String
+ Language.Fortran.Analysis.BBlocks: type ASTBlockNode = Int
+ Language.Fortran.Analysis.BBlocks: type ASTExprNode = Int
+ Language.Fortran.Analysis.DataFlow: ConstBinary :: BinaryOp -> Constant -> Constant -> Constant
+ Language.Fortran.Analysis.DataFlow: ConstInt :: Integer -> Constant
+ Language.Fortran.Analysis.DataFlow: ConstUnary :: UnaryOp -> Constant -> Constant
+ Language.Fortran.Analysis.DataFlow: ConstUninterpInt :: String -> Constant
+ Language.Fortran.Analysis.DataFlow: ConstUninterpReal :: String -> Constant
+ Language.Fortran.Analysis.DataFlow: analyseConstExps :: forall a. Data a => ProgramFile (Analysis a) -> ProgramFile (Analysis a)
+ Language.Fortran.Analysis.DataFlow: analyseParameterVars :: forall a. Data a => ParameterVarMap -> ProgramFile (Analysis a) -> ProgramFile (Analysis a)
+ Language.Fortran.Analysis.DataFlow: data Constant
+ Language.Fortran.Analysis.DataFlow: genConstExpMap :: forall a. Data a => ProgramFile (Analysis a) -> ConstExpMap
+ Language.Fortran.Analysis.DataFlow: showFlowsDOT :: (Data a, Out a, Show a) => ProgramFile (Analysis a) -> BBGr (Analysis a) -> ASTBlockNode -> Bool -> String
+ Language.Fortran.Analysis.DataFlow: type ASTBlockNodeMap = IntMap
+ Language.Fortran.Analysis.DataFlow: type ASTBlockNodeSet = IntSet
+ Language.Fortran.Analysis.DataFlow: type ASTExprNodeMap = IntMap
+ Language.Fortran.Analysis.DataFlow: type ASTExprNodeSet = IntSet
+ Language.Fortran.Analysis.DataFlow: type BBNodeMap = IntMap
+ Language.Fortran.Analysis.DataFlow: type BBNodeSet = IntSet
+ Language.Fortran.Analysis.DataFlow: type ConstExpMap = ASTExprNodeMap (Maybe Constant)
+ Language.Fortran.Analysis.DataFlow: type ParameterVarMap = Map Name Constant
+ Language.Fortran.Analysis.Types: analyseAndCheckTypesWithEnv :: Data a => TypeEnv -> ProgramFile (Analysis a) -> (ProgramFile (Analysis a), TypeEnv, [TypeError])
+ Language.Fortran.Analysis.Types: type TypeError = (String, SrcSpan)
+ Language.Fortran.Lexer.FreeForm: TAbstract :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TAsynchronous :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TBind :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TC :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TClass :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TEndEnum :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TEnum :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TEnumerator :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TErr :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TErrMsg :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TFlush :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TIOMsg :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TIOStat :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TImport :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TName :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TNonIntrinsic :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TProcedure :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TProtected :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TSource :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TStat :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TUnit :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TValue :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: TVolatile :: SrcSpan -> Token
+ Language.Fortran.Lexer.FreeForm: alex_action_160 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_161 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_162 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_163 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_164 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_165 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_166 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_167 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_168 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_169 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_170 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_171 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_172 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_173 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_174 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_175 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_176 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_177 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_178 :: Parse AlexInput Token (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_179 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_180 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_181 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_182 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_183 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_184 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_185 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_186 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_187 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_188 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_189 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_190 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_191 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_192 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_193 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_194 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_195 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_196 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_197 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_198 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_199 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_2 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_200 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_201 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_202 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: alex_action_203 :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: allocateP :: User -> AlexInput -> Int -> AlexInput -> Bool
+ Language.Fortran.Lexer.FreeForm: bindP :: User -> AlexInput -> Int -> AlexInput -> Bool
+ Language.Fortran.Lexer.FreeForm: followsBindP :: User -> AlexInput -> Int -> AlexInput -> Bool
+ Language.Fortran.Lexer.FreeForm: followsCP :: User -> AlexInput -> Int -> AlexInput -> Bool
+ Language.Fortran.Lexer.FreeForm: followsFlushP :: User -> AlexInput -> Int -> AlexInput -> Bool
+ Language.Fortran.Lexer.FreeForm: followsProcedureP :: User -> AlexInput -> Int -> AlexInput -> Bool
+ Language.Fortran.Lexer.FreeForm: labelledWhereP :: User -> AlexInput -> Int -> AlexInput -> Bool
+ Language.Fortran.Lexer.FreeForm: lexHash :: LexAction (Maybe Token)
+ Language.Fortran.Lexer.FreeForm: parenLevel :: [Token] -> Int
+ Language.Fortran.Lexer.FreeForm: skipCComment :: LexAction (Maybe Token)
+ Language.Fortran.Parser.Any: fortranParserWithModFilesAndVersion :: FortranVersion -> ParserWithModFiles
+ Language.Fortran.Parser.Any: fortranParserWithVersion :: FortranVersion -> Parser
+ Language.Fortran.Parser.Fortran2003: fortran2003Parser :: ByteString -> String -> ParseResult AlexInput Token (ProgramFile A0)
+ Language.Fortran.Parser.Fortran2003: fortran2003ParserWithModFiles :: ModFiles -> ByteString -> String -> ParseResult AlexInput Token (ProgramFile A0)
+ Language.Fortran.Parser.Fortran2003: functionParser :: LexAction (ProgramUnit A0)
+ Language.Fortran.Parser.Fortran2003: statementParser :: LexAction (Statement A0)
+ Language.Fortran.ParserMonad: fortranVersionAliases :: [(String, FortranVersion)]
+ Language.Fortran.ParserMonad: instance (Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable b, GHC.Show.Show a, GHC.Show.Show b) => GHC.Exception.Type.Exception (Language.Fortran.ParserMonad.ParseError a b)
+ Language.Fortran.ParserMonad: selectFortranVersion :: String -> Maybe FortranVersion
+ Language.Fortran.PrettyPrint: instance Language.Fortran.PrettyPrint.IndentablePretty a => Language.Fortran.PrettyPrint.IndentablePretty (GHC.Maybe.Maybe a)
+ Language.Fortran.PrettyPrint: instance Language.Fortran.PrettyPrint.Pretty (Language.Fortran.AST.AllocOpt a)
+ Language.Fortran.PrettyPrint: instance Language.Fortran.PrettyPrint.Pretty (Language.Fortran.AST.FlushSpec a)
+ Language.Fortran.PrettyPrint: instance Language.Fortran.PrettyPrint.Pretty (Language.Fortran.AST.ProcDecl a)
+ Language.Fortran.PrettyPrint: instance Language.Fortran.PrettyPrint.Pretty (Language.Fortran.AST.ProcInterface a)
+ Language.Fortran.PrettyPrint: instance Language.Fortran.PrettyPrint.Pretty (Language.Fortran.AST.Suffix a)
+ Language.Fortran.PrettyPrint: instance Language.Fortran.PrettyPrint.Pretty Language.Fortran.AST.CharacterLen
+ Language.Fortran.PrettyPrint: instance Language.Fortran.PrettyPrint.Pretty a => Language.Fortran.PrettyPrint.Pretty (GHC.Maybe.Maybe a)
+ Language.Fortran.Util.ModFile: combinedParamVarMap :: ModFiles -> ParamVarMap
+ Language.Fortran.Util.ModFile: combinedStringMap :: ModFiles -> StringMap
+ Language.Fortran.Util.ModFile: type ParamVarMap = ParameterVarMap
+ Language.Fortran.Util.ModFile: type StringMap = Map String String
+ Language.Fortran.Util.Position: [filePath] :: Position -> String
+ Language.Fortran.Util.Position: [posPragmaOffset] :: Position -> Maybe (Int, String)
+ Language.Fortran.Util.Position: apparentFilePath :: Position -> String
+ Language.Fortran.Util.Position: apparentLineCol :: Position -> (Int, Int)
+ Language.Fortran.Util.Position: spannedLines :: SrcSpan -> [Int]
- Language.Fortran.AST: Argument :: a -> SrcSpan -> (Maybe String) -> (Expression a) -> Argument a
+ Language.Fortran.AST: Argument :: a -> SrcSpan -> Maybe String -> Expression a -> Argument a
- Language.Fortran.AST: AttrDimension :: a -> SrcSpan -> (AList DimensionDeclarator a) -> Attribute a
+ Language.Fortran.AST: AttrDimension :: a -> SrcSpan -> AList DimensionDeclarator a -> Attribute a
- Language.Fortran.AST: BlCase :: a -> SrcSpan -> (Maybe (Expression a)) -> (Maybe String) -> (Expression a) -> [Maybe (AList Index a)] -> [[Block a]] -> (Maybe (Expression a)) -> Block a
+ Language.Fortran.AST: BlCase :: a -> SrcSpan -> Maybe (Expression a) -> Maybe String -> Expression a -> [Maybe (AList Index a)] -> [[Block a]] -> Maybe (Expression a) -> Block a
- Language.Fortran.AST: BlComment :: a -> SrcSpan -> (Comment a) -> Block a
+ Language.Fortran.AST: BlComment :: a -> SrcSpan -> Comment a -> Block a
- Language.Fortran.AST: BlDo :: a -> SrcSpan -> (Maybe (Expression a)) -> (Maybe String) -> (Maybe (Expression a)) -> (Maybe (DoSpecification a)) -> [Block a] -> (Maybe (Expression a)) -> Block a
+ Language.Fortran.AST: BlDo :: a -> SrcSpan -> Maybe (Expression a) -> Maybe String -> Maybe (Expression a) -> Maybe (DoSpecification a) -> [Block a] -> Maybe (Expression a) -> Block a
- Language.Fortran.AST: BlDoWhile :: a -> SrcSpan -> (Maybe (Expression a)) -> (Maybe String) -> (Maybe (Expression a)) -> (Expression a) -> [Block a] -> (Maybe (Expression a)) -> Block a
+ Language.Fortran.AST: BlDoWhile :: a -> SrcSpan -> Maybe (Expression a) -> Maybe String -> Maybe (Expression a) -> Expression a -> [Block a] -> Maybe (Expression a) -> Block a
- Language.Fortran.AST: BlForall :: a -> SrcSpan -> (Maybe (Expression a)) -> (Maybe String) -> (ForallHeader a) -> [Block a] -> (Maybe (Expression a)) -> Block a
+ Language.Fortran.AST: BlForall :: a -> SrcSpan -> Maybe (Expression a) -> Maybe String -> ForallHeader a -> [Block a] -> Maybe (Expression a) -> Block a
- Language.Fortran.AST: BlIf :: a -> SrcSpan -> (Maybe (Expression a)) -> (Maybe String) -> [Maybe (Expression a)] -> [[Block a]] -> (Maybe (Expression a)) -> Block a
+ Language.Fortran.AST: BlIf :: a -> SrcSpan -> Maybe (Expression a) -> Maybe String -> [Maybe (Expression a)] -> [[Block a]] -> Maybe (Expression a) -> Block a
- Language.Fortran.AST: BlInterface :: a -> SrcSpan -> (Maybe (Expression a)) -> [ProgramUnit a] -> [Block a] -> Block a
+ Language.Fortran.AST: BlInterface :: a -> SrcSpan -> Maybe (Expression a) -> Bool -> [ProgramUnit a] -> [Block a] -> Block a
- Language.Fortran.AST: BlStatement :: a -> SrcSpan -> (Maybe (Expression a)) -> (Statement a) -> Block a
+ Language.Fortran.AST: BlStatement :: a -> SrcSpan -> Maybe (Expression a) -> Statement a -> Block a
- Language.Fortran.AST: CommonGroup :: a -> SrcSpan -> (Maybe (Expression a)) -> (AList Expression a) -> CommonGroup a
+ Language.Fortran.AST: CommonGroup :: a -> SrcSpan -> Maybe (Expression a) -> AList Expression a -> CommonGroup a
- Language.Fortran.AST: ControlPair :: a -> SrcSpan -> (Maybe String) -> (Expression a) -> ControlPair a
+ Language.Fortran.AST: ControlPair :: a -> SrcSpan -> Maybe String -> Expression a -> ControlPair a
- Language.Fortran.AST: DataGroup :: a -> SrcSpan -> (AList Expression a) -> (AList Expression a) -> DataGroup a
+ Language.Fortran.AST: DataGroup :: a -> SrcSpan -> AList Expression a -> AList Expression a -> DataGroup a
- Language.Fortran.AST: DeclArray :: a -> SrcSpan -> (Expression a) -> (AList DimensionDeclarator a) -> (Maybe (Expression a)) -> (Maybe (Expression a)) -> Declarator a
+ Language.Fortran.AST: DeclArray :: a -> SrcSpan -> Expression a -> AList DimensionDeclarator a -> Maybe (Expression a) -> Maybe (Expression a) -> Declarator a
- Language.Fortran.AST: DeclVariable :: a -> SrcSpan -> (Expression a) -> (Maybe (Expression a)) -> (Maybe (Expression a)) -> Declarator a
+ Language.Fortran.AST: DeclVariable :: a -> SrcSpan -> Expression a -> Maybe (Expression a) -> Maybe (Expression a) -> Declarator a
- Language.Fortran.AST: DimensionDeclarator :: a -> SrcSpan -> (Maybe (Expression a)) -> (Maybe (Expression a)) -> DimensionDeclarator a
+ Language.Fortran.AST: DimensionDeclarator :: a -> SrcSpan -> Maybe (Expression a) -> Maybe (Expression a) -> DimensionDeclarator a
- Language.Fortran.AST: DoSpecification :: a -> SrcSpan -> (Statement a) -> (Expression a) -> (Maybe (Expression a)) -> DoSpecification a
+ Language.Fortran.AST: DoSpecification :: a -> SrcSpan -> Statement a -> Expression a -> Maybe (Expression a) -> DoSpecification a
- Language.Fortran.AST: ExpBinary :: a -> SrcSpan -> BinaryOp -> (Expression a) -> (Expression a) -> Expression a
+ Language.Fortran.AST: ExpBinary :: a -> SrcSpan -> BinaryOp -> Expression a -> Expression a -> Expression a
- Language.Fortran.AST: ExpDataRef :: a -> SrcSpan -> (Expression a) -> (Expression a) -> Expression a
+ Language.Fortran.AST: ExpDataRef :: a -> SrcSpan -> Expression a -> Expression a -> Expression a
- Language.Fortran.AST: ExpFunctionCall :: a -> SrcSpan -> (Expression a) -> (Maybe (AList Argument a)) -> Expression a
+ Language.Fortran.AST: ExpFunctionCall :: a -> SrcSpan -> Expression a -> Maybe (AList Argument a) -> Expression a
- Language.Fortran.AST: ExpImpliedDo :: a -> SrcSpan -> (AList Expression a) -> (DoSpecification a) -> Expression a
+ Language.Fortran.AST: ExpImpliedDo :: a -> SrcSpan -> AList Expression a -> DoSpecification a -> Expression a
- Language.Fortran.AST: ExpInitialisation :: a -> SrcSpan -> (AList Expression a) -> Expression a
+ Language.Fortran.AST: ExpInitialisation :: a -> SrcSpan -> AList Expression a -> Expression a
- Language.Fortran.AST: ExpReturnSpec :: a -> SrcSpan -> (Expression a) -> Expression a
+ Language.Fortran.AST: ExpReturnSpec :: a -> SrcSpan -> Expression a -> Expression a
- Language.Fortran.AST: ExpSubscript :: a -> SrcSpan -> (Expression a) -> (AList Index a) -> Expression a
+ Language.Fortran.AST: ExpSubscript :: a -> SrcSpan -> Expression a -> AList Index a -> Expression a
- Language.Fortran.AST: ExpUnary :: a -> SrcSpan -> UnaryOp -> (Expression a) -> Expression a
+ Language.Fortran.AST: ExpUnary :: a -> SrcSpan -> UnaryOp -> Expression a -> Expression a
- Language.Fortran.AST: ExpValue :: a -> SrcSpan -> (Value a) -> Expression a
+ Language.Fortran.AST: ExpValue :: a -> SrcSpan -> Value a -> Expression a
- Language.Fortran.AST: FIFieldDescriptorAIL :: a -> SrcSpan -> (Maybe Integer) -> Char -> Integer -> FormatItem a
+ Language.Fortran.AST: FIFieldDescriptorAIL :: a -> SrcSpan -> Maybe Integer -> Char -> Integer -> FormatItem a
- Language.Fortran.AST: FIFieldDescriptorDEFG :: a -> SrcSpan -> (Maybe Integer) -> Char -> Integer -> Integer -> FormatItem a
+ Language.Fortran.AST: FIFieldDescriptorDEFG :: a -> SrcSpan -> Maybe Integer -> Char -> Integer -> Integer -> FormatItem a
- Language.Fortran.AST: FIFormatList :: a -> SrcSpan -> (Maybe String) -> (AList FormatItem a) -> FormatItem a
+ Language.Fortran.AST: FIFormatList :: a -> SrcSpan -> Maybe String -> AList FormatItem a -> FormatItem a
- Language.Fortran.AST: FIHollerith :: a -> SrcSpan -> (Value a) -> FormatItem a
+ Language.Fortran.AST: FIHollerith :: a -> SrcSpan -> Value a -> FormatItem a
- Language.Fortran.AST: ForallHeader :: [(Name, Expression a, Expression a, Maybe (Expression a))] -> (Maybe (Expression a)) -> ForallHeader a
+ Language.Fortran.AST: ForallHeader :: [(Name, Expression a, Expression a, Maybe (Expression a))] -> Maybe (Expression a) -> ForallHeader a
- Language.Fortran.AST: ImpList :: a -> SrcSpan -> (TypeSpec a) -> (AList ImpElement a) -> ImpList a
+ Language.Fortran.AST: ImpList :: a -> SrcSpan -> TypeSpec a -> AList ImpElement a -> ImpList a
- Language.Fortran.AST: IxRange :: a -> SrcSpan -> (Maybe (Expression a)) -> (Maybe (Expression a)) -> (Maybe (Expression a)) -> Index a
+ Language.Fortran.AST: IxRange :: a -> SrcSpan -> Maybe (Expression a) -> Maybe (Expression a) -> Maybe (Expression a) -> Index a
- Language.Fortran.AST: IxSingle :: a -> SrcSpan -> (Maybe String) -> (Expression a) -> Index a
+ Language.Fortran.AST: IxSingle :: a -> SrcSpan -> Maybe String -> Expression a -> Index a
- Language.Fortran.AST: Namelist :: a -> SrcSpan -> (Expression a) -> (AList Expression a) -> Namelist a
+ Language.Fortran.AST: Namelist :: a -> SrcSpan -> Expression a -> AList Expression a -> Namelist a
- Language.Fortran.AST: PUBlockData :: a -> SrcSpan -> (Maybe Name) -> [Block a] -> ProgramUnit a
+ Language.Fortran.AST: PUBlockData :: a -> SrcSpan -> Maybe Name -> [Block a] -> ProgramUnit a
- Language.Fortran.AST: PUComment :: a -> SrcSpan -> (Comment a) -> ProgramUnit a
+ Language.Fortran.AST: PUComment :: a -> SrcSpan -> Comment a -> ProgramUnit a
- Language.Fortran.AST: PUFunction :: a -> SrcSpan -> (Maybe (TypeSpec a)) -> (PUFunctionOpt a) -> Name -> (Maybe (AList Expression a)) -> (Maybe (Expression a)) -> [Block a] -> (Maybe [ProgramUnit a]) -> ProgramUnit a
+ Language.Fortran.AST: PUFunction :: a -> SrcSpan -> Maybe (TypeSpec a) -> PrefixSuffix a -> Name -> Maybe (AList Expression a) -> Maybe (Expression a) -> [Block a] -> Maybe [ProgramUnit a] -> ProgramUnit a
- Language.Fortran.AST: PUMain :: a -> SrcSpan -> (Maybe Name) -> [Block a] -> (Maybe [ProgramUnit a]) -> ProgramUnit a
+ Language.Fortran.AST: PUMain :: a -> SrcSpan -> Maybe Name -> [Block a] -> Maybe [ProgramUnit a] -> ProgramUnit a
- Language.Fortran.AST: PUModule :: a -> SrcSpan -> Name -> [Block a] -> (Maybe [ProgramUnit a]) -> ProgramUnit a
+ Language.Fortran.AST: PUModule :: a -> SrcSpan -> Name -> [Block a] -> Maybe [ProgramUnit a] -> ProgramUnit a
- Language.Fortran.AST: PUSubroutine :: a -> SrcSpan -> (PUFunctionOpt a) -> Name -> (Maybe (AList Expression a)) -> [Block a] -> (Maybe [ProgramUnit a]) -> ProgramUnit a
+ Language.Fortran.AST: PUSubroutine :: a -> SrcSpan -> PrefixSuffix a -> Name -> Maybe (AList Expression a) -> [Block a] -> Maybe [ProgramUnit a] -> ProgramUnit a
- Language.Fortran.AST: Selector :: a -> SrcSpan -> (Maybe (Expression a)) -> (Maybe (Expression a)) -> Selector a
+ Language.Fortran.AST: Selector :: a -> SrcSpan -> Maybe (Expression a) -> Maybe (Expression a) -> Selector a
- Language.Fortran.AST: StAllocatable :: a -> SrcSpan -> (AList Declarator a) -> Statement a
+ Language.Fortran.AST: StAllocatable :: a -> SrcSpan -> AList Declarator a -> Statement a
- Language.Fortran.AST: StAllocate :: a -> SrcSpan -> (AList Expression a) -> (Maybe (ControlPair a)) -> Statement a
+ Language.Fortran.AST: StAllocate :: a -> SrcSpan -> Maybe (TypeSpec a) -> AList Expression a -> Maybe (AList AllocOpt a) -> Statement a
- Language.Fortran.AST: StAutomatic :: a -> SrcSpan -> (AList Declarator a) -> Statement a
+ Language.Fortran.AST: StAutomatic :: a -> SrcSpan -> AList Declarator a -> Statement a
- Language.Fortran.AST: StBackspace :: a -> SrcSpan -> (AList ControlPair a) -> Statement a
+ Language.Fortran.AST: StBackspace :: a -> SrcSpan -> AList ControlPair a -> Statement a
- Language.Fortran.AST: StBackspace2 :: a -> SrcSpan -> (Expression a) -> Statement a
+ Language.Fortran.AST: StBackspace2 :: a -> SrcSpan -> Expression a -> Statement a
- Language.Fortran.AST: StCall :: a -> SrcSpan -> (Expression a) -> (Maybe (AList Argument a)) -> Statement a
+ Language.Fortran.AST: StCall :: a -> SrcSpan -> Expression a -> Maybe (AList Argument a) -> Statement a
- Language.Fortran.AST: StCase :: a -> SrcSpan -> (Maybe String) -> (Maybe (AList Index a)) -> Statement a
+ Language.Fortran.AST: StCase :: a -> SrcSpan -> Maybe String -> Maybe (AList Index a) -> Statement a
- Language.Fortran.AST: StClose :: a -> SrcSpan -> (AList ControlPair a) -> Statement a
+ Language.Fortran.AST: StClose :: a -> SrcSpan -> AList ControlPair a -> Statement a
- Language.Fortran.AST: StCommon :: a -> SrcSpan -> (AList CommonGroup a) -> Statement a
+ Language.Fortran.AST: StCommon :: a -> SrcSpan -> AList CommonGroup a -> Statement a
- Language.Fortran.AST: StCycle :: a -> SrcSpan -> (Maybe (Expression a)) -> Statement a
+ Language.Fortran.AST: StCycle :: a -> SrcSpan -> Maybe (Expression a) -> Statement a
- Language.Fortran.AST: StData :: a -> SrcSpan -> (AList DataGroup a) -> Statement a
+ Language.Fortran.AST: StData :: a -> SrcSpan -> AList DataGroup a -> Statement a
- Language.Fortran.AST: StDeallocate :: a -> SrcSpan -> (AList Expression a) -> (Maybe (ControlPair a)) -> Statement a
+ Language.Fortran.AST: StDeallocate :: a -> SrcSpan -> AList Expression a -> Maybe (AList AllocOpt a) -> Statement a
- Language.Fortran.AST: StDeclaration :: a -> SrcSpan -> (TypeSpec a) -> (Maybe (AList Attribute a)) -> (AList Declarator a) -> Statement a
+ Language.Fortran.AST: StDeclaration :: a -> SrcSpan -> TypeSpec a -> Maybe (AList Attribute a) -> AList Declarator a -> Statement a
- Language.Fortran.AST: StDimension :: a -> SrcSpan -> (AList Declarator a) -> Statement a
+ Language.Fortran.AST: StDimension :: a -> SrcSpan -> AList Declarator a -> Statement a
- Language.Fortran.AST: StDo :: a -> SrcSpan -> (Maybe String) -> (Maybe (Expression a)) -> (Maybe (DoSpecification a)) -> Statement a
+ Language.Fortran.AST: StDo :: a -> SrcSpan -> Maybe String -> Maybe (Expression a) -> Maybe (DoSpecification a) -> Statement a
- Language.Fortran.AST: StDoWhile :: a -> SrcSpan -> (Maybe String) -> (Maybe (Expression a)) -> (Expression a) -> Statement a
+ Language.Fortran.AST: StDoWhile :: a -> SrcSpan -> Maybe String -> Maybe (Expression a) -> Expression a -> Statement a
- Language.Fortran.AST: StElse :: a -> SrcSpan -> (Maybe String) -> Statement a
+ Language.Fortran.AST: StElse :: a -> SrcSpan -> Maybe String -> Statement a
- Language.Fortran.AST: StElsewhere :: a -> SrcSpan -> Statement a
+ Language.Fortran.AST: StElsewhere :: a -> SrcSpan -> Maybe String -> Maybe (Expression a) -> Statement a
- Language.Fortran.AST: StElsif :: a -> SrcSpan -> (Maybe String) -> (Expression a) -> Statement a
+ Language.Fortran.AST: StElsif :: a -> SrcSpan -> Maybe String -> Expression a -> Statement a
- Language.Fortran.AST: StEndForall :: a -> SrcSpan -> (Maybe String) -> Statement a
+ Language.Fortran.AST: StEndForall :: a -> SrcSpan -> Maybe String -> Statement a
- Language.Fortran.AST: StEndType :: a -> SrcSpan -> (Maybe String) -> Statement a
+ Language.Fortran.AST: StEndType :: a -> SrcSpan -> Maybe String -> Statement a
- Language.Fortran.AST: StEndWhere :: a -> SrcSpan -> Statement a
+ Language.Fortran.AST: StEndWhere :: a -> SrcSpan -> Maybe String -> Statement a
- Language.Fortran.AST: StEndcase :: a -> SrcSpan -> (Maybe String) -> Statement a
+ Language.Fortran.AST: StEndcase :: a -> SrcSpan -> Maybe String -> Statement a
- Language.Fortran.AST: StEnddo :: a -> SrcSpan -> (Maybe String) -> Statement a
+ Language.Fortran.AST: StEnddo :: a -> SrcSpan -> Maybe String -> Statement a
- Language.Fortran.AST: StEndfile :: a -> SrcSpan -> (AList ControlPair a) -> Statement a
+ Language.Fortran.AST: StEndfile :: a -> SrcSpan -> AList ControlPair a -> Statement a
- Language.Fortran.AST: StEndfile2 :: a -> SrcSpan -> (Expression a) -> Statement a
+ Language.Fortran.AST: StEndfile2 :: a -> SrcSpan -> Expression a -> Statement a
- Language.Fortran.AST: StEndif :: a -> SrcSpan -> (Maybe String) -> Statement a
+ Language.Fortran.AST: StEndif :: a -> SrcSpan -> Maybe String -> Statement a
- Language.Fortran.AST: StEntry :: a -> SrcSpan -> (Expression a) -> (Maybe (AList Expression a)) -> (Maybe (Expression a)) -> Statement a
+ Language.Fortran.AST: StEntry :: a -> SrcSpan -> Expression a -> Maybe (AList Expression a) -> Maybe (Expression a) -> Statement a
- Language.Fortran.AST: StEquivalence :: a -> SrcSpan -> (AList (AList Expression) a) -> Statement a
+ Language.Fortran.AST: StEquivalence :: a -> SrcSpan -> AList (AList Expression) a -> Statement a
- Language.Fortran.AST: StExit :: a -> SrcSpan -> (Maybe (Expression a)) -> Statement a
+ Language.Fortran.AST: StExit :: a -> SrcSpan -> Maybe (Expression a) -> Statement a
- Language.Fortran.AST: StExpressionAssign :: a -> SrcSpan -> (Expression a) -> (Expression a) -> Statement a
+ Language.Fortran.AST: StExpressionAssign :: a -> SrcSpan -> Expression a -> Expression a -> Statement a
- Language.Fortran.AST: StExternal :: a -> SrcSpan -> (AList Expression a) -> Statement a
+ Language.Fortran.AST: StExternal :: a -> SrcSpan -> AList Expression a -> Statement a
- Language.Fortran.AST: StForall :: a -> SrcSpan -> (Maybe String) -> (ForallHeader a) -> Statement a
+ Language.Fortran.AST: StForall :: a -> SrcSpan -> Maybe String -> ForallHeader a -> Statement a
- Language.Fortran.AST: StForallStatement :: a -> SrcSpan -> (ForallHeader a) -> (Statement a) -> Statement a
+ Language.Fortran.AST: StForallStatement :: a -> SrcSpan -> ForallHeader a -> Statement a -> Statement a
- Language.Fortran.AST: StFormat :: a -> SrcSpan -> (AList FormatItem a) -> Statement a
+ Language.Fortran.AST: StFormat :: a -> SrcSpan -> AList FormatItem a -> Statement a
- Language.Fortran.AST: StFunction :: a -> SrcSpan -> (Expression a) -> (AList Expression a) -> (Expression a) -> Statement a
+ Language.Fortran.AST: StFunction :: a -> SrcSpan -> Expression a -> AList Expression a -> Expression a -> Statement a
- Language.Fortran.AST: StGotoAssigned :: a -> SrcSpan -> (Expression a) -> (Maybe (AList Expression a)) -> Statement a
+ Language.Fortran.AST: StGotoAssigned :: a -> SrcSpan -> Expression a -> Maybe (AList Expression a) -> Statement a
- Language.Fortran.AST: StGotoComputed :: a -> SrcSpan -> (AList Expression a) -> (Expression a) -> Statement a
+ Language.Fortran.AST: StGotoComputed :: a -> SrcSpan -> AList Expression a -> Expression a -> Statement a
- Language.Fortran.AST: StGotoUnconditional :: a -> SrcSpan -> (Expression a) -> Statement a
+ Language.Fortran.AST: StGotoUnconditional :: a -> SrcSpan -> Expression a -> Statement a
- Language.Fortran.AST: StIfArithmetic :: a -> SrcSpan -> (Expression a) -> (Expression a) -> (Expression a) -> (Expression a) -> Statement a
+ Language.Fortran.AST: StIfArithmetic :: a -> SrcSpan -> Expression a -> Expression a -> Expression a -> Expression a -> Statement a
- Language.Fortran.AST: StIfLogical :: a -> SrcSpan -> (Expression a) -> (Statement a) -> Statement a
+ Language.Fortran.AST: StIfLogical :: a -> SrcSpan -> Expression a -> Statement a -> Statement a
- Language.Fortran.AST: StIfThen :: a -> SrcSpan -> (Maybe String) -> (Expression a) -> Statement a
+ Language.Fortran.AST: StIfThen :: a -> SrcSpan -> Maybe String -> Expression a -> Statement a
- Language.Fortran.AST: StImplicit :: a -> SrcSpan -> (Maybe (AList ImpList a)) -> Statement a
+ Language.Fortran.AST: StImplicit :: a -> SrcSpan -> Maybe (AList ImpList a) -> Statement a
- Language.Fortran.AST: StInclude :: a -> SrcSpan -> (Expression a) -> (Maybe [Block a]) -> Statement a
+ Language.Fortran.AST: StInclude :: a -> SrcSpan -> Expression a -> Maybe [Block a] -> Statement a
- Language.Fortran.AST: StInquire :: a -> SrcSpan -> (AList ControlPair a) -> Statement a
+ Language.Fortran.AST: StInquire :: a -> SrcSpan -> AList ControlPair a -> Statement a
- Language.Fortran.AST: StIntent :: a -> SrcSpan -> Intent -> (AList Expression a) -> Statement a
+ Language.Fortran.AST: StIntent :: a -> SrcSpan -> Intent -> AList Expression a -> Statement a
- Language.Fortran.AST: StIntrinsic :: a -> SrcSpan -> (AList Expression a) -> Statement a
+ Language.Fortran.AST: StIntrinsic :: a -> SrcSpan -> AList Expression a -> Statement a
- Language.Fortran.AST: StLabelAssign :: a -> SrcSpan -> (Expression a) -> (Expression a) -> Statement a
+ Language.Fortran.AST: StLabelAssign :: a -> SrcSpan -> Expression a -> Expression a -> Statement a
- Language.Fortran.AST: StModuleProcedure :: a -> SrcSpan -> (AList Expression a) -> Statement a
+ Language.Fortran.AST: StModuleProcedure :: a -> SrcSpan -> AList Expression a -> Statement a
- Language.Fortran.AST: StNamelist :: a -> SrcSpan -> (AList Namelist a) -> Statement a
+ Language.Fortran.AST: StNamelist :: a -> SrcSpan -> AList Namelist a -> Statement a
- Language.Fortran.AST: StNullify :: a -> SrcSpan -> (AList Expression a) -> Statement a
+ Language.Fortran.AST: StNullify :: a -> SrcSpan -> AList Expression a -> Statement a
- Language.Fortran.AST: StOpen :: a -> SrcSpan -> (AList ControlPair a) -> Statement a
+ Language.Fortran.AST: StOpen :: a -> SrcSpan -> AList ControlPair a -> Statement a
- Language.Fortran.AST: StOptional :: a -> SrcSpan -> (AList Expression a) -> Statement a
+ Language.Fortran.AST: StOptional :: a -> SrcSpan -> AList Expression a -> Statement a
- Language.Fortran.AST: StParameter :: a -> SrcSpan -> (AList Declarator a) -> Statement a
+ Language.Fortran.AST: StParameter :: a -> SrcSpan -> AList Declarator a -> Statement a
- Language.Fortran.AST: StPause :: a -> SrcSpan -> (Maybe (Expression a)) -> Statement a
+ Language.Fortran.AST: StPause :: a -> SrcSpan -> Maybe (Expression a) -> Statement a
- Language.Fortran.AST: StPointer :: a -> SrcSpan -> (AList Declarator a) -> Statement a
+ Language.Fortran.AST: StPointer :: a -> SrcSpan -> AList Declarator a -> Statement a
- Language.Fortran.AST: StPointerAssign :: a -> SrcSpan -> (Expression a) -> (Expression a) -> Statement a
+ Language.Fortran.AST: StPointerAssign :: a -> SrcSpan -> Expression a -> Expression a -> Statement a
- Language.Fortran.AST: StPrint :: a -> SrcSpan -> (Expression a) -> (Maybe (AList Expression a)) -> Statement a
+ Language.Fortran.AST: StPrint :: a -> SrcSpan -> Expression a -> Maybe (AList Expression a) -> Statement a
- Language.Fortran.AST: StPrivate :: a -> SrcSpan -> (Maybe (AList Expression a)) -> Statement a
+ Language.Fortran.AST: StPrivate :: a -> SrcSpan -> Maybe (AList Expression a) -> Statement a
- Language.Fortran.AST: StPublic :: a -> SrcSpan -> (Maybe (AList Expression a)) -> Statement a
+ Language.Fortran.AST: StPublic :: a -> SrcSpan -> Maybe (AList Expression a) -> Statement a
- Language.Fortran.AST: StRead :: a -> SrcSpan -> (AList ControlPair a) -> (Maybe (AList Expression a)) -> Statement a
+ Language.Fortran.AST: StRead :: a -> SrcSpan -> AList ControlPair a -> Maybe (AList Expression a) -> Statement a
- Language.Fortran.AST: StRead2 :: a -> SrcSpan -> (Expression a) -> (Maybe (AList Expression a)) -> Statement a
+ Language.Fortran.AST: StRead2 :: a -> SrcSpan -> Expression a -> Maybe (AList Expression a) -> Statement a
- Language.Fortran.AST: StReturn :: a -> SrcSpan -> (Maybe (Expression a)) -> Statement a
+ Language.Fortran.AST: StReturn :: a -> SrcSpan -> Maybe (Expression a) -> Statement a
- Language.Fortran.AST: StRewind :: a -> SrcSpan -> (AList ControlPair a) -> Statement a
+ Language.Fortran.AST: StRewind :: a -> SrcSpan -> AList ControlPair a -> Statement a
- Language.Fortran.AST: StRewind2 :: a -> SrcSpan -> (Expression a) -> Statement a
+ Language.Fortran.AST: StRewind2 :: a -> SrcSpan -> Expression a -> Statement a
- Language.Fortran.AST: StSave :: a -> SrcSpan -> (Maybe (AList Expression a)) -> Statement a
+ Language.Fortran.AST: StSave :: a -> SrcSpan -> Maybe (AList Expression a) -> Statement a
- Language.Fortran.AST: StSelectCase :: a -> SrcSpan -> (Maybe String) -> (Expression a) -> Statement a
+ Language.Fortran.AST: StSelectCase :: a -> SrcSpan -> Maybe String -> Expression a -> Statement a
- Language.Fortran.AST: StStop :: a -> SrcSpan -> (Maybe (Expression a)) -> Statement a
+ Language.Fortran.AST: StStop :: a -> SrcSpan -> Maybe (Expression a) -> Statement a
- Language.Fortran.AST: StStructure :: a -> SrcSpan -> (Maybe String) -> (AList StructureItem a) -> Statement a
+ Language.Fortran.AST: StStructure :: a -> SrcSpan -> Maybe String -> AList StructureItem a -> Statement a
- Language.Fortran.AST: StTarget :: a -> SrcSpan -> (AList Declarator a) -> Statement a
+ Language.Fortran.AST: StTarget :: a -> SrcSpan -> AList Declarator a -> Statement a
- Language.Fortran.AST: StType :: a -> SrcSpan -> (Maybe (AList Attribute a)) -> String -> Statement a
+ Language.Fortran.AST: StType :: a -> SrcSpan -> Maybe (AList Attribute a) -> String -> Statement a
- Language.Fortran.AST: StTypePrint :: a -> SrcSpan -> (Expression a) -> (Maybe (AList Expression a)) -> Statement a
+ Language.Fortran.AST: StTypePrint :: a -> SrcSpan -> Expression a -> Maybe (AList Expression a) -> Statement a
- Language.Fortran.AST: StUse :: a -> SrcSpan -> (Expression a) -> Only -> (Maybe (AList Use a)) -> Statement a
+ Language.Fortran.AST: StUse :: a -> SrcSpan -> Expression a -> Maybe ModuleNature -> Only -> Maybe (AList Use a) -> Statement a
- Language.Fortran.AST: StWhere :: a -> SrcSpan -> (Expression a) -> (Statement a) -> Statement a
+ Language.Fortran.AST: StWhere :: a -> SrcSpan -> Expression a -> Statement a -> Statement a
- Language.Fortran.AST: StWhereConstruct :: a -> SrcSpan -> (Expression a) -> Statement a
+ Language.Fortran.AST: StWhereConstruct :: a -> SrcSpan -> Maybe String -> Expression a -> Statement a
- Language.Fortran.AST: StWrite :: a -> SrcSpan -> (AList ControlPair a) -> (Maybe (AList Expression a)) -> Statement a
+ Language.Fortran.AST: StWrite :: a -> SrcSpan -> AList ControlPair a -> Maybe (AList Expression a) -> Statement a
- Language.Fortran.AST: StructFields :: a -> SrcSpan -> (TypeSpec a) -> (Maybe (AList Attribute a)) -> (AList Declarator a) -> StructureItem a
+ Language.Fortran.AST: StructFields :: a -> SrcSpan -> TypeSpec a -> Maybe (AList Attribute a) -> AList Declarator a -> StructureItem a
- Language.Fortran.AST: StructStructure :: a -> SrcSpan -> (Maybe String) -> (AList StructureItem a) -> StructureItem a
+ Language.Fortran.AST: StructStructure :: a -> SrcSpan -> Maybe String -> AList StructureItem a -> StructureItem a
- Language.Fortran.AST: StructUnion :: a -> SrcSpan -> (AList UnionMap a) -> StructureItem a
+ Language.Fortran.AST: StructUnion :: a -> SrcSpan -> AList UnionMap a -> StructureItem a
- Language.Fortran.AST: TypeCharacter :: BaseType
+ Language.Fortran.AST: TypeCharacter :: Maybe CharacterLen -> Maybe String -> BaseType
- Language.Fortran.AST: TypeSpec :: a -> SrcSpan -> BaseType -> (Maybe (Selector a)) -> TypeSpec a
+ Language.Fortran.AST: TypeSpec :: a -> SrcSpan -> BaseType -> Maybe (Selector a) -> TypeSpec a
- Language.Fortran.AST: UnionMap :: a -> SrcSpan -> (AList StructureItem a) -> UnionMap a
+ Language.Fortran.AST: UnionMap :: a -> SrcSpan -> AList StructureItem a -> UnionMap a
- Language.Fortran.AST: UseID :: a -> SrcSpan -> (Expression a) -> Use a
+ Language.Fortran.AST: UseID :: a -> SrcSpan -> Expression a -> Use a
- Language.Fortran.AST: UseRename :: a -> SrcSpan -> (Expression a) -> (Expression a) -> Use a
+ Language.Fortran.AST: UseRename :: a -> SrcSpan -> Expression a -> Expression a -> Use a
- Language.Fortran.AST: ValComplex :: (Expression a) -> (Expression a) -> Value a
+ Language.Fortran.AST: ValComplex :: Expression a -> Expression a -> Value a
- Language.Fortran.AST: getAnnotation :: (Annotated f, (FirstParameter (f a) a)) => f a -> a
+ Language.Fortran.AST: getAnnotation :: (Annotated f, FirstParameter (f a) a) => f a -> a
- Language.Fortran.AST: pfGetFilename :: () => ProgramFile a -> String
+ Language.Fortran.AST: pfGetFilename :: ProgramFile a -> String
- Language.Fortran.AST: pfSetFilename :: () => String -> ProgramFile a -> ProgramFile a
+ Language.Fortran.AST: pfSetFilename :: String -> ProgramFile a -> ProgramFile a
- Language.Fortran.AST: setAnnotation :: (Annotated f, (FirstParameter (f a) a)) => a -> f a -> f a
+ Language.Fortran.AST: setAnnotation :: (Annotated f, FirstParameter (f a) a) => a -> f a -> f a
- Language.Fortran.Analysis: Analysis :: a -> Maybe String -> Maybe String -> Maybe (BBGr (Analysis a)) -> Maybe Int -> Maybe ModEnv -> Maybe IDType -> [Name] -> Analysis a
+ Language.Fortran.Analysis: Analysis :: a -> Maybe String -> Maybe String -> Maybe (BBGr (Analysis a)) -> Maybe Int -> Maybe ModEnv -> Maybe IDType -> [Name] -> Maybe Constant -> Analysis a
- Language.Fortran.Analysis: CTArray :: ConstructType
+ Language.Fortran.Analysis: CTArray :: [(Maybe Int, Maybe Int)] -> ConstructType
- Language.Fortran.Analysis: TypeCharacter :: BaseType
+ Language.Fortran.Analysis: TypeCharacter :: Maybe CharacterLen -> Maybe String -> BaseType
- Language.Fortran.Analysis: blockVarUses :: Data a => Block (Analysis a) -> [Name]
+ Language.Fortran.Analysis: blockVarUses :: forall a. Data a => Block (Analysis a) -> [Name]
- Language.Fortran.Analysis.DataFlow: genDUMap :: Data a => BlockMap a -> DefMap -> BBGr (Analysis a) -> InOutMap IntSet -> DUMap
+ Language.Fortran.Analysis.DataFlow: genDUMap :: Data a => BlockMap a -> DefMap -> BBGr (Analysis a) -> InOutMap ASTBlockNodeSet -> DUMap
- Language.Fortran.Analysis.DataFlow: genFlowsToGraph :: Data a => BlockMap a -> DefMap -> BBGr (Analysis a) -> InOutMap IntSet -> FlowsGraph a
+ Language.Fortran.Analysis.DataFlow: genFlowsToGraph :: Data a => BlockMap a -> DefMap -> BBGr (Analysis a) -> InOutMap ASTBlockNodeSet -> FlowsGraph a
- Language.Fortran.Analysis.DataFlow: genUDMap :: Data a => BlockMap a -> DefMap -> BBGr (Analysis a) -> InOutMap IntSet -> UDMap
+ Language.Fortran.Analysis.DataFlow: genUDMap :: Data a => BlockMap a -> DefMap -> BBGr (Analysis a) -> InOutMap ASTBlockNodeSet -> UDMap
- Language.Fortran.Analysis.DataFlow: loopNodes :: Graph gr => BackEdgeMap -> gr a b -> [IntSet]
+ Language.Fortran.Analysis.DataFlow: loopNodes :: Graph gr => BackEdgeMap -> gr a b -> [BBNodeSet]
- Language.Fortran.Analysis.DataFlow: reachingDefinitions :: Data a => DefMap -> BBGr (Analysis a) -> InOutMap IntSet
+ Language.Fortran.Analysis.DataFlow: reachingDefinitions :: Data a => DefMap -> BBGr (Analysis a) -> InOutMap ASTBlockNodeSet
- Language.Fortran.Analysis.DataFlow: sccWith :: (Graph gr) => Node -> gr a b -> [Node]
+ Language.Fortran.Analysis.DataFlow: sccWith :: Graph gr => Node -> gr a b -> [Node]
- Language.Fortran.Analysis.DataFlow: type BackEdgeMap = IntMap Node
+ Language.Fortran.Analysis.DataFlow: type BackEdgeMap = BBNodeMap BBNode
- Language.Fortran.Analysis.DataFlow: type BlockMap a = IntMap (Block (Analysis a))
+ Language.Fortran.Analysis.DataFlow: type BlockMap a = ASTBlockNodeMap (Block (Analysis a))
- Language.Fortran.Analysis.DataFlow: type DUMap = IntMap IntSet
+ Language.Fortran.Analysis.DataFlow: type DUMap = ASTBlockNodeMap ASTBlockNodeSet
- Language.Fortran.Analysis.DataFlow: type DefMap = Map Name IntSet
+ Language.Fortran.Analysis.DataFlow: type DefMap = Map Name ASTBlockNodeSet
- Language.Fortran.Analysis.DataFlow: type DerivedInductionMap = IntMap InductionExpr
+ Language.Fortran.Analysis.DataFlow: type DerivedInductionMap = ASTExprNodeMap InductionExpr
- Language.Fortran.Analysis.DataFlow: type DomMap = IntMap IntSet
+ Language.Fortran.Analysis.DataFlow: type DomMap = BBNodeMap BBNodeSet
- Language.Fortran.Analysis.DataFlow: type IDomMap = IntMap Int
+ Language.Fortran.Analysis.DataFlow: type IDomMap = BBNodeMap BBNode
- Language.Fortran.Analysis.DataFlow: type InOutMap t = IntMap (InOut t)
+ Language.Fortran.Analysis.DataFlow: type InOutMap t = BBNodeMap (InOut t)
- Language.Fortran.Analysis.DataFlow: type InductionVarMap = IntMap (Set Name)
+ Language.Fortran.Analysis.DataFlow: type InductionVarMap = BBNodeMap (Set Name)
- Language.Fortran.Analysis.DataFlow: type InductionVarMapByASTBlock = IntMap (Set Name)
+ Language.Fortran.Analysis.DataFlow: type InductionVarMapByASTBlock = ASTBlockNodeMap (Set Name)
- Language.Fortran.Analysis.DataFlow: type LoopNodeMap = IntMap IntSet
+ Language.Fortran.Analysis.DataFlow: type LoopNodeMap = BBNodeMap BBNodeSet
- Language.Fortran.Analysis.DataFlow: type UDMap = IntMap IntSet
+ Language.Fortran.Analysis.DataFlow: type UDMap = ASTBlockNodeMap ASTBlockNodeSet
- Language.Fortran.LValue: LvDataRef :: a -> SrcSpan -> (LValue a) -> (LValue a) -> LValue a
+ Language.Fortran.LValue: LvDataRef :: a -> SrcSpan -> LValue a -> LValue a -> LValue a
- Language.Fortran.LValue: LvSubscript :: a -> SrcSpan -> (LValue a) -> (AList Index a) -> LValue a
+ Language.Fortran.LValue: LvSubscript :: a -> SrcSpan -> LValue a -> AList Index a -> LValue a
- Language.Fortran.Lexer.FreeForm: AlexAccPred :: Int -> (AlexAccPred user) -> (AlexAcc user) -> AlexAcc user
+ Language.Fortran.Lexer.FreeForm: AlexAccPred :: Int -> AlexAccPred user -> AlexAcc user -> AlexAcc user
- Language.Fortran.Lexer.FreeForm: AlexAccSkipPred :: (AlexAccPred user) -> (AlexAcc user) -> AlexAcc user
+ Language.Fortran.Lexer.FreeForm: AlexAccSkipPred :: AlexAccPred user -> AlexAcc user -> AlexAcc user
- Language.Fortran.Lexer.FreeForm: AlexInput :: !ByteString -> {-# UNPACK #-} !Position -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Char -> {-# UNPACK #-} !Lexeme -> {-# UNPACK #-} !StartCode -> !(Maybe Token) -> !([Token]) -> AlexInput
+ Language.Fortran.Lexer.FreeForm: AlexInput :: !ByteString -> {-# UNPACK #-} !Position -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Char -> {-# UNPACK #-} !Lexeme -> {-# UNPACK #-} !StartCode -> !Maybe Token -> ![Token] -> AlexInput
- Language.Fortran.Lexer.FreeForm: [aiPreviousToken] :: AlexInput -> !(Maybe Token)
+ Language.Fortran.Lexer.FreeForm: [aiPreviousToken] :: AlexInput -> !Maybe Token
- Language.Fortran.Lexer.FreeForm: [aiPreviousTokensInLine] :: AlexInput -> !([Token])
+ Language.Fortran.Lexer.FreeForm: [aiPreviousTokensInLine] :: AlexInput -> ![Token]
- Language.Fortran.Lexer.FreeForm: alexScan :: AlexInput -> Int -> AlexReturn LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alexScan :: AlexInput -> Int -> AlexReturn (LexAction (Maybe Token))
- Language.Fortran.Lexer.FreeForm: alex_accept :: Array Int AlexAcc User
+ Language.Fortran.Lexer.FreeForm: alex_accept :: Array Int (AlexAcc User)
- Language.Fortran.Lexer.FreeForm: alex_action_0 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_0 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_1 :: Parse AlexInput Token Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_1 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_10 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_10 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_100 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_100 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_101 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_101 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_102 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_102 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_103 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_103 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_104 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_104 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_105 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_105 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_106 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_106 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_107 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_107 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_108 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_108 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_109 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_109 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_11 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_11 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_110 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_110 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_111 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_111 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_112 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_112 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_113 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_113 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_114 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_114 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_115 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_115 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_116 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_116 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_117 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_117 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_118 :: Parse AlexInput Token Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_118 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_119 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_119 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_12 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_12 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_120 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_120 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_121 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_121 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_122 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_122 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_123 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_123 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_124 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_124 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_125 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_125 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_126 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_126 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_127 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_127 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_128 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_128 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_129 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_129 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_13 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_13 :: Parse AlexInput Token (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_130 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_130 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_131 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_131 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_132 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_132 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_133 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_133 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_134 :: Parse AlexInput Token Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_134 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_135 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_135 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_136 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_136 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_137 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_137 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_138 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_138 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_139 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_139 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_14 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_14 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_140 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_140 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_141 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_141 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_142 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_142 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_143 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_143 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_144 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_144 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_145 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_145 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_146 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_146 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_147 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_147 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_148 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_148 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_149 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_149 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_15 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_15 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_150 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_150 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_151 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_151 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_152 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_152 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_153 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_153 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_154 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_154 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_155 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_155 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_156 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_156 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_157 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_157 :: Parse AlexInput Token (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_158 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_158 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_159 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_159 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_16 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_16 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_17 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_17 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_18 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_18 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_19 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_19 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_20 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_20 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_21 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_21 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_22 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_22 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_23 :: Parse AlexInput Token Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_23 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_24 :: Parse AlexInput Token Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_24 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_25 :: Parse AlexInput Token Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_25 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_26 :: Parse AlexInput Token Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_26 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_27 :: Parse AlexInput Token Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_27 :: Parse AlexInput Token (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_28 :: Parse AlexInput Token Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_28 :: Parse AlexInput Token (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_29 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_29 :: Parse AlexInput Token (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_3 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_3 :: Parse AlexInput Token (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_30 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_30 :: Parse AlexInput Token (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_31 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_31 :: Parse AlexInput Token (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_32 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_32 :: Parse AlexInput Token (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_33 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_33 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_34 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_34 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_35 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_35 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_36 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_36 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_37 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_37 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_38 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_38 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_39 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_39 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_40 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_40 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_41 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_41 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_42 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_42 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_43 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_43 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_44 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_44 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_45 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_45 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_46 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_46 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_47 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_47 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_48 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_48 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_49 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_49 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_5 :: Parse AlexInput Token Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_5 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_50 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_50 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_51 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_51 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_52 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_52 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_53 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_53 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_54 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_54 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_55 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_55 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_56 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_56 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_57 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_57 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_58 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_58 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_59 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_59 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_6 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_6 :: Parse AlexInput Token (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_60 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_60 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_61 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_61 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_62 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_62 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_63 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_63 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_64 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_64 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_65 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_65 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_66 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_66 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_67 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_67 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_68 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_68 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_69 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_69 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_7 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_7 :: Parse AlexInput Token (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_70 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_70 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_71 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_71 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_72 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_72 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_73 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_73 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_74 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_74 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_75 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_75 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_76 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_76 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_77 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_77 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_78 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_78 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_79 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_79 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_8 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_8 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_80 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_80 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_81 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_81 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_82 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_82 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_83 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_83 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_84 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_84 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_85 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_85 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_86 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_86 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_87 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_87 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_88 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_88 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_89 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_89 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_9 :: Parse AlexInput Token Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_9 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_90 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_90 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_91 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_91 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_92 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_92 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_93 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_93 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_94 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_94 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_95 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_95 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_96 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_96 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_97 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_97 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_98 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_98 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_action_99 :: LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_action_99 :: LexAction (Maybe Token)
- Language.Fortran.Lexer.FreeForm: alex_actions :: Array Int LexAction Maybe Token
+ Language.Fortran.Lexer.FreeForm: alex_actions :: Array Int (LexAction (Maybe Token))
- Language.Fortran.Lexer.FreeForm: quickIndex :: Array Int AlexAcc User -> Int -> AlexAcc User
+ Language.Fortran.Lexer.FreeForm: quickIndex :: Array Int (AlexAcc User) -> Int -> AlexAcc User
- Language.Fortran.Parser.Any: after :: () => (b -> c) -> (t -> a -> b) -> t -> a -> c
+ Language.Fortran.Parser.Any: after :: (b -> c) -> (t -> a -> b) -> t -> a -> c
- Language.Fortran.Parser.Fortran66: expressionParser :: LexAction Expression A0
+ Language.Fortran.Parser.Fortran66: expressionParser :: LexAction (Expression A0)
- Language.Fortran.Parser.Fortran66: statementParser :: LexAction Statement A0
+ Language.Fortran.Parser.Fortran66: statementParser :: LexAction (Statement A0)
- Language.Fortran.Parser.Fortran77: expressionParser :: LexAction Expression A0
+ Language.Fortran.Parser.Fortran77: expressionParser :: LexAction (Expression A0)
- Language.Fortran.Parser.Fortran77: statementParser :: LexAction Statement A0
+ Language.Fortran.Parser.Fortran77: statementParser :: LexAction (Statement A0)
- Language.Fortran.Parser.Fortran90: functionParser :: LexAction ProgramUnit A0
+ Language.Fortran.Parser.Fortran90: functionParser :: LexAction (ProgramUnit A0)
- Language.Fortran.Parser.Fortran90: statementParser :: LexAction Statement A0
+ Language.Fortran.Parser.Fortran90: statementParser :: LexAction (Statement A0)
- Language.Fortran.Parser.Fortran95: functionParser :: LexAction ProgramUnit A0
+ Language.Fortran.Parser.Fortran95: functionParser :: LexAction (ProgramUnit A0)
- Language.Fortran.Parser.Fortran95: statementParser :: LexAction Statement A0
+ Language.Fortran.Parser.Fortran95: statementParser :: LexAction (Statement A0)
- Language.Fortran.ParserMonad: ParseFailed :: (ParseError b c) -> ParseResult b c a
+ Language.Fortran.ParserMonad: ParseFailed :: ParseError b c -> ParseResult b c a
- Language.Fortran.ParserMonad: ParseOk :: a -> (ParseState b) -> ParseResult b c a
+ Language.Fortran.ParserMonad: ParseOk :: a -> ParseState b -> ParseResult b c a
- Language.Fortran.ParserMonad: fromParseResult :: (Show c) => ParseResult b c a -> Either ParseErrorSimple a
+ Language.Fortran.ParserMonad: fromParseResult :: Show c => ParseResult b c a -> Either ParseErrorSimple a
- Language.Fortran.ParserMonad: fromParseResultUnsafe :: (Show c) => ParseResult b c a -> a
+ Language.Fortran.ParserMonad: fromParseResultUnsafe :: Show c => ParseResult b c a -> a
- Language.Fortran.ParserMonad: getLastToken :: (LastToken a b, (Show b)) => a -> Maybe b
+ Language.Fortran.ParserMonad: getLastToken :: (LastToken a b, Show b) => a -> Maybe b
- Language.Fortran.ParserMonad: throwIOerror :: () => String -> a
+ Language.Fortran.ParserMonad: throwIOerror :: String -> a
- Language.Fortran.ParserMonad: tokenMsg :: Show a => Maybe a -> [Char]
+ Language.Fortran.ParserMonad: tokenMsg :: Show a => Maybe a -> String
- Language.Fortran.Util.ModFile: decodeModFile :: Binary a => ByteString -> Either String a
+ Language.Fortran.Util.ModFile: decodeModFile :: ByteString -> Either String ModFile
- Language.Fortran.Util.Position: Position :: {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> Position
+ Language.Fortran.Util.Position: Position :: Int -> Int -> Int -> String -> Maybe (Int, String) -> Position
- Language.Fortran.Util.Position: [posAbsoluteOffset] :: Position -> {-# UNPACK #-} !Int
+ Language.Fortran.Util.Position: [posAbsoluteOffset] :: Position -> Int
- Language.Fortran.Util.Position: [posColumn] :: Position -> {-# UNPACK #-} !Int
+ Language.Fortran.Util.Position: [posColumn] :: Position -> Int
- Language.Fortran.Util.Position: [posLine] :: Position -> {-# UNPACK #-} !Int
+ Language.Fortran.Util.Position: [posLine] :: Position -> Int
- Language.Fortran.Util.Position: getSpan :: (Spanned a, (SecondParameter a SrcSpan)) => a -> SrcSpan
+ Language.Fortran.Util.Position: getSpan :: (Spanned a, SecondParameter a SrcSpan) => a -> SrcSpan
- Language.Fortran.Util.Position: setSpan :: (Spanned a, (SecondParameter a SrcSpan)) => SrcSpan -> a -> a
+ Language.Fortran.Util.Position: setSpan :: (Spanned a, SecondParameter a SrcSpan) => SrcSpan -> a -> a
Files
- CHANGELOG.md +29/−0
- LICENSE +4/−2
- fortran-src.cabal +135/−122
- src/Language/Fortran/AST.hs +221/−91
- src/Language/Fortran/Analysis.hs +98/−48
- src/Language/Fortran/Analysis/BBlocks.hs +303/−173
- src/Language/Fortran/Analysis/DataFlow.hs +256/−112
- src/Language/Fortran/Analysis/Renaming.hs +127/−64
- src/Language/Fortran/Analysis/Types.hs +231/−39
- src/Language/Fortran/Intrinsics.hs +21/−12
- src/Language/Fortran/LValue.hs +1/−0
- src/Language/Fortran/Lexer/FixedForm.x +70/−50
- src/Language/Fortran/Lexer/FreeForm.x +251/−37
- src/Language/Fortran/Parser/Any.hs +20/−3
- src/Language/Fortran/Parser/Fortran2003.y +1328/−0
- src/Language/Fortran/Parser/Fortran66.y +3/−3
- src/Language/Fortran/Parser/Fortran77.y +16/−14
- src/Language/Fortran/Parser/Fortran90.y +82/−57
- src/Language/Fortran/Parser/Fortran95.y +96/−86
- src/Language/Fortran/Parser/Utils.hs +7/−0
- src/Language/Fortran/ParserMonad.hs +23/−6
- src/Language/Fortran/PrettyPrint.hs +267/−101
- src/Language/Fortran/Transformation/Disambiguation/Function.hs +13/−6
- src/Language/Fortran/Transformation/Disambiguation/Intrinsic.hs +2/−2
- src/Language/Fortran/Transformation/Grouping.hs +105/−57
- src/Language/Fortran/Transformation/TransformMonad.hs +2/−2
- src/Language/Fortran/Util/FirstParameter.hs +4/−5
- src/Language/Fortran/Util/ModFile.hs +100/−30
- src/Language/Fortran/Util/Position.hs +27/−9
- src/Language/Fortran/Util/SecondParameter.hs +3/−4
- src/Main.hs +152/−69
- test/Language/Fortran/Analysis/BBlocksSpec.hs +139/−27
- test/Language/Fortran/Analysis/DataFlowSpec.hs +150/−90
- test/Language/Fortran/Analysis/RenamingSpec.hs +135/−34
- test/Language/Fortran/Analysis/TypesSpec.hs +162/−17
- test/Language/Fortran/AnalysisSpec.hs +5/−8
- test/Language/Fortran/Lexer/FixedFormSpec.hs +23/−22
- test/Language/Fortran/Lexer/FreeFormSpec.hs +109/−4
- test/Language/Fortran/Parser/Fortran2003Spec.hs +150/−3
- test/Language/Fortran/Parser/Fortran2008Spec.hs +3/−4
- test/Language/Fortran/Parser/Fortran66Spec.hs +1/−3
- test/Language/Fortran/Parser/Fortran77/IncludeSpec.hs +53/−0
- test/Language/Fortran/Parser/Fortran77/ParserSpec.hs +312/−0
- test/Language/Fortran/Parser/Fortran77Spec.hs +0/−306
- test/Language/Fortran/Parser/Fortran90Spec.hs +91/−70
- test/Language/Fortran/Parser/Fortran95Spec.hs +190/−152
- test/Language/Fortran/Parser/UtilsSpec.hs +8/−9
- test/Language/Fortran/ParserMonadSpec.hs +12/−13
- test/Language/Fortran/PrettyPrintSpec.hs +37/−22
- test/Language/Fortran/Transformation/Disambiguation/FunctionSpec.hs +150/−9
- test/Language/Fortran/Transformation/GroupingSpec.hs +142/−9
- test/Language/Fortran/Util/FirstParameterSpec.hs +15/−15
- test/Language/Fortran/Util/SecondParameterSpec.hs +11/−11
- test/TestUtil.hs +13/−4
CHANGELOG.md view
@@ -1,3 +1,32 @@+### 0.3.0 (June 13, 2019)++* Add partial Fortran2003 support.+* Introduce datatype for BBGr instead of prior type alias for Gr.+ * Now split into three fields: bbgrGr, bbgrEntries and bbgrExits+ * May require refactoring of code to use bbgrGr field where a Gr was expected before.+* Introduce pragmaOffset field for Position, allowing pragmas to specify an apparent file and line-number.+ * May require refactoring of code that uses the Position constructor.+ * Fifth field is Maybe (Int, String), containing a line-offset and a target filename when present.+ * It's designed such that most Position-based transformations are not affected by the pragmaOffset.+ * They may need to preserve the field, though, as it passes through functions.+ * Default value is 'Nothing'.+* Add --show-flows-to/--show-flows-from features+ * Visualise the dataflow use/def chains using GraphViz.+* Add --show-block-numbers feature.+ * Allows user to get AST-block numbers easily in order to use them with the above visualisation features.+* Fix several bugs with dataflow analysis that had accumulated.+* Eliminate StContinue and StEnddo are eliminated during GroupLabeledDo transformations.+ * To be consistent with unlabeled Do.+* Parse and discard C-comments as a convenience feature for when fortran-src must interact with the output of C preprocessors that insert spurious comments.+* Add type propagation into type analysis, annotating every expression with a type.+ * Additional interface: analyseTypesWithEnv to access a list of type errors found.+* Add dimensional information to CTArray and length/kind to TypeCharacter.+* Stricter checking of the grouping transform - if any statements that should be grouped are not grouped, raise an error.+* Support pragmas that alter the current 'filename and position' tracker, often used by preprocessors to help pinpoint original code locations.+ * Uses a relative offset field called 'posPragmaOffset' so that relative measures continue to function correctly.+* Add constant propagation / parameter variable analysis.+* Add -c feature to compile 'fsmod files' with renaming and type info.+ ### 0.2.1.1 (May 18, 2018) * Extend Fortran 95 support
LICENSE view
@@ -1,10 +1,12 @@-Copyright (c) 2015, Mistral Contrastin+Copyright (c) 2015-2019: Mistral Contrastin, Matthew Danish, Dominic Orchard and Andrew Rice +Additional thanks for contributions from: Anthony Burzillo, Azeem Bande-Ali, Ben Moon, Bradley Hardy, Eric Seidel, Harry Clarke, Jason Xu, Lukasz Kolodziejczyk, TravelTissues and Vaibhav Yenamandra+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0+ http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
fortran-src.cabal view
@@ -1,135 +1,148 @@--- Initial Language.Fortran.cabal generated by cabal init. For further--- documentation, see http://haskell.org/cabal/users-guide/+cabal-version: 1.12 -name: fortran-src-version: 0.2.1.1-synopsis: Parser and anlyses 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.-bug-reports: https://github.com/camfort/fortran-src/issues-license: Apache-2.0-license-file: LICENSE-author: Mistral Contrastin, Matthew Danish, Dominic Orchard, Andrew Rice-maintainer: me@madgen.net--- copyright:-category: Language-build-type: Simple-extra-source-files: CHANGELOG.md-cabal-version: >=1.10+-- This file has been generated from package.yaml by hpack version 0.31.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: f33857aa248d66c7f4c20fdc906e32ee466aeca57820d7fd2c0874092659737a++name: fortran-src+version: 0.3.0+synopsis: Parser and anlyses 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+homepage: https://github.com/camfort/fortran-src#readme+bug-reports: https://github.com/camfort/fortran-src/issues+author: Mistral Contrastin, Matthew Danish, Dominic Orchard, Andrew Rice+maintainer: me@madgen.net+license: Apache-2.0+license-file: LICENSE+build-type: Simple+extra-source-files:+ CHANGELOG.md+ source-repository head- type: git+ type: git location: https://github.com/camfort/fortran-src -executable fortran-src- main-is: src/Main.hs- build-depends:- base >= 4.6 && < 5,- mtl >= 2.2 && < 3,- array >= 0.5 && < 0.6,- uniplate >= 1.6 && < 2,- GenericPretty >= 1.2.2 && < 2,- pretty >= 1.1 && < 2,- containers >= 0.5 && < 0.6,- text >= 1.2 && < 2,- bytestring >= 0.10 && < 0.11,- binary >= 0.8.3.0 && < 0.9,- filepath >= 1.4 && < 2,- directory >= 1.2 && < 2,- fgl >= 5 && < 6,- fortran-src- ghc-options: -fno-warn-tabs- default-language: Haskell2010- library exposed-modules:- Language.Fortran.Analysis- Language.Fortran.Analysis.Renaming- Language.Fortran.Analysis.Types- Language.Fortran.Analysis.BBlocks- Language.Fortran.Analysis.DataFlow- Language.Fortran.AST- Language.Fortran.LValue- Language.Fortran.Intrinsics- Language.Fortran.Lexer.FixedForm- Language.Fortran.Lexer.FreeForm- Language.Fortran.ParserMonad- Language.Fortran.Parser.Any- Language.Fortran.Parser.Fortran66- Language.Fortran.Parser.Fortran77- Language.Fortran.Parser.Fortran90- Language.Fortran.Parser.Fortran95- Language.Fortran.Parser.Utils- Language.Fortran.PrettyPrint- Language.Fortran.Transformation.Disambiguation.Function- Language.Fortran.Transformation.Disambiguation.Intrinsic- Language.Fortran.Transformation.Grouping- Language.Fortran.Transformation.TransformMonad- Language.Fortran.Transformer- Language.Fortran.Util.Position- Language.Fortran.Util.FirstParameter- Language.Fortran.Util.SecondParameter- Language.Fortran.Util.ModFile- build-tools:- alex >= 3.1,- happy >= 1.19+ Language.Fortran.Analysis+ Language.Fortran.Analysis.Renaming+ Language.Fortran.Analysis.Types+ Language.Fortran.Analysis.BBlocks+ Language.Fortran.Analysis.DataFlow+ Language.Fortran.AST+ Language.Fortran.LValue+ Language.Fortran.Intrinsics+ Language.Fortran.Lexer.FixedForm+ Language.Fortran.Lexer.FreeForm+ Language.Fortran.ParserMonad+ Language.Fortran.Parser.Any+ Language.Fortran.Parser.Fortran66+ Language.Fortran.Parser.Fortran77+ Language.Fortran.Parser.Fortran90+ Language.Fortran.Parser.Fortran95+ Language.Fortran.Parser.Fortran2003+ Language.Fortran.Parser.Utils+ Language.Fortran.PrettyPrint+ Language.Fortran.Transformation.Disambiguation.Function+ Language.Fortran.Transformation.Disambiguation.Intrinsic+ Language.Fortran.Transformation.Grouping+ Language.Fortran.Transformation.TransformMonad+ Language.Fortran.Transformer+ Language.Fortran.Util.Position+ Language.Fortran.Util.FirstParameter+ Language.Fortran.Util.SecondParameter+ Language.Fortran.Util.ModFile+ hs-source-dirs:+ src+ ghc-options: -fno-warn-tabs build-depends:- base >= 4.6 && < 5,- mtl >= 2.2 && < 3,- array >= 0.5 && < 0.6,- uniplate >= 1.6 && < 2,- GenericPretty >= 1.2.2 && < 2,- pretty >= 1.1 && < 2,- containers >= 0.5 && < 0.6,- text >= 1.2 && < 2,- bytestring >= 0.10 && < 0.11,- binary >= 0.8.3.0 && < 0.9,- filepath >= 1.4 && < 2,- directory >= 1.2 && < 2,- fgl >= 5 && < 6- hs-source-dirs: src+ GenericPretty >=1.2.2 && <2+ , array >=0.5 && <0.6+ , base >=4.6 && <5+ , binary >=0.8.3.0 && <0.9+ , bytestring >=0.10 && <0.11+ , containers >=0.5 && <0.7+ , directory >=1.2 && <2+ , fgl >=5 && <6+ , filepath >=1.4 && <2+ , mtl >=2.2 && <3+ , pretty >=1.1 && <2+ , text >=1.2 && <2+ , uniplate >=1.6 && <2+ build-tools:+ alex >=3.1+ , happy >=1.19+ default-language: Haskell2010++executable fortran-src+ main-is: src/Main.hs+ other-modules:+ Paths_fortran_src ghc-options: -fno-warn-tabs- default-language: Haskell2010+ build-depends:+ GenericPretty >=1.2.2 && <2+ , array >=0.5 && <0.6+ , base >=4.6 && <5+ , binary >=0.8.3.0 && <0.9+ , bytestring >=0.10 && <0.11+ , containers >=0.5 && <0.7+ , directory >=1.2 && <2+ , fgl >=5 && <6+ , filepath >=1.4 && <2+ , fortran-src+ , mtl >=2.2 && <3+ , pretty >=1.1 && <2+ , text >=1.2 && <2+ , uniplate >=1.6 && <2+ default-language: Haskell2010 test-suite spec type: exitcode-stdio-1.0- build-depends:- deepseq,- base >= 4.6 && < 5,- hspec >= 2.2 && < 3,- mtl >= 2.2 && < 3,- array >= 0.5 && < 0.6,- uniplate >= 1.6 && < 2,- directory >= 1.2 && < 2,- filepath >= 1.4 && < 2,- GenericPretty >= 1.2.2 && < 2,- pretty >= 1.1 && < 2,- containers >= 0.5 && < 0.6,- text >= 1.2 && < 2,- bytestring >= 0.10 && < 0.11,- binary >= 0.8.3.0 && < 0.9,- fgl >= 5 && < 6,- fortran-src- hs-source-dirs: test main-is: Spec.hs other-modules:- Language.Fortran.Analysis.BBlocksSpec- Language.Fortran.Analysis.DataFlowSpec- Language.Fortran.Analysis.RenamingSpec- Language.Fortran.Analysis.TypesSpec- Language.Fortran.AnalysisSpec- Language.Fortran.Lexer.FixedFormSpec- Language.Fortran.Lexer.FreeFormSpec- Language.Fortran.Parser.Fortran2003Spec- Language.Fortran.Parser.Fortran2008Spec- Language.Fortran.Parser.Fortran66Spec- Language.Fortran.Parser.Fortran77Spec- Language.Fortran.Parser.Fortran90Spec- Language.Fortran.Parser.Fortran95Spec- Language.Fortran.Parser.UtilsSpec- Language.Fortran.ParserMonadSpec- Language.Fortran.PrettyPrintSpec- Language.Fortran.Transformation.Disambiguation.FunctionSpec- Language.Fortran.Transformation.GroupingSpec- Language.Fortran.Util.FirstParameterSpec- Language.Fortran.Util.SecondParameterSpec- TestUtil- default-language: Haskell2010+ Language.Fortran.Analysis.BBlocksSpec+ Language.Fortran.Analysis.DataFlowSpec+ Language.Fortran.Analysis.RenamingSpec+ Language.Fortran.Analysis.TypesSpec+ Language.Fortran.AnalysisSpec+ Language.Fortran.Lexer.FixedFormSpec+ Language.Fortran.Lexer.FreeFormSpec+ Language.Fortran.Parser.Fortran2003Spec+ Language.Fortran.Parser.Fortran2008Spec+ Language.Fortran.Parser.Fortran66Spec+ Language.Fortran.Parser.Fortran77.IncludeSpec+ Language.Fortran.Parser.Fortran77.ParserSpec+ Language.Fortran.Parser.Fortran90Spec+ Language.Fortran.Parser.Fortran95Spec+ Language.Fortran.Parser.UtilsSpec+ Language.Fortran.ParserMonadSpec+ Language.Fortran.PrettyPrintSpec+ Language.Fortran.Transformation.Disambiguation.FunctionSpec+ Language.Fortran.Transformation.GroupingSpec+ Language.Fortran.Util.FirstParameterSpec+ Language.Fortran.Util.SecondParameterSpec+ TestUtil+ Paths_fortran_src+ hs-source-dirs:+ test+ build-depends:+ GenericPretty >=1.2.2 && <2+ , array >=0.5 && <0.6+ , base >=4.6 && <5+ , binary >=0.8.3.0 && <0.9+ , bytestring >=0.10 && <0.11+ , containers >=0.5 && <0.7+ , deepseq+ , directory >=1.2 && <2+ , fgl >=5 && <6+ , filepath >=1.4 && <2+ , fortran-src+ , hspec >=2.2 && <3+ , mtl >=2.2 && <3+ , pretty >=1.1 && <2+ , text >=1.2 && <2+ , uniplate >=1.6 && <2+ default-language: Haskell2010
src/Language/Fortran/AST.hs view
@@ -5,9 +5,12 @@ {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE FlexibleContexts #-}+-- orphans are instances of package-natives+{-# OPTIONS_GHC -Wno-orphans #-} module Language.Fortran.AST where +import Prelude hiding (init) import Data.Data import Data.Generics.Uniplate.Data () import Data.Typeable ()@@ -34,12 +37,22 @@ instance Functor t => Functor (AList t) where fmap f (AList a s xs) = AList (f a) s (map (fmap f) xs) ++-- Convert non-empty list to AList. fromList :: Spanned (t a) => a -> [ t a ] -> AList t a fromList a xs = AList a (getSpan xs) xs +-- Nothing iff list is empty+fromList' :: Spanned (t a) => a -> [ t a ] -> Maybe (AList t a)+fromList' _ [] = Nothing+fromList' a xs = Just $ fromList a xs+ fromReverseList :: Spanned (t ()) => [ t () ] -> AList t () fromReverseList = fromList () . reverse +fromReverseList' :: Spanned (t ()) => [ t () ] -> Maybe (AList t ())+fromReverseList' = fromList' () . reverse+ aCons :: t a -> AList t a -> AList t a aCons x (AList a s xs) = AList a s $ x:xs @@ -51,6 +64,10 @@ aStrip :: AList t a -> [t a] aStrip (AList _ _ l) = l +aStrip' :: Maybe (AList t a) -> [t a]+aStrip' Nothing = []+aStrip' (Just a) = aStrip a+ aMap :: (t a -> r a) -> AList t a -> AList r a aMap f (AList a s xs) = AList a s (map f xs) @@ -62,13 +79,38 @@ | TypeComplex | TypeDoubleComplex | TypeLogical- | TypeCharacter+ | TypeCharacter (Maybe CharacterLen) (Maybe String) -- ^ len and kind, if specified | TypeCustom String+ | ClassStar+ | ClassCustom String | TypeByte deriving (Ord, Eq, Show, Data, Typeable, Generic) 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+ data TypeSpec a = TypeSpec a SrcSpan BaseType (Maybe (Selector a)) deriving (Eq, Show, Data, Typeable, Generic, Functor) @@ -84,7 +126,9 @@ data ProgramFile a = ProgramFile MetaInfo [ ProgramUnit a ] deriving (Eq, Show, Data, Typeable, Generic, Functor) +pfSetFilename :: String -> ProgramFile a -> ProgramFile a pfSetFilename fn (ProgramFile mi pus) = ProgramFile (mi { miFilename = fn }) pus+pfGetFilename :: ProgramFile a -> String pfGetFilename (ProgramFile mi _) = miFilename mi data ProgramUnit a =@@ -100,7 +144,7 @@ (Maybe [ProgramUnit a]) -- Subprograms | PUSubroutine a SrcSpan- (PUFunctionOpt a) -- Subroutine options+ (PrefixSuffix a) -- Subroutine options Name (Maybe (AList Expression a)) -- Arguments [Block a] -- Body@@ -108,7 +152,7 @@ | PUFunction a SrcSpan (Maybe (TypeSpec a)) -- Return type- (PUFunctionOpt a) -- Function Options+ (PrefixSuffix a) -- Function Options Name (Maybe (AList Expression a)) -- Arguments (Maybe (Expression a)) -- Result@@ -121,65 +165,66 @@ | PUComment a SrcSpan (Comment a) deriving (Eq, Show, Data, Typeable, Generic, Functor) -type IsRecursive = Bool-data PUFunctionOpt a =- None a SrcSpan IsRecursive- | Pure a SrcSpan IsRecursive- | Elemental a SrcSpan- deriving (Eq, Show, Data, Typeable, Generic, Functor)+type Prefixes a = Maybe (AList Prefix a)+type Suffixes a = Maybe (AList Suffix a)+type PrefixSuffix a = (Prefixes a, Suffixes a) -buildPUFunctionOpt :: (PUFunctionOpt ()) -> (PUFunctionOpt ()) -> Either String (PUFunctionOpt ())-buildPUFunctionOpt a b =- case (a, b) of- ((None () _ False ), _) -> Right $ setSpan (getTransSpan a b) b- (_, (None () _ False)) -> Right $ setSpan (getTransSpan a b) a- ((Elemental () _), _) -> if functionIsRecursive b- then Left "Function cannot be both elemental and recursive. "- else Right . Elemental () $ getTransSpan a b- (_, (Elemental () _)) -> buildPUFunctionOpt b a- ((Pure () _ r), b) -> Right $ Pure () (getTransSpan a b) (r || functionIsRecursive b)- (a, (Pure () _ r)) -> Right $ Pure () (getTransSpan a b) (r || functionIsRecursive a)- ((None () _ r), (None () _ r')) -> Right $ None () (getTransSpan a b) (r || r')--- Should parse: "elemental pure recursive function f()\nend": Right (Elemental ()) FAILED [4]+emptyPrefixes :: Prefixes a+emptyPrefixes = Nothing -buildPUFunctionOpts :: [PUFunctionOpt ()] -> Either String (PUFunctionOpt())-buildPUFunctionOpts =- foldr merge . Right $ None () initSrcSpan False- where merge a = either Left $ buildPUFunctionOpt a+emptySuffixes :: Suffixes a+emptySuffixes = Nothing -functionIsRecursive :: (PUFunctionOpt a) -> Bool-functionIsRecursive (Elemental _ _) = False-functionIsRecursive (Pure _ _ r) = r-functionIsRecursive (None _ _ r) = r+emptyPrefixSuffix :: PrefixSuffix a+emptyPrefixSuffix = (emptyPrefixes, emptySuffixes) +data Prefix a = PfxRecursive a SrcSpan+ | PfxElemental a SrcSpan+ | PfxPure a SrcSpan+ deriving (Eq, Show, Data, Typeable, Generic, Functor)++-- see C1241 & C1242 (Fortran2003)+validPrefixSuffix :: PrefixSuffix a -> Bool+validPrefixSuffix (mpfxs, msfxs) =+ not (any isElem pfxs) || (not (any isRec pfxs) && not (any isBind sfxs))+ where+ isElem (PfxElemental {}) = True; isElem _ = False+ isRec (PfxRecursive {}) = True; isRec _ = False+ isBind (SfxBind {}) = True+ pfxs = aStrip' mpfxs+ sfxs = aStrip' msfxs++data Suffix a = SfxBind a SrcSpan (Maybe (Expression a))+ deriving (Eq, Show, Data, Typeable, Generic, Functor)+ programUnitBody :: ProgramUnit a -> [Block a] programUnitBody (PUMain _ _ _ bs _) = bs programUnitBody (PUModule _ _ _ bs _) = bs programUnitBody (PUSubroutine _ _ _ _ _ bs _) = bs programUnitBody (PUFunction _ _ _ _ _ _ _ bs _) = bs programUnitBody (PUBlockData _ _ _ bs) = bs-programUnitBody (PUComment {}) = []+programUnitBody PUComment{} = [] updateProgramUnitBody :: ProgramUnit a -> [Block a] -> ProgramUnit a-updateProgramUnitBody (PUMain a s n bs pu) bs' =+updateProgramUnitBody (PUMain a s n _ pu) bs' = PUMain a s n bs' pu-updateProgramUnitBody (PUModule a s n bs pu) bs' =+updateProgramUnitBody (PUModule a s n _ pu) bs' = PUModule a s n bs' pu-updateProgramUnitBody (PUSubroutine a s f n args bs pu) bs' =+updateProgramUnitBody (PUSubroutine a s f n args _ pu) bs' = PUSubroutine a s f n args bs' pu-updateProgramUnitBody (PUFunction a s t f n args res bs pu) bs' =+updateProgramUnitBody (PUFunction a s t f n args res _ pu) bs' = PUFunction a s t f n args res bs' pu-updateProgramUnitBody (PUBlockData a s n bs) bs' =+updateProgramUnitBody (PUBlockData a s n _) bs' = PUBlockData a s n bs'-updateProgramUnitBody p@(PUComment {}) _ = p+updateProgramUnitBody p@PUComment{} _ = p programUnitSubprograms :: ProgramUnit a -> Maybe [ProgramUnit a] programUnitSubprograms (PUMain _ _ _ _ s) = s programUnitSubprograms (PUModule _ _ _ _ s) = s programUnitSubprograms (PUSubroutine _ _ _ _ _ _ s) = s programUnitSubprograms (PUFunction _ _ _ _ _ _ _ _ s) = s-programUnitSubprograms (PUBlockData {}) = Nothing-programUnitSubprograms (PUComment {}) = Nothing+programUnitSubprograms PUBlockData{} = Nothing+programUnitSubprograms PUComment{} = Nothing newtype Comment a = Comment String deriving (Eq, Show, Data, Typeable, Generic, Functor)@@ -229,6 +274,7 @@ | BlInterface a SrcSpan (Maybe (Expression a)) -- label+ Bool -- abstract? [ ProgramUnit a ] -- Routine decls. in the interface [ Block a ] -- Module procedures @@ -242,11 +288,15 @@ | StOptional a SrcSpan (AList Expression a) | StPublic a SrcSpan (Maybe (AList Expression a)) | StPrivate a SrcSpan (Maybe (AList Expression a))+ | StProtected a SrcSpan (Maybe (AList Expression a)) | StSave a SrcSpan (Maybe (AList Expression a)) | StDimension a SrcSpan (AList Declarator a) | StAllocatable a SrcSpan (AList Declarator a)+ | StAsynchronous a SrcSpan (AList Declarator a) | StPointer a SrcSpan (AList Declarator a) | StTarget a SrcSpan (AList Declarator a)+ | StValue a SrcSpan (AList Declarator a)+ | StVolatile a SrcSpan (AList Declarator a) | StData a SrcSpan (AList DataGroup a) | StAutomatic a SrcSpan (AList Declarator a) | StNamelist a SrcSpan (AList Namelist a)@@ -292,6 +342,7 @@ | StTypePrint a SrcSpan (Expression a) (Maybe (AList Expression a)) | StOpen a SrcSpan (AList ControlPair a) | StClose a SrcSpan (AList ControlPair a)+ | StFlush a SrcSpan (AList FlushSpec a) | StInquire a SrcSpan (AList ControlPair a) | StRewind a SrcSpan (AList ControlPair a) | StRewind2 a SrcSpan (Expression a)@@ -299,26 +350,40 @@ | StBackspace2 a SrcSpan (Expression a) | StEndfile a SrcSpan (AList ControlPair a) | StEndfile2 a SrcSpan (Expression a)- | StAllocate a SrcSpan (AList Expression a) (Maybe (ControlPair a))+ | StAllocate a SrcSpan (Maybe (TypeSpec a)) (AList Expression a) (Maybe (AList AllocOpt a)) | StNullify a SrcSpan (AList Expression a)- | StDeallocate a SrcSpan (AList Expression a) (Maybe (ControlPair a))+ | StDeallocate a SrcSpan (AList Expression a) (Maybe (AList AllocOpt a)) | StWhere a SrcSpan (Expression a) (Statement a)- | StWhereConstruct a SrcSpan (Expression a)- | StElsewhere a SrcSpan- | StEndWhere a SrcSpan- | StUse a SrcSpan (Expression a) Only (Maybe (AList Use a))+ | StWhereConstruct a SrcSpan (Maybe String) (Expression a)+ | StElsewhere a SrcSpan (Maybe String) (Maybe (Expression a))+ | StEndWhere a SrcSpan (Maybe String)+ | StUse a SrcSpan (Expression a) (Maybe ModuleNature) Only (Maybe (AList Use a)) | StModuleProcedure a SrcSpan (AList Expression a)+ | StProcedure a SrcSpan (Maybe (ProcInterface a)) (Maybe (Attribute a)) (AList ProcDecl a) | StType a SrcSpan (Maybe (AList Attribute a)) String | StEndType a SrcSpan (Maybe String) | StSequence a SrcSpan | StForall a SrcSpan (Maybe String) (ForallHeader a) | StForallStatement a SrcSpan (ForallHeader a) (Statement a) | StEndForall a SrcSpan (Maybe String)+ | StImport a SrcSpan (AList Expression a)+ | StEnum a SrcSpan+ | StEnumerator a SrcSpan (AList Declarator a)+ | StEndEnum a SrcSpan -- Following is a temporary solution to a complicated FORMAT statement -- parsing problem. | StFormatBogus a SrcSpan String deriving (Eq, Show, Data, Typeable, Generic, Functor) +-- R1214 proc-decl is procedure-entity-name [=> null-init]+data ProcDecl a = ProcDecl a SrcSpan (Expression a) (Maybe (Expression a))+ deriving (Eq, Show, Data, Typeable, Generic, Functor)++-- R1212 proc-interface is interface-name or declaration-type-spec+data ProcInterface a = ProcInterfaceName a SrcSpan (Expression a)+ | ProcInterfaceType a SrcSpan (TypeSpec a)+ deriving (Eq, Show, Data, Typeable, Generic, Functor)+ data ForallHeader a = ForallHeader -- List of tuples: index-name, start subscript, end subscript, optional stride [(Name, Expression a, Expression a, Maybe (Expression a))]@@ -329,6 +394,9 @@ data Only = Exclusive | Permissive deriving (Eq, Show, Data, Typeable, Generic) +data ModuleNature = ModIntrinsic | ModNonIntrinsic+ deriving (Eq, Show, Data, Typeable, Generic)+ data Use a = UseRename a SrcSpan (Expression a) (Expression a) | UseID a SrcSpan (Expression a)@@ -338,18 +406,23 @@ deriving (Eq, Show, Data, Typeable, Generic, Functor) data Attribute a =- AttrParameter a SrcSpan- | AttrPublic a SrcSpan- | AttrPrivate a SrcSpan- | AttrAllocatable a SrcSpan+ AttrAllocatable a SrcSpan+ | AttrAsynchronous a SrcSpan | AttrDimension a SrcSpan (AList DimensionDeclarator a) | AttrExternal a SrcSpan | AttrIntent a SrcSpan Intent | AttrIntrinsic a SrcSpan | AttrOptional a SrcSpan+ | AttrParameter a SrcSpan | AttrPointer a SrcSpan+ | AttrPrivate a SrcSpan+ | AttrProtected a SrcSpan+ | AttrPublic a SrcSpan | AttrSave a SrcSpan+ | AttrSuffix a SrcSpan (Suffix a) -- for language-binding-spec | AttrTarget a SrcSpan+ | AttrValue a SrcSpan+ | AttrVolatile a SrcSpan deriving (Eq, Show, Data, Typeable, Generic, Functor) data Intent = In | Out | InOut@@ -358,6 +431,12 @@ data ControlPair a = ControlPair a SrcSpan (Maybe String) (Expression a) deriving (Eq, Show, Data, Typeable, Generic, Functor) +data AllocOpt a =+ AOStat a SrcSpan (Expression a)+ | AOErrMsg a SrcSpan (Expression a)+ | AOSource a SrcSpan (Expression a)+ deriving (Eq, Show, Data, Typeable, Generic, Functor)+ data ImpList a = ImpList a SrcSpan (TypeSpec a) (AList ImpElement a) deriving (Eq, Show, Data, Typeable, Generic, Functor) @@ -399,6 +478,13 @@ | FIScaleFactor a SrcSpan Integer deriving (Eq, Show, Data, Typeable, Generic, Functor) +data FlushSpec a =+ FSUnit a SrcSpan (Expression a)+ | FSIOStat a SrcSpan (Expression a)+ | FSIOMsg a SrcSpan (Expression a)+ | FSErr a SrcSpan (Expression a)+ deriving (Eq, Show, Data, Typeable, Generic, Functor)+ data DoSpecification a = DoSpecification a SrcSpan (Statement a) (Expression a) (Maybe (Expression a)) deriving (Eq, Show, Data, Typeable, Generic, Functor)@@ -456,6 +542,7 @@ -- ^ Overloaded assignment in interfaces | ValType String | ValStar+ | ValColon -- see R402 / C403 in Fortran2003 spec. deriving (Eq, Show, Data, Typeable, Generic, Functor) data Declarator a =@@ -475,6 +562,8 @@ DeclVariable a (getTransSpan s init) v l (Just init) setInitialisation (DeclArray a s v ds l Nothing) init = DeclArray a (getTransSpan s init) v ds l (Just init)+-- do nothing when there is already a value+setInitialisation d _ = d data DimensionDeclarator a = DimensionDeclarator a SrcSpan (Maybe (Expression a)) (Maybe (Expression a))@@ -485,8 +574,10 @@ | Minus | Not | UnCustom String- deriving (Eq, Show, Data, Typeable, Generic)+ deriving (Eq, Ord, Show, Data, Typeable, Generic) +instance Binary UnaryOp+ data BinaryOp = Addition | Subtraction@@ -506,8 +597,10 @@ | Equivalent | NotEquivalent | BinCustom String- deriving (Eq, Show, Data, Typeable, Generic)+ deriving (Eq, Ord, Show, Data, Typeable, Generic) +instance Binary BinaryOp+ -- Retrieving SrcSpan and Annotation from nodes class Annotated f where getAnnotation :: f a -> a@@ -523,12 +616,15 @@ instance FirstParameter (AList t a) a instance FirstParameter (ProgramUnit a) a-instance FirstParameter (PUFunctionOpt a) a+instance FirstParameter (Prefix a) a+instance FirstParameter (Suffix a) a instance FirstParameter (Block a) a instance FirstParameter (Statement a) a instance FirstParameter (Argument a) a instance FirstParameter (Use a) a instance FirstParameter (TypeSpec a) a+instance FirstParameter (ProcDecl a) a+instance FirstParameter (ProcInterface a) a instance FirstParameter (Selector a) a instance FirstParameter (Attribute a) a instance FirstParameter (ImpList a) a@@ -542,18 +638,23 @@ instance FirstParameter (Expression a) a instance FirstParameter (Index a) a instance FirstParameter (DoSpecification a) a+instance FirstParameter (FlushSpec a) a instance FirstParameter (Declarator a) a instance FirstParameter (DimensionDeclarator a) a instance FirstParameter (ControlPair a) a+instance FirstParameter (AllocOpt a) a instance SecondParameter (AList t a) SrcSpan instance SecondParameter (ProgramUnit a) SrcSpan-instance SecondParameter (PUFunctionOpt a) SrcSpan+instance SecondParameter (Prefix a) SrcSpan+instance SecondParameter (Suffix a) SrcSpan instance SecondParameter (Block a) SrcSpan instance SecondParameter (Statement a) SrcSpan instance SecondParameter (Argument a) SrcSpan instance SecondParameter (Use a) SrcSpan instance SecondParameter (TypeSpec a) SrcSpan+instance SecondParameter (ProcDecl a) SrcSpan+instance SecondParameter (ProcInterface a) SrcSpan instance SecondParameter (Selector a) SrcSpan instance SecondParameter (Attribute a) SrcSpan instance SecondParameter (ImpList a) SrcSpan@@ -567,9 +668,11 @@ instance SecondParameter (Expression a) SrcSpan instance SecondParameter (Index a) SrcSpan instance SecondParameter (DoSpecification a) SrcSpan+instance SecondParameter (FlushSpec a) SrcSpan instance SecondParameter (Declarator a) SrcSpan instance SecondParameter (DimensionDeclarator a) SrcSpan instance SecondParameter (ControlPair a) SrcSpan+instance SecondParameter (AllocOpt a) SrcSpan instance Annotated (AList t) instance Annotated ProgramUnit@@ -578,6 +681,8 @@ instance Annotated Argument instance Annotated Use instance Annotated TypeSpec+instance Annotated ProcDecl+instance Annotated ProcInterface instance Annotated Selector instance Annotated Attribute instance Annotated ImpList@@ -591,18 +696,23 @@ instance Annotated Expression instance Annotated Index instance Annotated DoSpecification+instance Annotated FlushSpec instance Annotated Declarator instance Annotated DimensionDeclarator instance Annotated ControlPair+instance Annotated AllocOpt instance Spanned (AList t a) instance Spanned (ProgramUnit a)-instance Spanned (PUFunctionOpt a)+instance Spanned (Prefix a)+instance Spanned (Suffix a) instance Spanned (Statement a) instance Spanned (Argument a) instance Spanned (Use a) instance Spanned (Attribute a) instance Spanned (TypeSpec a)+instance Spanned (ProcDecl a)+instance Spanned (ProcInterface a) instance Spanned (Selector a) instance Spanned (ImpList a) instance Spanned (ImpElement a)@@ -616,15 +726,17 @@ instance Spanned (Expression a) instance Spanned (Index a) instance Spanned (DoSpecification a)+instance Spanned (FlushSpec a) instance Spanned (Declarator a) instance Spanned (DimensionDeclarator a) instance Spanned (ControlPair a)+instance Spanned (AllocOpt a) instance Spanned (ProgramFile a) where getSpan (ProgramFile _ pus) = case pus of [] -> SrcSpan initPosition initPosition- pus -> getSpan pus+ pus' -> getSpan pus' setSpan _ _ = error "Cannot set span to a program unit" @@ -644,6 +756,11 @@ getSpan (_,y) = getSpan y setSpan _ = undefined +instance (Spanned a, Spanned b) => Spanned (Either a b) where+ getSpan (Left x) = getSpan x+ getSpan (Right x) = getSpan x+ setSpan _ = undefined+ instance {-# OVERLAPPABLE #-} (Spanned a, Spanned b) => Spanned (a, b) where getSpan (x,y) = getTransSpan x y setSpan _ = undefined@@ -670,7 +787,7 @@ setSpan _ = undefined instance {-# OVERLAPPABLE #-} (Spanned a, Spanned b, Spanned c) => Spanned (a, b, c) where- getSpan (x,y,z) = getTransSpan x z+ getSpan (x,_,z) = getTransSpan x z setSpan _ = undefined class (Spanned a, Spanned b) => SpannedPair a b where@@ -719,7 +836,7 @@ setLabel (BlIf a s _ mn conds bs el) l = BlIf a s (Just l) mn conds bs el setLabel (BlDo a s _ mn tl spec bs el) l = BlDo a s (Just l) mn tl spec bs el setLabel (BlDoWhile a s _ n tl spec bs el) l = BlDoWhile a s (Just l) n tl spec bs el- setLabel b l = b+ setLabel b _ = b class Conditioned f where getCondition :: f a -> Maybe (Expression a)@@ -754,7 +871,7 @@ getName (PUFunction _ _ _ _ n _ _ _ _) = Named n getName (PUBlockData _ _ Nothing _) = NamelessBlockData getName (PUBlockData _ _ (Just n) _) = Named n- getName (PUComment {}) = NamelessComment+ getName PUComment{} = NamelessComment setName (Named n) (PUMain a s _ b pus) = PUMain a s (Just n) b pus setName _ (PUMain a s _ b pus) = PUMain a s Nothing b pus setName (Named n) (PUModule a s _ b pus) = PUModule a s n b pus@@ -764,15 +881,21 @@ PUFunction a s r rec n p res b subs setName (Named n) (PUBlockData a s _ b) = PUBlockData a s (Just n) b setName _ (PUBlockData a s _ b) = PUBlockData a s Nothing b+ -- Identity function if first arg is nameless or second arg is comment.+ setName _ a = a instance Out FortranVersion instance Out MetaInfo instance Out a => Out (ProgramFile a) instance Out a => Out (ProgramUnit a)-instance Out a => Out (PUFunctionOpt a)+instance Out a => Out (Prefix a)+instance Out a => Out (Suffix a) instance (Out a, Out (t a)) => Out (AList t a) instance Out a => Out (Statement a)+instance Out a => Out (ProcDecl a)+instance Out a => Out (ProcInterface a) instance Out Only+instance Out ModuleNature instance Out a => Out (Argument a) instance Out a => Out (Use a) instance Out a => Out (Attribute a)@@ -790,13 +913,16 @@ instance Out a => Out (Expression a) instance Out a => Out (Index a) instance Out a => Out (DoSpecification a)+instance Out a => Out (FlushSpec a) 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) instance Out a => Out (ControlPair a)+instance Out a => Out (AllocOpt a) instance Out UnaryOp instance Out BinaryOp instance Out a => Out (ForallHeader a)@@ -804,35 +930,39 @@ -- Classifiers on statement and blocks ASTs nonExecutableStatement :: FortranVersion -> Statement a -> Bool-nonExecutableStatement v s = case s of- StIntent {} -> True- StOptional {} -> True- StPublic {} -> True- StPrivate {} -> True- StSave {} -> True- StDimension {} -> True- StAllocatable {} -> True- StPointer {} -> True- StTarget {} -> True- StData {} -> True- StParameter {} -> True- StImplicit {} -> True- StNamelist {} -> True- StEquivalence {} -> True- StCommon {} -> True- StExternal {} -> True- StIntrinsic {} -> True- StUse {} -> True- StEntry {} -> True- StSequence {} -> True- StType {} -> True- StEndType {} -> True- StFormat {} -> True- StFormatBogus {} -> True- StInclude {} -> True- StDeclaration {} -> True- StStructure {} -> True- _ -> False+nonExecutableStatement _ s = case s of+ StIntent {} -> True+ StOptional {} -> True+ StPublic {} -> True+ StPrivate {} -> True+ StProtected {} -> True+ StSave {} -> True+ StDimension {} -> True+ StAllocatable {} -> True+ StAsynchronous {} -> True+ StPointer {} -> True+ StTarget {} -> True+ StValue {} -> True+ StVolatile {} -> True+ StData {} -> True+ StParameter {} -> True+ StImplicit {} -> True+ StNamelist {} -> True+ StEquivalence {} -> True+ StCommon {} -> True+ StExternal {} -> True+ StIntrinsic {} -> True+ StUse {} -> True+ StEntry {} -> True+ StSequence {} -> True+ StType {} -> True+ StEndType {} -> True+ StFormat {} -> True+ StFormatBogus {} -> True+ StInclude {} -> True+ StDeclaration {} -> True+ StStructure {} -> True+ _ -> False executableStatement :: FortranVersion -> Statement a -> Bool -- Some statements are both executable and non-executable in Fortran 90 upwards@@ -843,9 +973,9 @@ executableStatementBlock :: FortranVersion -> Block a -> Bool executableStatementBlock v (BlStatement _ _ _ s) = executableStatement v s-executableStatementBlock v _ = False+executableStatementBlock _ _ = False nonExecutableStatementBlock :: FortranVersion -> Block a -> Bool nonExecutableStatementBlock v (BlStatement _ _ _ s) = nonExecutableStatement v s-nonExecutableStatementBlock v BlInterface{} = True-nonExecutableStatementBlock v _ = False+nonExecutableStatementBlock _ BlInterface{} = True+nonExecutableStatementBlock _ _ = False
src/Language/Fortran/Analysis.hs view
@@ -1,27 +1,31 @@ {-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable, StandaloneDeriving, DeriveGeneric, TupleSections #-}+{-# OPTIONS_GHC -Wno-orphans #-} -- | -- Common data structures and functions supporting analysis of the AST. module Language.Fortran.Analysis- ( initAnalysis, stripAnalysis, Analysis(..)+ ( initAnalysis, stripAnalysis, Analysis(..), Constant(..) , varName, srcName, lvVarName, lvSrcName, isNamedExpression , genVar, puName, puSrcName, blockRhsExprs, rhsExprs , ModEnv, NameType(..), IDType(..), ConstructType(..), BaseType(..) , lhsExprs, isLExpr, allVars, analyseAllLhsVars, analyseAllLhsVars1, allLhsVars , blockVarUses, blockVarDefs- , BB, BBGr+ , BB, BBNode, BBGr(..), bbgrMap, bbgrMapM, bbgrEmpty , TransFunc, TransFuncM ) where +import Prelude hiding (exp)+import Control.Monad (void) import Language.Fortran.Util.Position (SrcSpan) import Data.Generics.Uniplate.Data import Data.Data import Language.Fortran.AST import Language.Fortran.LValue+import Data.Graph.Inductive (Node, empty) import Data.Graph.Inductive.PatriciaTree (Gr) import GHC.Generics (Generic) import Text.PrettyPrint.GenericPretty-import Text.PrettyPrint+import Text.PrettyPrint hiding (empty, isEmpty) import qualified Data.Map.Strict as M import Data.Maybe import Data.Binary@@ -34,12 +38,32 @@ type BB a = [Block a] -- | Basic block graph.-type BBGr a = Gr (BB a) ()+data BBGr a = BBGr { bbgrGr :: Gr (BB a) () -- ^ the underlying graph+ , bbgrEntries :: [Node] -- ^ the entry node(s)+ , bbgrExits :: [Node] -- ^ the exit node(s)+ }+ deriving (Data, Show, Eq, Generic) +type BBNode = Int++-- | Empty basic block graph+bbgrEmpty :: BBGr a+bbgrEmpty = BBGr empty [] []++-- | Call function on the underlying graph+bbgrMap :: (Gr (BB a) () -> Gr (BB b) ()) -> BBGr a -> BBGr b+bbgrMap f bb = bb { bbgrGr = f (bbgrGr bb) }++-- | Monadically call function on the underlying graph+bbgrMapM :: Monad m => (Gr (BB a1) () -> m (Gr (BB a2) ())) -> BBGr a1 -> m (BBGr a2)+bbgrMapM f bb = do+ x <- f (bbgrGr bb)+ return $ bb { bbgrGr = x }+ -- Allow graphs to reside inside of annotations deriving instance (Typeable a, Typeable b) => Typeable (Gr a b) instance (Typeable a, Typeable b) => Data (Gr a b) where- gfoldl _k z v = z v -- make graphs opaque to Uniplate+ gfoldl _k z = z -- make graphs opaque to Uniplate toConstr _ = error "toConstr" gunfold _ _ = error "gunfold" dataTypeOf _ = mkNoRepType "Gr"@@ -66,7 +90,7 @@ | CTSubroutine | CTExternal | CTVariable- | CTArray+ | CTArray [(Maybe Int, Maybe Int)] | CTParameter | CTIntrinsic deriving (Ord, Eq, Show, Data, Typeable, Generic)@@ -82,6 +106,18 @@ instance Out IDType instance Binary IDType +-- | Information about potential / actual constant expressions.+data Constant+ = ConstInt Integer -- ^ interpreted integer+ | ConstUninterpInt String -- ^ uninterpreted integer+ | ConstUninterpReal String -- ^ uninterpreted real+ | ConstBinary BinaryOp Constant Constant -- ^ binary operation on potential constants+ | ConstUnary UnaryOp Constant -- ^ unary operation on potential constants+ deriving (Show, Ord, Eq, Typeable, Generic, Data)++instance Out Constant+instance Binary Constant+ data Analysis a = Analysis { prevAnnotation :: a -- ^ original annotation , uniqueName :: Maybe String -- ^ unique name for function/variable, after variable renaming phase@@ -91,6 +127,7 @@ , moduleEnv :: Maybe ModEnv , idType :: Maybe IDType , allLhsVarsAnn :: [Name]+ , constExp :: Maybe Constant } deriving (Data, Show, Eq, Generic) @@ -100,11 +137,12 @@ { prevAnnotation = f (prevAnnotation analysis) , uniqueName = uniqueName analysis , sourceName = sourceName analysis- , bBlocks = fmap (first . fmap . fmap . fmap $ f) . bBlocks $ analysis+ , bBlocks = fmap (bbgrMap (first . fmap . fmap . fmap $ f)) . bBlocks $ analysis , insLabel = insLabel analysis , moduleEnv = moduleEnv analysis , idType = idType analysis , allLhsVarsAnn = allLhsVarsAnn analysis+ , constExp = constExp analysis } instance Out (Analysis a) where@@ -115,6 +153,7 @@ , ("idType: ", fmap show (idType a)) ] docPrec _ = doc +analysis0 :: a -> Analysis a analysis0 a = Analysis { prevAnnotation = a , uniqueName = Nothing , sourceName = Nothing@@ -122,7 +161,8 @@ , insLabel = Nothing , moduleEnv = Nothing , idType = Nothing- , allLhsVarsAnn = [] }+ , allLhsVarsAnn = []+ , constExp = Nothing } -- | True iff the expression can be used with varName or srcName isNamedExpression :: Expression a -> Bool@@ -132,32 +172,32 @@ -- | Obtain either uniqueName or source name from an ExpValue variable. varName :: Expression (Analysis a) -> String-varName (ExpValue (Analysis { uniqueName = Just n }) _ (ValVariable {})) = n-varName (ExpValue (Analysis { sourceName = Just n }) _ (ValVariable {})) = n-varName (ExpValue _ _ (ValVariable n)) = n-varName (ExpValue (Analysis { uniqueName = Just n }) _ (ValIntrinsic {})) = n-varName (ExpValue (Analysis { sourceName = Just n }) _ (ValIntrinsic {})) = n-varName (ExpValue _ _ (ValIntrinsic n)) = n-varName _ = error "Use of varName on non-variable."+varName (ExpValue Analysis { uniqueName = Just n } _ ValVariable{}) = n+varName (ExpValue Analysis { sourceName = Just n } _ ValVariable{}) = n+varName (ExpValue _ _ (ValVariable n)) = n+varName (ExpValue Analysis { uniqueName = Just n } _ ValIntrinsic{}) = n+varName (ExpValue Analysis { sourceName = Just n } _ ValIntrinsic{}) = n+varName (ExpValue _ _ (ValIntrinsic n)) = n+varName _ = error "Use of varName on non-variable." -- | Obtain the source name from an ExpValue variable. srcName :: Expression (Analysis a) -> String-srcName (ExpValue (Analysis { sourceName = Just n }) _ (ValVariable {})) = n-srcName (ExpValue _ _ (ValVariable n)) = n-srcName (ExpValue (Analysis { sourceName = Just n }) _ (ValIntrinsic {})) = n-srcName (ExpValue _ _ (ValIntrinsic n)) = n-srcName _ = error "Use of srcName on non-variable."+srcName (ExpValue Analysis { sourceName = Just n } _ ValVariable{}) = n+srcName (ExpValue _ _ (ValVariable n)) = n+srcName (ExpValue Analysis { sourceName = Just n } _ ValIntrinsic{}) = n+srcName (ExpValue _ _ (ValIntrinsic n)) = n+srcName _ = error "Use of srcName on non-variable." -- | Obtain either uniqueName or source name from an LvSimpleVar variable. lvVarName :: LValue (Analysis a) -> String-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."+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 (LvSimpleVar (Analysis { sourceName = Just n }) _ _) = n+lvSrcName (LvSimpleVar Analysis { sourceName = Just n } _ _) = n lvSrcName (LvSimpleVar _ _ n) = n lvSrcName _ = error "Use of lvSrcName on a non-variable" @@ -219,9 +259,9 @@ -- | Is this an expression capable of assignment? isLExpr :: Expression a -> Bool-isLExpr (ExpValue _ _ (ValVariable {})) = True-isLExpr (ExpSubscript _ _ _ _) = True-isLExpr _ = False+isLExpr (ExpValue _ _ ValVariable {}) = True+isLExpr ExpSubscript{} = True+isLExpr _ = False -- | Set of names found in an AST node. allVars :: forall a b. (Data a, Data (b (Analysis a))) => b (Analysis a) -> [Name]@@ -243,10 +283,10 @@ -- an assignment statement. -- allLhsVars :: (Annotated b, Data a, Data (b (Analysis a))) => b (Analysis a) -> [Name] allLhsVars :: Data a => Block (Analysis a) -> [Name]-allLhsVars x = allLhsVarsAnn . getAnnotation $ x+allLhsVars = allLhsVarsAnn . getAnnotation allLhsVarsDoSpec :: Data a => DoSpecification (Analysis a) -> [Name]-allLhsVarsDoSpec x = computeAllLhsVars x+allLhsVarsDoSpec = computeAllLhsVars -- | Set of names found in the parts of an AST that are the target of -- an assignment statement.@@ -255,11 +295,16 @@ where lhsOfStmt :: Statement (Analysis a) -> [Name] lhsOfStmt (StExpressionAssign _ _ e e') = match' e : onExprs e'+ lhsOfStmt (StDeclaration _ _ _ _ decls) = concat [ lhsOfDecls decl | decl <- universeBi decls ] lhsOfStmt (StCall _ _ f@(ExpValue _ _ (ValIntrinsic _)) _) | Just defs <- intrinsicDefs f = defs lhsOfStmt (StCall _ _ _ (Just aexps)) = concatMap (match'' . extractExp) (aStrip aexps) lhsOfStmt s = onExprs s + lhsOfDecls (DeclVariable _ _ e _ (Just e')) = match' e : onExprs e'+ lhsOfDecls (DeclArray _ _ e _ _ (Just e')) = match' e : onExprs e'+ lhsOfDecls _ = []+ onExprs :: (Data (c (Analysis a))) => c (Analysis a) -> [Name] onExprs = concatMap lhsOfExp . universeBi @@ -270,22 +315,22 @@ extractExp (Argument _ _ _ exp) = exp -- Match and give the varname for LHS of statement- match' v@(ExpValue _ _ (ValVariable {})) = varName v- match' (ExpSubscript _ _ v@(ExpValue _ _ (ValVariable {})) _) = varName v+ match' v@(ExpValue _ _ ValVariable{}) = varName v+ match' (ExpSubscript _ _ v@(ExpValue _ _ ValVariable{}) _) = varName v match' (ExpDataRef _ _ v _) = match' v- match' e = error $ "An unexpected LHS to an expression assign: " ++ show (fmap (const ()) e)+ match' e = error $ "An unexpected LHS to an expression assign: " ++ show (void (const ()) e) -- Match and give the varname of LHSes which occur in subroutine calls- match'' v@(ExpValue _ _ (ValVariable {})) = [varName v]- match'' (ExpSubscript _ _ v@(ExpValue _ _ (ValVariable {})) _) = [varName v]- match'' (ExpDataRef _ _ v _) = match'' v- match'' e = onExprs e+ match'' v@(ExpValue _ _ ValVariable{}) = [varName v]+ match'' (ExpSubscript _ _ v@(ExpValue _ _ ValVariable{}) _) = [varName v]+ match'' (ExpDataRef _ _ v _) = match'' v+ match'' e = onExprs e -- Match and give the varname of LHSes which occur in function calls- match v@(ExpValue _ _ (ValVariable {})) = [varName v]- match (ExpSubscript _ _ v@(ExpValue _ _ (ValVariable {})) _) = [varName v]- match (ExpDataRef _ _ e _) = match e- match e = []+ match v@(ExpValue _ _ ValVariable{}) = [varName v]+ match (ExpSubscript _ _ v@(ExpValue _ _ ValVariable{}) _) = [varName v]+ match (ExpDataRef _ _ e _) = match e+ match _ = [] -- | Set of expressions used -- not defined -- by an AST-block. blockRhsExprs :: Data a => Block a -> [Expression a]@@ -302,23 +347,28 @@ statementRhsExprs (StExpressionAssign _ _ lhs rhs) | ExpSubscript _ _ _ subs <- lhs = universeBi rhs ++ universeBi subs | otherwise = universeBi rhs-statementRhsExprs (StDeclaration {}) = []+statementRhsExprs StDeclaration{} = [] statementRhsExprs (StIfLogical _ _ _ s) = statementRhsExprs s-statementRhsExprs (StDo _ _ _ l s) = (universeBi l) ++ doSpecRhsExprs s+statementRhsExprs (StDo _ _ _ l s') = universeBi l ++ doSpecRhsExprs s' where doSpecRhsExprs (Just (DoSpecification _ _ s e1 e2)) =- (e1 : (universeBi e2)) ++ statementRhsExprs s+ (e1 : universeBi e2) ++ statementRhsExprs s doSpecRhsExprs Nothing = [] statementRhsExprs s = universeBi s -- | Set of names used -- not defined -- by an AST-block.-blockVarUses :: Data a => Block (Analysis a) -> [Name]+blockVarUses :: forall a. Data a => Block (Analysis a) -> [Name] blockVarUses (BlStatement _ _ _ (StExpressionAssign _ _ lhs rhs)) | ExpSubscript _ _ _ subs <- lhs = allVars rhs ++ concatMap allVars (aStrip subs) | otherwise = allVars rhs blockVarUses (BlDo _ _ _ _ _ (Just (DoSpecification _ _ (StExpressionAssign _ _ lhs rhs) e1 e2)) _ _) | ExpSubscript _ _ _ subs <- lhs = allVars rhs ++ allVars e1 ++ maybe [] allVars e2 ++ concatMap allVars (aStrip subs) | otherwise = allVars rhs ++ allVars e1 ++ maybe [] allVars e2-blockVarUses (BlStatement _ _ _ (StDeclaration {})) = []+blockVarUses (BlStatement _ _ _ st@StDeclaration{}) = concat [ rhsOfDecls d | d <- universeBi st ]+ where+ rhsOfDecls :: Data a => Declarator (Analysis a) -> [Name]+ rhsOfDecls (DeclVariable _ _ _ _ (Just e)) = allVars e+ rhsOfDecls (DeclArray _ _ _ _ _ (Just e)) = allVars e+ rhsOfDecls _ = [] blockVarUses (BlStatement _ _ _ (StCall _ _ f@(ExpValue _ _ (ValIntrinsic _)) _)) | Just uses <- intrinsicUses f = uses blockVarUses (BlStatement _ _ _ (StCall _ _ _ (Just aexps))) = allVars aexps@@ -328,7 +378,7 @@ -- | Set of names defined by an AST-block. blockVarDefs :: Data a => Block (Analysis a) -> [Name]-blockVarDefs b@(BlStatement _ _ _ st) = allLhsVars b+blockVarDefs b@BlStatement{} = allLhsVars b blockVarDefs (BlDo _ _ _ _ _ (Just doSpec) _ _) = allLhsVarsDoSpec doSpec blockVarDefs _ = [] @@ -347,7 +397,7 @@ -- return dummy arg names (defined, used) by intrinsic intrinsicDefsUses :: Expression (Analysis a) -> Maybe ([Name], [Name]) intrinsicDefsUses f = both (map (dummyArg (varName f))) <$> getIntrinsicDefsUses (srcName f) allIntrinsics- where both f (x, y) = (f x, f y)+ where both f' (x, y) = (f' x, f' y) -- Local variables: -- mode: haskell
src/Language/Fortran/Analysis/BBlocks.hs view
@@ -1,20 +1,22 @@ -- | Analyse a program file and create basic blocks. -{-# LANGUAGE FlexibleContexts, PatternGuards, ScopedTypeVariables #-}+{-# LANGUAGE TupleSections, FlexibleContexts, PatternGuards, ScopedTypeVariables #-} module Language.Fortran.Analysis.BBlocks- ( analyseBBlocks, genBBlockMap, showBBGr, showAnalysedBBGr, showBBlocks, bbgrToDOT, BBlockMap- , genSuperBBGr, SuperBBGr, showSuperBBGr, superBBGrToDOT, superBBGrGraph, superBBGrClusters, superBBGrEntries- , findLabeledBBlock )+ ( analyseBBlocks, genBBlockMap, showBBGr, showAnalysedBBGr, showBBlocks, bbgrToDOT, BBlockMap, ASTBlockNode, ASTExprNode+ , genSuperBBGr, SuperBBGr(..), showSuperBBGr, superBBGrToDOT, findLabeledBBlock, showBlock ) where -import Data.Generics.Uniplate.Data+import Prelude hiding (exp)+import Data.Generics.Uniplate.Data hiding (transform)+import Data.Char (toLower) import Data.Data+import Data.List (unfoldr, foldl') import Control.Monad-import Control.Monad.State.Lazy-import Control.Monad.Writer+import Control.Monad.State.Lazy hiding (fix)+import Control.Monad.Writer hiding (fix) import Text.PrettyPrint.GenericPretty (pretty, Out) import Language.Fortran.Analysis-import Language.Fortran.AST+import Language.Fortran.AST hiding (setName) import Language.Fortran.Util.Position import qualified Data.Map as M import qualified Data.IntMap as IM@@ -22,6 +24,7 @@ import Data.Graph.Inductive.PatriciaTree (Gr) import Data.List (intercalate) import Data.Maybe+import Data.Functor.Identity -------------------------------------------------- @@ -48,16 +51,18 @@ -------------------------------------------------- +type ASTBlockNode = Int+ -- Insert unique labels on each AST-block for easier look-up later.-labelBlocks :: Data a => ProgramFile (Analysis a) -> State Int (ProgramFile (Analysis a))-labelBlocks gr = transform eachBlock gr+labelBlocks :: Data a => ProgramFile (Analysis a) -> State ASTBlockNode (ProgramFile (Analysis a))+labelBlocks = transform eachBlock where- eachBlock :: Data a => Block (Analysis a) -> State Int (Block (Analysis a))+ eachBlock :: Data a => Block (Analysis a) -> State ASTBlockNode (Block (Analysis a)) eachBlock b = do n <- get- put $ (n + 1)+ put (n + 1) return . labelWithinBlocks $ setAnnotation ((getAnnotation b) { insLabel = Just n }) b- transform :: Data a => TransFuncM (State Int) Block ProgramFile a+ transform :: Data a => TransFuncM (State ASTBlockNode) Block ProgramFile a transform = transformBiM -- A version of labelBlocks that works on all AST-blocks inside of a@@ -65,27 +70,27 @@ -- numbers. The reason that this function must exist is because -- additional AST-blocks are generated within the process of creating -- basic-block graphs, and must also be labelled.-labelBlocksInBBGr :: Data a => ProgramFile (Analysis a) -> State Int (ProgramFile (Analysis a))-labelBlocksInBBGr pf = transform (nmapM' (mapM eachBlock)) pf+labelBlocksInBBGr :: Data a => ProgramFile (Analysis a) -> State ASTBlockNode (ProgramFile (Analysis a))+labelBlocksInBBGr = transform (bbgrMapM (nmapM' (mapM eachBlock))) where- eachBlock :: Data a => Block (Analysis a) -> State Int (Block (Analysis a))+ eachBlock :: Data a => Block (Analysis a) -> State ASTBlockNode (Block (Analysis a)) eachBlock b | a@Analysis { insLabel = Nothing } <- getAnnotation b = do n <- get put $ n + 1 return . analyseAllLhsVars1 . labelWithinBlocks $ setAnnotation (a { insLabel = Just n }) b | otherwise = return . analyseAllLhsVars1 $ b- transform :: Data a => (BBGr a -> State Int (BBGr a)) ->- ProgramFile a -> State Int (ProgramFile a)+ transform :: Data a => (BBGr a -> State ASTBlockNode (BBGr a)) ->+ ProgramFile a -> State ASTBlockNode (ProgramFile a) transform = transformBiM -- Sets the label on each Index within a Block to match the Block, for -- later look-up. labelWithinBlocks :: forall a. Data a => Block (Analysis a) -> Block (Analysis a)-labelWithinBlocks = perBlock+labelWithinBlocks = perBlock' where- perBlock :: Block (Analysis a) -> Block (Analysis a)- perBlock b =+ perBlock' :: Block (Analysis a) -> Block (Analysis a)+ perBlock' b = case b of BlStatement a s e st -> BlStatement a s (mfill i e) (fill i st) BlIf a s e1 mn e2 bss el -> BlIf a s (mfill i e1) mn (mmfill i e2) bss el@@ -98,7 +103,7 @@ mfill i = fmap (fill i) mmfill i = fmap (fmap (fill i)) - fill :: forall f. (Data (f (Analysis a))) => Maybe Int -> f (Analysis a) -> f (Analysis a)+ fill :: forall f. (Data (f (Analysis a))) => Maybe ASTBlockNode -> f (Analysis a) -> f (Analysis a) fill Nothing = id fill (Just i) = transform perIndex where@@ -110,16 +115,18 @@ -------------------------------------------------- +type ASTExprNode = Int+ -- Insert unique labels on each expression for easier look-up later.-labelExprs :: Data a => ProgramFile (Analysis a) -> State Int (ProgramFile (Analysis a))-labelExprs gr = transform eachExpr gr+labelExprs :: Data a => ProgramFile (Analysis a) -> State ASTExprNode (ProgramFile (Analysis a))+labelExprs = transform eachExpr where- eachExpr :: Data a => Expression (Analysis a) -> State Int (Expression (Analysis a))+ eachExpr :: Data a => Expression (Analysis a) -> State ASTExprNode (Expression (Analysis a)) eachExpr e = do n <- get- put $ (n + 1)+ put (n + 1) return $ setAnnotation ((getAnnotation e) { insLabel = Just n }) e- transform :: Data a => TransFuncM (State Int) Expression ProgramFile a+ transform :: Data a => TransFuncM (State ASTExprNode) Expression ProgramFile a transform = transformBiM -- A version of labelExprs that works on all expressions inside of a@@ -127,21 +134,21 @@ -- numbers. The reason that this function must exist is because -- additional expressions are generated within the process of creating -- basic-block graphs, and must also be labelled.-labelExprsInBBGr :: Data a => ProgramFile (Analysis a) -> State Int (ProgramFile (Analysis a))-labelExprsInBBGr pf = transformBB (nmapM' (transformExpr eachExpr)) pf+labelExprsInBBGr :: Data a => ProgramFile (Analysis a) -> State ASTExprNode (ProgramFile (Analysis a))+labelExprsInBBGr = transformBB (bbgrMapM (nmapM' (transformExpr eachExpr))) where- eachExpr :: Data a => Expression (Analysis a) -> State Int (Expression (Analysis a))+ eachExpr :: Data a => Expression (Analysis a) -> State ASTExprNode (Expression (Analysis a)) eachExpr e | a@Analysis { insLabel = Nothing } <- getAnnotation e = do n <- get put $ n + 1 return $ setAnnotation (a { insLabel = Just n }) e | otherwise = return e- transformBB :: Data a => (BBGr a -> State Int (BBGr a)) ->- ProgramFile a -> State Int (ProgramFile a)+ transformBB :: Data a => (BBGr a -> State ASTExprNode (BBGr a)) ->+ ProgramFile a -> State ASTExprNode (ProgramFile a) transformBB = transformBiM- transformExpr :: Data a => (Expression (Analysis a) -> State Int (Expression (Analysis a))) ->- [Block (Analysis a)] -> State Int [Block (Analysis a)]+ transformExpr :: Data a => (Expression (Analysis a) -> State ASTExprNode (Expression (Analysis a))) ->+ [Block (Analysis a)] -> State ASTExprNode [Block (Analysis a)] transformExpr = transformBiM --------------------------------------------------@@ -154,45 +161,49 @@ where bs = case pu of- PUMain _ _ _ bs _ -> bs;- PUSubroutine _ _ _ _ _ bs _ -> bs;- PUFunction _ _ _ _ _ _ _ bs _ -> bs+ PUMain _ _ _ bs' _ -> bs';+ PUSubroutine _ _ _ _ _ bs' _ -> bs';+ PUFunction _ _ _ _ _ _ _ bs' _ -> bs' _ -> [] bbs = execBBlocker (processBlocks bs) fix = delEmptyBBlocks . delUnreachable . insExitEdges pu lm . delInvalidExits . insEntryEdges pu- gr = fix (insEdges (newEdges bbs) (bbGraph bbs))- pu' = setAnnotation ((getAnnotation pu) { bBlocks = Just gr }) pu+ gr = bbgrMap (fix . insEdges (newEdges bbs)) $ bbGraph bbs+ gr' = gr { bbgrEntries = [0], bbgrExits = [-1] } -- conventional entry/exit blocks+ pu' = setAnnotation ((getAnnotation pu) { bBlocks = Just gr' }) pu lm = labelMap bbs -- Create node 0 "the start node" and link it -- for now assume only one entry+insEntryEdges :: (Data a, DynGraph gr) => ProgramUnit (Analysis a) -> gr [Block (Analysis a)] () -> gr [Block (Analysis a)] () insEntryEdges pu = insEdge (0, 1, ()) . insNode (0, bs) where bs = genInOutAssignments pu False -- create assignments of the form "x = f[1]" or "f[1] = x" at the -- entry/exit bblocks.+genInOutAssignments :: Data a => ProgramUnit (Analysis a) -> Bool -> [Block (Analysis a)] genInOutAssignments pu exit- | exit, PUFunction _ _ _ _ _ _ _ _ _ <- pu = zipWith genAssign (genVar a0 noSrcSpan fn:vs) [0..]- | otherwise = zipWith genAssign vs [1..]+ | exit, PUFunction{} <- pu = zipWith genAssign (genVar a0 noSrcSpan fn:vs) [(0::Integer)..]+ | otherwise = zipWith genAssign vs [(1::Integer)..] where Named fn = puName pu name i = fn ++ "[" ++ show i ++ "]" a0 = head $ initAnalysis [prevAnnotation a] (a, s, vs) = case pu of- PUFunction _ _ _ _ _ (Just (AList a s vs)) _ _ _ -> (a, s, vs)- PUSubroutine _ _ _ _ (Just (AList a s vs)) _ _ -> (a, s, vs)- PUFunction a s _ _ _ Nothing _ _ _ -> (a, s, [])- PUSubroutine a s _ _ Nothing _ _ -> (a, s, [])+ PUFunction _ _ _ _ _ (Just (AList a' s' vs')) _ _ _ -> (a', s', vs')+ PUSubroutine _ _ _ _ (Just (AList a' s' vs')) _ _ -> (a', s', vs')+ PUFunction a' s' _ _ _ Nothing _ _ _ -> (a', s', [])+ PUSubroutine a' s' _ _ Nothing _ _ -> (a', s', []) _ -> (error "genInOutAssignments", error "genInOutAssignments", []) genAssign v i = analyseAllLhsVars1 $ BlStatement a0 s Nothing (StExpressionAssign a0 s vl vr) where (vl, vr) = if exit then (v', v) else (v, v') v' = case v of- ExpValue a' s (ValVariable _) -> genVar a0 s (name i)- _ -> error $ "unhandled genAssign case: " ++ show (fmap (const ()) v)+ ExpValue _ s' (ValVariable _) -> genVar a0 s' (name i)+ _ -> error $ "unhandled genAssign case: " ++ show (void (const ()) v) -- Remove exit edges for bblocks where standard construction doesn't apply.+delInvalidExits :: DynGraph gr => gr [Block a] b -> gr [Block a] b delInvalidExits gr = flip delEdges gr $ do n <- nodes gr bs <- maybeToList $ lab gr n@@ -201,40 +212,81 @@ return $ toEdge le -- Insert exit edges for bblocks with special handling.+insExitEdges :: (Data a, DynGraph gr) => ProgramUnit (Analysis a) -> M.Map String Node -> gr [Block (Analysis a)] () -> gr [Block (Analysis a)] () insExitEdges pu lm gr = flip insEdges (insNode (-1, bs) gr) $ do n <- nodes gr- guard $ null (out gr n)- bs <- maybeToList $ lab gr n- n' <- examineFinalBlock lm bs+ bs' <- maybeToList $ lab gr n+ guard $ null (out gr n) || isFinalBlockExceptionalCtrlXfer bs'+ n' <- examineFinalBlock lm bs' return (n, n', ()) where bs = genInOutAssignments pu True +-- Given a list of ControlPairs for a StRead, return (if any exists)+-- the expression accompanying an END or ERR, respectively+getReadCtrlXfers :: [ControlPair a] -> (Maybe (Expression a), Maybe (Expression a))+getReadCtrlXfers = foldl' handler (Nothing, Nothing)+ where+ handler r@(r1, r2) (ControlPair _ _ ms e) = case ms of+ Nothing -> r+ Just s ->+ case map toLower s of+ "end" -> (Just e, r2)+ "err" -> (r1, Just e)+ _ -> r+ -- Find target of Goto statements (Return statements default target to -1).+examineFinalBlock :: Num a1 => M.Map String a1 -> [Block a2] -> [a1] examineFinalBlock lm bs@(_:_) | BlStatement _ _ _ (StGotoUnconditional _ _ k) <- last bs = [lookupBBlock lm k] | BlStatement _ _ _ (StGotoAssigned _ _ _ ks) <- last bs = map (lookupBBlock lm) (maybe [] aStrip ks) | BlStatement _ _ _ (StGotoComputed _ _ ks _) <- last bs = map (lookupBBlock lm) (aStrip ks)- | BlStatement _ _ _ (StReturn _ _ _) <- last bs = [-1]+ | BlStatement _ _ _ StReturn{} <- last bs = [-1] | BlStatement _ _ _ (StIfArithmetic _ _ _ k1 k2 k3) <- last bs = [lookupBBlock lm k1, lookupBBlock lm k2, lookupBBlock lm k3]+ | BlStatement _ _ _ (StRead _ _ cs _) <- last bs =+ let (me, mr) = getReadCtrlXfers $ aStrip cs+ f = maybe [] $ \v -> [lookupBBlock lm v]+ in f me ++ f mr examineFinalBlock _ _ = [-1] -- True iff the final block in the list is an explicit control transfer.+isFinalBlockCtrlXfer :: [Block a] -> Bool isFinalBlockCtrlXfer bs@(_:_)- | BlStatement _ _ _ (StGotoUnconditional {}) <- last bs = True- | BlStatement _ _ _ (StGotoAssigned {}) <- last bs = True- | BlStatement _ _ _ (StGotoComputed {}) <- last bs = True- | BlStatement _ _ _ (StReturn {}) <- last bs = True- | BlStatement _ _ _ (StIfArithmetic {}) <- last bs = True-isFinalBlockCtrlXfer _ = False+ | BlStatement _ _ _ StGotoUnconditional{} <- last bs = True+ | BlStatement _ _ _ StGotoAssigned{} <- last bs = True+ | BlStatement _ _ _ StReturn{} <- last bs = True+ | BlStatement _ _ _ StIfArithmetic{} <- last bs = True+ -- Note that StGotoComputed is not handled here since it+ -- is not an explicit control transfer if the expression+ -- does not index into one of the labels, in which case+ -- it acts as a StContinue+isFinalBlockCtrlXfer _ = False -lookupBBlock lm (ExpValue _ _ (ValInteger l)) = (-1) `fromMaybe` M.lookup l lm+-- True iff the final block in the list has an control transfer+-- with exceptional circumstances, like a StGotoComputed or a StRead+isFinalBlockExceptionalCtrlXfer :: [Block a] -> Bool+isFinalBlockExceptionalCtrlXfer bs@(_:_)+ | BlStatement _ _ _ StGotoComputed{} <- last bs = True+ | BlStatement _ _ _ StRead{} <- last bs = True+isFinalBlockExceptionalCtrlXfer _ = False++-- Drop any '0' that appear at the beginning of a label since+-- labels like "40" and "040" are considered equivalent.+dropLeadingZeroes :: String -> String+dropLeadingZeroes = dropWhile (== '0')++lookupBBlock :: Num a1 => M.Map String a1 -> Expression a2 -> a1+lookupBBlock lm a =+ case a of+ ExpValue _ _ (ValInteger l) -> (-1) `fromMaybe` M.lookup (dropLeadingZeroes l) lm -- This occurs if a variable is being used for a label, e.g., from a Fortran 77 ASSIGN statement-lookupBBlock lm (ExpValue _ _ (ValVariable l)) = (-1) `fromMaybe` M.lookup l lm+ ExpValue _ _ (ValVariable l) -> (-1) `fromMaybe` M.lookup l lm+ _ -> error "unhandled lookupBBlock" -- Seek out empty bblocks with a single entrance and a single exit -- edge, and remove them, re-establishing the edges without them.+delEmptyBBlocks :: (Foldable t, DynGraph gr) => gr (t a) b -> gr (t a) b delEmptyBBlocks gr | (n, s, t, l):_ <- candidates = delEmptyBBlocks . insEdge (s, t, l) . delNode n $ gr | otherwise = gr@@ -247,6 +299,7 @@ return (n, s, t, l) -- Delete unreachable nodes.+delUnreachable :: DynGraph gr => gr a b -> gr a b delUnreachable gr = subgraph (reachable 0 gr) gr --------------------------------------------------@@ -261,7 +314,8 @@ , newEdges :: [LEdge ()] } -- Initial state-bbs0 = BBS { bbGraph = empty, curBB = [], curNode = 1+bbs0 :: BBState a+bbs0 = BBS { bbGraph = bbgrEmpty, curBB = [], curNode = 1 , labelMap = M.empty, nums = [2..], tempNums = [0..] , newEdges = [] } @@ -283,7 +337,7 @@ startN <- gets curNode mapM_ perBlock bs endN <- gets curNode- modify $ \ st -> st { bbGraph = insNode (endN, reverse (curBB st)) (bbGraph st)+ modify $ \ st -> st { bbGraph = bbgrMap (insNode (endN, reverse (curBB st))) (bbGraph st) , curBB = [] } return (startN, endN) @@ -295,14 +349,14 @@ -- invariant: curBB is in reverse order perBlock b@(BlIf _ _ _ _ exps bss _) = do processLabel b- exps' <- forM (map fromJust . filter isJust $ exps) processFunctionCalls+ _ <- forM (catMaybes . filter isJust $ exps) processFunctionCalls addToBBlock $ stripNestedBlocks b (ifN, _) <- closeBBlock -- go through nested AST-blocks startEnds <- forM bss $ \ bs -> do (thenN, endN) <- processBlocks bs- genBBlock+ _ <- genBBlock return (thenN, endN) -- connect all the new bblocks with edges, link to subsequent bblock labeled nxtN@@ -319,7 +373,7 @@ -- go through nested AST-blocks startEnds <- forM bss $ \ bs -> do (caseN, endN) <- processBlocks bs- genBBlock+ _ <- genBBlock return (caseN, endN) -- connect all the new bblocks with edges, link to subsequent bblock labeled nxtN@@ -328,77 +382,102 @@ -- if there is no "CASE DEFAULT"-statement then we need an edge from selectN -> nxtN createEdges $ if any isNothing inds then es else (selectN, nxtN, ()):es +perBlock b@(BlStatement _ _ _ (StGotoComputed _ _ _ exp)) = do+ processLabel b+ _ <- processFunctionCalls exp+ addToBBlock b+ (gotoN, nxtN) <- closeBBlock+ createEdges [(gotoN, nxtN, ())]+ perBlock b@(BlStatement a ss _ (StIfLogical _ _ exp stm)) = do processLabel b- exp' <- processFunctionCalls exp+ _ <- processFunctionCalls exp addToBBlock $ stripNestedBlocks b -- start a bblock for the nested statement inside the If (ifN, thenN) <- closeBBlock -- build pseudo-AST-block to contain nested statement- processBlocks [BlStatement a ss Nothing stm]- endN <- gets curNode+ _ <- processBlocks [BlStatement a{ insLabel = Nothing } ss Nothing stm]+ _ <- gets curNode -- connect all the new bblocks with edges, link to subsequent bblock labeled nxtN nxtN <- genBBlock createEdges [(ifN, thenN, ()), (ifN, nxtN, ()), (thenN, nxtN, ())] -perBlock b@(BlStatement _ _ _ (StIfArithmetic {})) =+perBlock b@(BlStatement _ _ _ StIfArithmetic{}) = -- Treat an arithmetic if similarly to a goto processLabel b >> addToBBlock b >> closeBBlock_-perBlock b@(BlDo _ _ mlab _ _ (Just spec) bs _) = do+perBlock b@(BlDo _ _ _ _ _ (Just spec) bs _) = do let DoSpecification _ _ (StExpressionAssign _ _ _ e1) e2 me3 = spec- e1' <- processFunctionCalls e1- e2' <- processFunctionCalls e2- me3' <- case me3 of Just e3 -> Just `fmap` processFunctionCalls e3; Nothing -> return Nothing+ _ <- processFunctionCalls e1+ _ <- processFunctionCalls e2+ _ <- case me3 of Just e3 -> Just `fmap` processFunctionCalls e3; Nothing -> return Nothing perDoBlock Nothing b bs perBlock b@(BlDo _ _ _ _ _ Nothing bs _) = perDoBlock Nothing b bs perBlock b@(BlDoWhile _ _ _ _ _ exp bs _) = perDoBlock (Just exp) b bs-perBlock b@(BlStatement _ _ _ (StReturn {})) =+perBlock b@(BlStatement _ _ _ StReturn{}) = processLabel b >> addToBBlock b >> closeBBlock_-perBlock b@(BlStatement _ _ _ (StGotoUnconditional {})) =+perBlock b@(BlStatement _ _ _ StGotoUnconditional{}) = processLabel b >> addToBBlock b >> closeBBlock_-perBlock b@(BlStatement a s l (StCall a' s' cn@(ExpValue _ _ _) Nothing)) = do+perBlock b@(BlStatement _ _ _ (StCall _ _ ExpValue{} Nothing)) = do (prevN, callN) <- closeBBlock -- put StCall in a bblock by itself addToBBlock b (_, nextN) <- closeBBlock createEdges [ (prevN, callN, ()), (callN, nextN, ()) ]-perBlock b@(BlStatement a s l (StCall a' s' cn@(ExpValue _ _ _) (Just aargs))) = do+perBlock (BlStatement a s l (StCall a' s' cn@ExpValue{} (Just aargs))) = do+ let a0 = head . initAnalysis $ [prevAnnotation a] let exps = map extractExp . aStrip $ aargs (prevN, formalN) <- closeBBlock -- create bblock that assigns formal parameters (n[1], n[2], ...) case l of- Just (ExpValue _ _ (ValInteger l)) -> insertLabel l formalN -- label goes here, if present- _ -> return ()+ Just (ExpValue _ _ (ValInteger l')) -> insertLabel l' formalN -- label goes here, if present+ _ -> return () let name i = varName cn ++ "[" ++ show i ++ "]"- let formal (ExpValue a s (ValVariable _)) i = ExpValue a s (ValVariable (name i))- formal e i = ExpValue a s (ValVariable (name i))- where a = getAnnotation e; s = getSpan e- forM_ (zip exps [1..]) $ \ (e, i) -> do- e' <- processFunctionCalls e- addToBBlock . analyseAllLhsVars1 $ BlStatement a s Nothing (StExpressionAssign a' s' (formal e' i) e')- (_, dummyCallN) <- closeBBlock+ let formal (ExpValue a'' s'' (ValVariable _)) i = genVar a''{ insLabel = Nothing } s'' (name i)+ formal e i = genVar a''{ insLabel = Nothing } s'' (name i)+ where a'' = getAnnotation e; s'' = getSpan e+ forM_ (zip exps [(1::Integer)..]) $ \ (e, i) -> do+ e' <- processFunctionCalls e -- may generate additional bblocks+ let b = BlStatement a{ insLabel = Nothing } s l (StExpressionAssign a' s' (formal e' i) e')+ addToBBlock $ analyseAllLhsVars1 b - -- create "dummy call" bblock with no parameters in the StCall AST-node.- addToBBlock . analyseAllLhsVars1 $ BlStatement a s Nothing (StCall a' s' cn Nothing)+ (formalN', dummyCallN) <- closeBBlock+ -- formalN' may differ from formalN when additional bblocks were+ -- generated by processFunctionCalls.++ let dummyArgs = map (Argument a0 s' Nothing) (zipWith formal exps [(1::Integer)..])++ -- create "dummy call" bblock with dummy parameters in the StCall AST-node.+ addToBBlock . analyseAllLhsVars1 $ BlStatement a s Nothing (StCall a' s' cn (Just $ fromList a0 dummyArgs)) (_, returnedN) <- closeBBlock -- re-assign the variables using the values of the formal parameters, if possible -- (because call-by-reference)- forM_ (zip exps [1..]) $ \ (e, i) ->+ forM_ (zip exps [(1::Integer)..]) $ \ (e, i) -> -- this is only possible for l-expressions- if isLExpr e then- addToBBlock . analyseAllLhsVars1 $ BlStatement a s Nothing (StExpressionAssign a' s' e (formal e i))- else return ()+ (when (isLExpr e) $+ addToBBlock . analyseAllLhsVars1 $+ BlStatement a{ insLabel = Nothing } s l (StExpressionAssign a' s' e (formal e i))) (_, nextN) <- closeBBlock -- connect the bblocks- createEdges [ (prevN, formalN, ()), (formalN, dummyCallN, ())+ createEdges [ (prevN, formalN, ()), (formalN', dummyCallN, ()) , (dummyCallN, returnedN, ()), (returnedN, nextN, ()) ] +perBlock b@(BlStatement _ _ _ (StRead _ _ cs _)) = do+ let (end, err) = getReadCtrlXfers $ aStrip cs++ processLabel b+ b' <- descendBiM processFunctionCalls b+ addToBBlock b'++ when (isJust end || isJust err) $ do+ (readN, nxtN) <- closeBBlock+ createEdges [(readN, nxtN, ())]+ perBlock b = do processLabel b b' <- descendBiM processFunctionCalls b@@ -414,9 +493,9 @@ case getLabel b of Just (ExpValue _ _ (ValInteger l)) -> insertLabel l doN _ -> return ()- case repeatExpr of Just e -> processFunctionCalls e >> return (); Nothing -> return ()+ case repeatExpr of Just e -> void (processFunctionCalls e); Nothing -> return () addToBBlock $ stripNestedBlocks b- closeBBlock+ _ <- closeBBlock -- process nested bblocks inside of do-statement (startN, endN) <- processBlocks bs n' <- genBBlock@@ -433,7 +512,8 @@ processLabel _ = return () -- Inserts into labelMap-insertLabel l n = modify $ \ st -> st { labelMap = M.insert l n (labelMap st) }+insertLabel :: MonadState (BBState a) m => String -> Node -> m ()+insertLabel l n = modify $ \ st -> st { labelMap = M.insert (dropLeadingZeroes l) n (labelMap st) } -- Puts an AST block into the current bblock. addToBBlock :: Block a -> BBlocker a ()@@ -443,10 +523,11 @@ closeBBlock :: BBlocker a (Node, Node) closeBBlock = do n <- gets curNode- modify $ \ st -> st { bbGraph = insNode (n, reverse (curBB st)) (bbGraph st), curBB = [] }+ modify $ \ st -> st { bbGraph = bbgrMap (insNode (n, reverse (curBB st))) (bbGraph st), curBB = [] } n' <- genBBlock return (n, n')-closeBBlock_ = closeBBlock >> return ()+closeBBlock_ :: StateT (BBState a) Identity ()+closeBBlock_ = void closeBBlock -- Starts up a new bblock. genBBlock :: BBlocker a Int@@ -456,23 +537,25 @@ return n' -- Adds labeled-edge mappings.+createEdges :: MonadState (BBState a) m => [LEdge ()] -> m () createEdges es = modify $ \ st -> st { newEdges = es ++ newEdges st } -- Generates a new node number. gen :: BBlocker a Int gen = do- n:ns <- gets nums+ ~(n:ns) <- gets nums modify $ \ s -> s { nums = ns } return n genTemp :: String -> BBlocker a String genTemp str = do- n:ns <- gets tempNums+ ~(n:ns) <- gets tempNums modify $ \ s -> s { tempNums = ns } return $ "_" ++ str ++ "_t#" ++ show n -- Strip nested code not necessary since it is duplicated in another -- basic block.+stripNestedBlocks :: Block a -> Block a stripNestedBlocks (BlDo a s l mn tl ds _ el) = BlDo a s l mn tl ds [] el stripNestedBlocks (BlDoWhile a s l tl n e _ el) = BlDoWhile a s l tl n e [] el stripNestedBlocks (BlIf a s l mn exps _ el) = BlIf a s l mn exps [] el@@ -498,17 +581,15 @@ -- create bblock that assigns formal parameters (fn[1], fn[2], ...) let name i = varName fn ++ "[" ++ show i ++ "]"- let setName n e = setAnnotation ((getAnnotation e) { uniqueName = Just n, sourceName = Just n }) e- let formal (ExpValue a s (ValVariable _)) i = setName n $ ExpValue a0 s (ValVariable n)- where n = name i- formal e i = setName n $ ExpValue a0 s (ValVariable n)- where a = getAnnotation e; s = getSpan e; n = name i- forM_ (zip exps [1..]) $ \ (e, i) -> do+ let formal (ExpValue _ s'' (ValVariable _)) i = genVar a0 s'' $ name i+ formal e i = genVar a0 (getSpan e) $ name i++ forM_ (zip exps [(1::Integer)..]) $ \ (e, i) -> addToBBlock . analyseAllLhsVars1 $ BlStatement a0 s Nothing (StExpressionAssign a' s' (formal e i) e) (_, dummyCallN) <- closeBBlock - let retV = setName (name 0) $ ExpValue a0 s (ValVariable (name 0))- let dummyArgs = map (Argument a0 s' Nothing) (retV:map (uncurry formal) (zip exps [1..]))+ let retV = genVar a0 s $ name (0::Integer)+ let dummyArgs = map (Argument a0 s' Nothing) (retV:zipWith formal exps [(1::Integer)..]) -- create "dummy call" bblock with dummy arguments in the StCall AST-node. addToBBlock . analyseAllLhsVars1 $ BlStatement a s Nothing (StCall a' s' fn (Just $ fromList a0 dummyArgs))@@ -516,13 +597,12 @@ -- re-assign the variables using the values of the formal parameters, if possible -- (because call-by-reference)- forM_ (zip exps [1..]) $ \ (e, i) ->+ forM_ (zip exps [(1::Integer)..]) $ \ (e, i) -> -- this is only possible for l-expressions- if isLExpr e then- addToBBlock . analyseAllLhsVars1 $ BlStatement a0 s Nothing (StExpressionAssign a' s' e (formal e i))- else return ()+ (when (isLExpr e) $+ addToBBlock . analyseAllLhsVars1 $ BlStatement a0 s Nothing (StExpressionAssign a' s' e (formal e i))) tempName <- genTemp (varName fn)- let temp = setName tempName $ ExpValue a0 s (ValVariable tempName)+ let temp = genVar a0 s tempName addToBBlock . analyseAllLhsVars1 $ BlStatement a0 s Nothing (StExpressionAssign a0 s' temp retV) (_, nextN) <- closeBBlock@@ -533,26 +613,15 @@ return temp processFunctionCall e = return e +extractExp :: Argument a -> Expression a extractExp (Argument _ _ _ exp) = exp -------------------------------------------------- -- Supergraph: all program units in one basic-block graph -data SuperBBGr a = SuperBBGr { graph :: BBGr a- , clusters :: IM.IntMap ProgramUnitName- , entries :: M.Map PUName SuperNode }---- | Extract graph from SuperBBGr-superBBGrGraph :: SuperBBGr a -> BBGr a-superBBGrGraph = graph---- | Extract entry map from SuperBBGr-superBBGrEntries :: SuperBBGr a -> M.Map ProgramUnitName SuperNode-superBBGrEntries = entries---- | Extract cluster map from SuperBBGr-superBBGrClusters :: SuperBBGr a -> IM.IntMap ProgramUnitName-superBBGrClusters = clusters+data SuperBBGr a = SuperBBGr { superBBGrGraph :: BBGr a+ , superBBGrClusters :: IM.IntMap ProgramUnitName+ , superBBGrEntries :: M.Map PUName SuperNode } type SuperNode = Node type SuperEdge = (SuperNode, SuperNode, ELabel)@@ -561,12 +630,14 @@ type ELabel = () genSuperBBGr :: forall a. Data a => BBlockMap (Analysis a) -> SuperBBGr (Analysis a)-genSuperBBGr bbm = SuperBBGr { graph = superGraph'', clusters = cmap, entries = entryMap }+genSuperBBGr bbm = SuperBBGr { superBBGrGraph = superGraph''+ , superBBGrClusters = cmap+ , superBBGrEntries = entryMap } where namedNodes :: [((PUName, Node), NLabel a)]- namedNodes = [ ((name, n), bs) | (name, gr) <- M.toList bbm, (n, bs) <- labNodes gr ]+ namedNodes = [ ((name, n), bs) | (name, gr) <- M.toList bbm, (n, bs) <- labNodes (bbgrGr gr) ] namedEdges :: [((PUName, Node), (PUName, Node), ELabel)]- namedEdges = [ ((name, n), (name, m), l) | (name, gr) <- M.toList bbm, (n, m, l) <- labEdges gr ]+ namedEdges = [ ((name, n), (name, m), l) | (name, gr) <- M.toList bbm, (n, m, l) <- labEdges (bbgrGr gr) ] superNodeMap :: M.Map (PUName, Node) SuperNode superNodeMap = M.fromList $ zip (map fst namedNodes) [1..] getSuperNode :: (PUName, Node) -> SuperNode@@ -585,7 +656,7 @@ -- Assumption: all StCalls appear by themselves in a bblock. stCalls :: [(SuperNode, String)] stCalls = [ (getSuperNode n, sub) | (n, [BlStatement _ _ _ (StCall _ _ e _)]) <- namedNodes- , v@(ExpValue _ _ _) <- [e]+ , v@ExpValue{} <- [e] , let sub = varName v , Named sub `M.member` entryMap && Named sub `M.member` exitMap ] stCallCtxts :: [([SuperEdge], SuperNode, String, [SuperEdge])]@@ -603,25 +674,28 @@ mainEntry :: SuperNode -- (possibly more than one, arbitrarily take first) mainEntry:_ = [ n | (n, _) <- labNodes superGraph', null (pre superGraph' n) ] -- Rename the main entry point to 0- superGraph'' :: Gr (NLabel a) ELabel- superGraph'' = delNode mainEntry .- insEdges [ (0, m, l) | (_, m, l) <- out superGraph' mainEntry ] .- insNode (0, []) $ superGraph'+ superGraph'' :: BBGr (Analysis a)+ superGraph'' = BBGr { bbgrGr = delNode mainEntry .+ insEdges [ (0, m, l) | (_, m, l) <- out superGraph' mainEntry ] .+ insNode (0, []) $ superGraph'+ , bbgrEntries = (0:) . filter (/=mainEntry) . map snd . M.toList $ entryMap+ , bbgrExits = (-1:) . map snd . M.toList $ exitMap } +fromJustMsg :: String -> Maybe a -> a fromJustMsg _ (Just x) = x fromJustMsg msg _ = error msg -------------------------------------------------- findLabeledBBlock :: String -> BBGr a -> Maybe Node-findLabeledBBlock lab gr =- listToMaybe [ n | (n, bs) <- labNodes gr, b <- bs- , ExpValue _ _ (ValInteger lab') <- maybeToList (getLabel b)- , lab == lab' ]+findLabeledBBlock llab gr =+ listToMaybe [ n | (n, bs) <- labNodes (bbgrGr gr), b <- bs+ , ExpValue _ _ (ValInteger llab') <- maybeToList (getLabel b)+ , llab == llab' ] -- | Show a basic block graph in a somewhat decent way. showBBGr :: (Out a, Show a) => BBGr a -> String-showBBGr gr = execWriter . forM (labNodes gr) $ \ (n, bs) -> do+showBBGr (BBGr gr _ _) = execWriter . forM (labNodes gr) $ \ (n, bs) -> do let b = "BBLOCK " ++ show n ++ " -> " ++ show (map (\ (_, m, _) -> m) $ out gr n) tell $ "\n\n" ++ b tell $ "\n" ++ replicate (length b) '-' ++ "\n"@@ -629,23 +703,27 @@ -- | Show a basic block graph without the clutter showAnalysedBBGr :: (Out a, Show a) => BBGr (Analysis a) -> String-showAnalysedBBGr = showBBGr . nmap strip+showAnalysedBBGr = showBBGr . bbgrMap (nmap strip) where strip = map (fmap insLabel) -- | Show a basic block supergraph showSuperBBGr :: (Out a, Show a) => SuperBBGr (Analysis a) -> String-showSuperBBGr = showAnalysedBBGr . graph+showSuperBBGr = showAnalysedBBGr . superBBGrGraph -- | Pick out and show the basic block graphs in the program file analysis. showBBlocks :: (Data a, Out a, Show a) => ProgramFile (Analysis a) -> String showBBlocks pf = perPU =<< getPUs pf where+ perPU PUComment{} = "" perPU pu | Analysis { bBlocks = Just gr } <- getAnnotation pu =- dashes ++ "\n" ++ p ++ "\n" ++ dashes ++ "\n" ++ showBBGr (nmap strip gr) ++ "\n\n"+ dashes ++ "\n" ++ p ++ "\n" ++ dashes ++ "\n" ++ showBBGr (bbgrMap (nmap strip) gr) ++ "\n\n" where p = "| Program Unit " ++ show (puName pu) ++ " |" dashes = replicate (length p) '-'- perPU _ = ""+ perPU pu =+ dashes ++ "\n" ++ p ++ "\n" ++ dashes ++ "\n" ++ unlines (map (pretty . fmap insLabel) (programUnitBody pu)) ++ "\n\n"+ where p = "| Program Unit " ++ show (puName pu) ++ " |"+ dashes = replicate (length p) '-' strip = map (fmap insLabel) getPUs :: Data a => ProgramFile (Analysis a) -> [ProgramUnit (Analysis a)] getPUs = universeBi@@ -656,35 +734,38 @@ -- | Output a supergraph in the GraphViz DOT format superBBGrToDOT :: SuperBBGr a -> String-superBBGrToDOT sgr = bbgrToDOT' (clusters sgr) (graph sgr)+superBBGrToDOT sgr = bbgrToDOT' (superBBGrClusters sgr) (superBBGrGraph sgr) -- shared code for DOT output bbgrToDOT' :: IM.IntMap ProgramUnitName -> BBGr a -> String-bbgrToDOT' clusters gr = execWriter $ do+bbgrToDOT' clusters' (BBGr{ bbgrGr = gr }) = execWriter $ do tell "strict digraph {\n" tell "node [shape=box,fontname=\"Courier New\"]\n"- let entryNodes = filter (\ n -> null (pre gr n)) (nodes gr)- let nodes = bfsn entryNodes gr- forM nodes $ \ n -> do+ let entryNodes = filter (null . pre gr) (nodes gr)+ let nodes' = bfsn entryNodes gr+ _ <- forM nodes' $ \ n -> do let Just bs = lab gr n- let mname = IM.lookup n clusters+ let mname = IM.lookup n clusters' case mname of Just name -> do tell $ "subgraph \"cluster " ++ showPUName name ++ "\" {\n" tell $ "label=\"" ++ showPUName name ++ "\"\n"- tell $ "fontname=\"Courier New\"\nfontsize=24\n"+ tell "fontname=\"Courier New\"\nfontsize=24\n" _ -> return ()- tell $ "bb" ++ show n ++ "[label=\"" ++ show n ++ "\\l" ++ (concatMap showBlock bs) ++ "\"]\n"+ tell $ "bb" ++ show n ++ "[label=\"" ++ show n ++ "\\l" ++ concatMap showBlock bs ++ "\"]\n" when (null bs) . tell $ "bb" ++ show n ++ "[shape=circle]\n" tell $ "bb" ++ show n ++ " -> {"- forM (suc gr n) $ \ m -> tell (" bb" ++ show m)+ _ <- forM (suc gr n) $ \ m -> tell (" bb" ++ show m) tell "}\n" when (isJust mname) $ tell "}\n" tell "}\n" +showPUName :: ProgramUnitName -> String showPUName (Named n) = n-showPUName (NamelessBlockData) = ".blockdata."-showPUName (NamelessMain) = ".main."+showPUName NamelessBlockData = ".blockdata."+showPUName NamelessMain = ".main."+showPUName NamelessComment = ".comment." --- Some helper functions to output some pseudo-code for readability+-- | Some helper functions to output some pseudo-code for readability.+showBlock :: Block a -> String showBlock (BlStatement _ _ mlab st) | null (str :: String) = "" | otherwise = showLab mlab ++ str ++ "\\l"@@ -703,7 +784,8 @@ aIntercalate ", " showAttr aattrs ++ aIntercalate ", " showDecl adecls StDimension _ _ adecls -> "dimension " ++ aIntercalate ", " showDecl adecls- _ -> ""+ StExit{} -> "exit"+ _ -> "<unhandled statement: " ++ show (toConstr (fmap (const ()) st)) ++ ">" showBlock (BlIf _ _ mlab _ (Just e1:_) _ _) = showLab mlab ++ "if " ++ showExpr e1 ++ "\\l" showBlock (BlDo _ _ mlab _ _ (Just spec) _ _) = showLab mlab ++ "do " ++ showExpr e1 ++ " <- " ++@@ -712,12 +794,16 @@ maybe "1" showExpr me4 ++ "\\l" where DoSpecification _ _ (StExpressionAssign _ _ e1 e2) e3 me4 = spec showBlock (BlDo _ _ _ _ _ Nothing _ _) = "do"-showBlock _ = ""+showBlock (BlComment{}) = ""+showBlock b = "<unhandled block: " ++ show (toConstr (fmap (const ()) b)) ++ ">" +showAttr :: Attribute a -> String showAttr (AttrParameter _ _) = "parameter" showAttr (AttrPublic _ _) = "public" showAttr (AttrPrivate _ _) = "private"+showAttr (AttrProtected _ _) = "protected" showAttr (AttrAllocatable _ _) = "allocatable"+showAttr (AttrAsynchronous _ _) = "asynchronous" showAttr (AttrDimension _ _ aDimDecs) = "dimension ( " ++ aIntercalate ", " showDim aDimDecs ++ " )" showAttr (AttrExternal _ _) = "external"@@ -729,66 +815,110 @@ showAttr (AttrPointer _ _) = "pointer" showAttr (AttrSave _ _) = "save" showAttr (AttrTarget _ _) = "target"+showAttr (AttrValue _ _) = "value"+showAttr (AttrVolatile _ _) = "volatile"+showAttr (AttrSuffix _ _ (SfxBind _ _ Nothing)) = "bind(c)"+showAttr (AttrSuffix _ _ (SfxBind _ _ (Just e))) = "bind(c,name=" ++ showExpr e ++ ")" -showLab Nothing = replicate 6 ' '-showLab (Just (ExpValue _ _ (ValInteger l))) = ' ':l ++ replicate (5 - length l) ' '+showLab :: Maybe (Expression a) -> String+showLab a =+ case a of+ Nothing -> replicate 6 ' '+ Just (ExpValue _ _ (ValInteger l)) -> ' ':l ++ replicate (5 - length l) ' '+ _ -> error "unhandled showLab" +showValue :: Value a -> Name showValue (ValVariable v) = v showValue (ValIntrinsic v) = v showValue (ValInteger v) = v showValue (ValReal v) = v showValue (ValComplex e1 e2) = "( " ++ showExpr e1 ++ " , " ++ showExpr e2 ++ " )"-showValue _ = ""+showValue (ValString s) = "\\\"" ++ escapeStr s ++ "\\\""+showValue v = "<unhandled value: " ++ show (toConstr (fmap (const ()) v)) ++ ">" +escapeStr :: String -> String+escapeStr = map fst . unfoldr f . map (,False)+ where+ f [] = Nothing+ f ((c,False):cs)+ | c `elem` "\"\\" = Just (('\\', False), (c, True):cs)+ f ((c,_):cs) = Just ((c, False), cs)++showExpr :: Expression a -> String showExpr (ExpValue _ _ v) = showValue v showExpr (ExpBinary _ _ op e1 e2) = "(" ++ showExpr e1 ++ showOp op ++ showExpr e2 ++ ")" showExpr (ExpUnary _ _ op e) = "(" ++ showUOp op ++ showExpr e ++ ")" showExpr (ExpSubscript _ _ e1 aexps) = showExpr e1 ++ "[" ++ aIntercalate ", " showIndex aexps ++ "]"-showExpr _ = ""+showExpr e = "<unhandled expr: " ++ show (toConstr (fmap (const ()) e)) ++ ">" +showIndex :: Index a -> String showIndex (IxSingle _ _ _ i) = showExpr i showIndex (IxRange _ _ l u s) = maybe "" showExpr l ++ -- Lower ':' : maybe "" showExpr u ++ -- Upper- maybe "" (\u -> ':' : showExpr u) s -- Stride+ maybe "" (\u' -> ':' : showExpr u') s -- Stride +showUOp :: UnaryOp -> String showUOp Plus = "+" showUOp Minus = "-" showUOp Not = "!"+-- needs a custom instance+showUOp (UnCustom x) = show x +showOp :: BinaryOp -> String showOp Addition = " + " showOp Multiplication = " * " showOp Subtraction = " - " showOp Division = " / "+showOp Concatenation = " // " showOp op = " ." ++ show op ++ ". " -showType (TypeSpec _ _ t (Just s)) = showBaseType t ++ "(selector)" -- ++ show s+showType :: TypeSpec a -> String+showType (TypeSpec _ _ t (Just _)) = showBaseType t ++ "(selector)" -- ++ show s showType (TypeSpec _ _ t Nothing) = showBaseType t +showBaseType :: BaseType -> String showBaseType TypeInteger = "integer" showBaseType TypeReal = "real" showBaseType TypeDoublePrecision = "double" showBaseType TypeComplex = "complex" showBaseType TypeDoubleComplex = "doublecomplex" showBaseType TypeLogical = "logical"-showBaseType TypeCharacter = "character"-showBaseType (TypeCustom s) = s+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 (TypeCustom s) = "type(" ++ s ++ ")"+showBaseType TypeByte = "byte"+showBaseType ClassStar = "class(*)"+showBaseType (ClassCustom s) = "class(" ++ s ++ ")" -showDecl (DeclArray _ _ e adims length initial) =+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) = showExpr e ++ "(" ++ aIntercalate "," showDim adims ++ ")" ++- maybe "" (\e -> "*" ++ showExpr e) length ++- maybe "" (\e -> " = " ++ showExpr e) initial-showDecl (DeclVariable _ _ e length initial) =+ maybe "" (\e' -> "*" ++ showExpr e') length' +++ maybe "" (\e' -> " = " ++ showExpr e') initial+showDecl (DeclVariable _ _ e length' initial) = showExpr e ++- maybe "" (\e -> "*" ++ showExpr e) length ++- maybe "" (\e -> " = " ++ showExpr e) initial+ maybe "" (\e' -> "*" ++ showExpr e') length' +++ maybe "" (\e' -> " = " ++ showExpr e') initial +showDim :: DimensionDeclarator a -> String showDim (DimensionDeclarator _ _ me1 me2) = maybe "" ((++":") . showExpr) me1 ++ maybe "" showExpr me2 +aIntercalate :: [a1] -> (t a2 -> [a1]) -> AList t a2 -> [a1] aIntercalate sep f = intercalate sep . map f . aStrip +noSrcSpan :: SrcSpan noSrcSpan = SrcSpan initPosition initPosition --------------------------------------------------@@ -798,7 +928,7 @@ ufoldM' :: (Graph gr, Monad m) => (Context a b -> c -> m c) -> c -> gr a b -> m c ufoldM' f u g | isEmpty g = return u- | otherwise = f c =<< (ufoldM' f u g')+ | otherwise = f c =<< ufoldM' f u g' where (c,g') = matchAny g
src/Language/Fortran/Analysis/DataFlow.hs view
@@ -4,52 +4,66 @@ module Language.Fortran.Analysis.DataFlow ( dominators, iDominators, DomMap, IDomMap , postOrder, revPostOrder, preOrder, revPreOrder, OrderF- , dataFlowSolver, showDataFlow, InOut, InOutMap, InF, OutF+ , dataFlowSolver, InOut, InOutMap, InF, OutF , liveVariableAnalysis, reachingDefinitions , genUDMap, genDUMap, duMapToUdMap, UDMap, DUMap , genFlowsToGraph, FlowsGraph , genVarFlowsToMap, VarFlowsMap+ , Constant(..), ParameterVarMap, ConstExpMap, genConstExpMap, analyseConstExps, analyseParameterVars , genBlockMap, genDefMap, BlockMap, DefMap , genCallMap, CallMap , loopNodes, genBackEdgeMap, sccWith, BackEdgeMap , genLoopNodeMap, LoopNodeMap , genInductionVarMap, InductionVarMap , genInductionVarMapByASTBlock, InductionVarMapByASTBlock- , noPredNodes, genDerivedInductionMap, DerivedInductionMap, InductionExpr(..)+ , genDerivedInductionMap, DerivedInductionMap, InductionExpr(..)+ , showDataFlow, showFlowsDOT+ , BBNodeMap, BBNodeSet, ASTBlockNodeMap, ASTBlockNodeSet, ASTExprNodeMap, ASTExprNodeSet ) where +import Prelude hiding (init) import Data.Generics.Uniplate.Data import GHC.Generics import Data.Data import Control.Monad.State.Lazy+import Control.Arrow ((&&&)) import Text.PrettyPrint.GenericPretty (Out) import Language.Fortran.Parser.Utils import Language.Fortran.Analysis+import Language.Fortran.Analysis.BBlocks (showBlock, ASTBlockNode, ASTExprNode) import Language.Fortran.AST import qualified Data.Map as M import qualified Data.IntMap.Lazy as IM import qualified Data.Set as S import qualified Data.IntSet as IS-import Data.Graph.Inductive hiding (trc, dom)+import Data.Graph.Inductive hiding (trc, dom, order, inn, out, rc) import Data.Graph.Inductive.PatriciaTree (Gr)-import Data.Graph.Inductive.Query.BFS (bfen) import Data.Maybe import Data.List (foldl', foldl1', (\\), union, intersect)+import Control.Monad.Writer hiding (fix) --------------------------------------------------+-- Better names for commonly used types+type BBNodeMap = IM.IntMap+type BBNodeSet = IS.IntSet+type ASTBlockNodeMap = IM.IntMap+type ASTBlockNodeSet = IS.IntSet+type ASTExprNodeMap = IM.IntMap+type ASTExprNodeSet = IS.IntSet -- | DomMap : node -> dominators of node-type DomMap = IM.IntMap IS.IntSet+type DomMap = BBNodeMap BBNodeSet -- | Compute dominators of each bblock in the graph. Node A dominates -- node B when all paths from the start node of that program unit must -- pass through node A in order to reach node B. That will be -- represented as the relation (B, [A, ...]) in the DomMap. dominators :: BBGr a -> DomMap-dominators gr = IM.map snd $ dataFlowSolver gr init revPostOrder inn out+dominators bbgr = IM.map snd $ dataFlowSolver bbgr init revPostOrder inn out where+ gr = bbgrGr bbgr nodeSet = IS.fromList $ nodes gr- init n = (nodeSet, nodeSet)+ init _ = (nodeSet, nodeSet) inn outF n | preNodes@(_:_) <- pre gr n = foldl1' IS.intersection . map outF $ preNodes@@ -58,7 +72,7 @@ out inF n = IS.insert n $ inF n -- | IDomMap : node -> immediate dominator of node-type IDomMap = IM.IntMap Int+type IDomMap = BBNodeMap BBNode -- | Compute the immediate dominator of each bblock in the graph. The -- immediate dominator is, in a sense, the 'closest' dominator of a@@ -66,14 +80,14 @@ -- dominated by node B if there does not exist any node C such that: -- node A dominates node C and node C dominates node B. iDominators :: BBGr a -> IDomMap-iDominators gr = IM.unions [ IM.fromList . flip iDom n $ gr | n <- noPredNodes gr ]+iDominators gr = IM.unions [ IM.fromList . flip iDom n $ bbgrGr gr | n <- bbgrEntries gr ] -- | An OrderF is a function from graph to a specific ordering of nodes. type OrderF a = BBGr a -> [Node] -- | The postordering of a graph outputs the label after traversal of children. postOrder :: OrderF a-postOrder gr = concatMap postorder . dff (noPredNodes gr) $ gr+postOrder gr = concatMap postorder . dff (bbgrEntries gr) $ bbgrGr gr -- | Reversed postordering. revPostOrder :: OrderF a@@ -81,24 +95,19 @@ -- | The preordering of a graph outputs the label before traversal of children. preOrder :: OrderF a-preOrder gr = concatMap preorder . dff (noPredNodes gr) $ gr+preOrder gr = concatMap preorder . dff (bbgrEntries gr) $ bbgrGr gr -- | Reversed preordering. revPreOrder :: OrderF a revPreOrder = reverse . preOrder --- | Compute the set of nodes with no predecessors.-noPredNodes :: Graph g => g a b -> [Node]--- noPredNodes = flip ufold [] $ \ ctx ns -> if null (pre' ctx) then node' ctx : ns else ns -- doesn't work, though it should-noPredNodes gr = filter (null . pre gr) (nodes gr)- -------------------------------------------------- -- | InOut : (dataflow into the bblock, dataflow out of the bblock) type InOut t = (t, t) -- | InOutMap : node -> (dataflow into node, dataflow out of node)-type InOutMap t = IM.IntMap (InOut t)+type InOutMap t = BBNodeMap (InOut t) -- | InF, a function that returns the in-dataflow for a given node type InF t = Node -> t@@ -117,22 +126,22 @@ where ordNodes = order gr initM = IM.fromList [ (n, initF n) | n <- ordNodes ]- step m = IM.fromList [ (n, (inF (snd . get m) n, outF (fst . get m) n)) | n <- ordNodes ]- get m n = fromJustMsg ("dataFlowSolver: get " ++ show (n)) $ IM.lookup n m+ step m = IM.fromList [ (n, (inF (snd . get' m) n, outF (fst . get' m) n)) | n <- ordNodes ]+ get' m n = fromJustMsg ("dataFlowSolver: get " ++ show n) $ IM.lookup n m --- | Apply the iterative dataflow analysis method.-dataFlowSolver' :: Ord t => BBGr a -- ^ basic block graph- -> (Node -> InOut t) -- ^ initialisation for in and out dataflows- -> OrderF a -- ^ ordering function- -> (OutF t -> InF t) -- ^ compute the in-flow given an out-flow function- -> (InF t -> OutF t) -- ^ compute the out-flow given an in-flow function- -> [InOutMap t] -- ^ dataflow steps-dataFlowSolver' gr initF order inF outF = iterate step initM- where- ordNodes = order gr- initM = IM.fromList [ (n, initF n) | n <- ordNodes ]- step m = IM.fromList [ (n, (inF (snd . get m) n, outF (fst . get m) n)) | n <- ordNodes ]- get m n = fromJustMsg ("dataFlowSolver': get " ++ show (n)) $ IM.lookup n m+-- Similar to above but return a list of states instead of just the final one.+--dataFlowSolver' :: Ord t => BBGr a -- ^ basic block graph+-- -> (Node -> InOut t) -- ^ initialisation for in and out dataflows+-- -> OrderF a -- ^ ordering function+-- -> (OutF t -> InF t) -- ^ compute the in-flow given an out-flow function+-- -> (InF t -> OutF t) -- ^ compute the out-flow given an in-flow function+-- -> [InOutMap t] -- ^ dataflow steps+--dataFlowSolver' gr initF order inF outF = iterate step initM+-- where+-- ordNodes = order gr+-- initM = IM.fromList [ (n, initF n) | n <- ordNodes ]+-- step m = IM.fromList [ (n, (inF (snd . get m) n, outF (fst . get m) n)) | n <- ordNodes ]+-- get m n = fromJustMsg ("dataFlowSolver': get " ++ show (n)) $ IM.lookup n m -------------------------------------------------- @@ -140,14 +149,14 @@ -- Each AST-block has been given a unique number label during analysis -- of basic blocks. The purpose of this map is to provide the ability -- to lookup AST-blocks by label.-type BlockMap a = IM.IntMap (Block (Analysis a))+type BlockMap a = ASTBlockNodeMap (Block (Analysis a)) -- | Build a BlockMap from the AST. This can only be performed after -- analyseBasicBlocks has operated, created basic blocks, and labeled -- all of the AST-blocks with unique numbers. genBlockMap :: Data a => ProgramFile (Analysis a) -> BlockMap a genBlockMap pf = IM.fromList [ (i, b) | gr <- uni pf- , (_, bs) <- labNodes gr+ , (_, bs) <- labNodes $ bbgrGr gr , b <- bs , let Just i = insLabel (getAnnotation b) ] where@@ -155,7 +164,7 @@ uni = universeBi -- | DefMap : variable name -> { AST-block label }-type DefMap = M.Map Name IS.IntSet+type DefMap = M.Map Name ASTBlockNodeSet -- | Build a DefMap from the BlockMap. This allows us to quickly look -- up the AST-block labels that wrote into the given variable.@@ -174,9 +183,9 @@ liveVariableAnalysis gr = dataFlowSolver gr (const (S.empty, S.empty)) revPreOrder inn out where inn outF b = (outF b S.\\ kill b) `S.union` gen b- out innF b = S.unions [ innF s | s <- suc gr b ]- kill b = bblockKill (fromJustMsg "liveVariableAnalysis kill" $ lab gr b)- gen b = bblockGen (fromJustMsg "liveVariableAnalysis gen" $ lab gr b)+ out innF b = S.unions [ innF s | s <- suc (bbgrGr gr) b ]+ kill b = bblockKill (fromJustMsg "liveVariableAnalysis kill" $ lab (bbgrGr gr) b)+ gen b = bblockGen (fromJustMsg "liveVariableAnalysis gen" $ lab (bbgrGr gr) b) -- | Iterate "KILL" set through a single basic block. bblockKill :: Data a => [Block (Analysis a)] -> S.Set Name@@ -184,17 +193,10 @@ -- | Iterate "GEN" set through a single basic block. bblockGen :: Data a => [Block (Analysis a)] -> S.Set Name-bblockGen bs = S.fromList . fst . foldl' f ([], []) $ zip (map blockGen bs) (map blockKill bs)+bblockGen bs = S.fromList . fst . foldl' f ([], []) $ map (blockGen &&& blockKill) bs where f (bbgen, bbkill) (gen, kill) = ((gen \\ bbkill) `union` bbgen, kill `union` bbkill) --- | Iterate "GEN" set through a single basic block.--- attempt to make this faster using sets internally (no obvious speedup though)-bblockGenFast :: Data a => [Block (Analysis a)] -> S.Set Name-bblockGenFast bs = fst . foldl' f (S.empty, S.empty) $ zip (map (S.fromList . blockGen) bs) (map (S.fromList . blockKill) bs)- where- f (bbgen, bbkill) (gen, kill) = ((gen S.\\ bbkill) `S.union` bbgen, kill `S.union` bbkill)- -- | "KILL" set for a single AST-block. blockKill :: Data a => Block (Analysis a) -> [Name] blockKill = blockVarDefs@@ -227,41 +229,41 @@ -- named v. Label A may reach another program point labeled P if there -- is at least one program path from label A to label P that does not -- redefine variable v.-reachingDefinitions :: Data a => DefMap -> BBGr (Analysis a) -> InOutMap IS.IntSet+reachingDefinitions :: Data a => DefMap -> BBGr (Analysis a) -> InOutMap ASTBlockNodeSet reachingDefinitions dm gr = dataFlowSolver gr (const (IS.empty, IS.empty)) revPostOrder inn out where- inn outF b = IS.unions [ outF s | s <- pre gr b ]+ inn outF b = IS.unions [ outF s | s <- pre (bbgrGr gr) b ] out innF b = gen `IS.union` (innF b IS.\\ kill)- where (gen, kill) = rdBblockGenKill dm (fromJustMsg "reachingDefinitions" $ lab gr b)+ where (gen, kill) = rdBblockGenKill dm (fromJustMsg "reachingDefinitions" $ lab (bbgrGr gr) b) -- Compute the "GEN" and "KILL" sets for a given basic block.-rdBblockGenKill :: Data a => DefMap -> [Block (Analysis a)] -> (IS.IntSet, IS.IntSet)-rdBblockGenKill dm bs = foldl' f (IS.empty, IS.empty) $ zip (map gen bs) (map kill bs)+rdBblockGenKill :: Data a => DefMap -> [Block (Analysis a)] -> (ASTBlockNodeSet, ASTBlockNodeSet)+rdBblockGenKill dm bs = foldl' f (IS.empty, IS.empty) $ map (gen &&& kill) bs where gen b | null (allLhsVars b) = IS.empty | otherwise = IS.singleton . fromJustMsg "rdBblockGenKill" . insLabel . getAnnotation $ b kill = rdDefs dm- f (bbgen, bbkill) (gen, kill) =- ((bbgen IS.\\ kill) `IS.union` gen, (bbkill IS.\\ gen) `IS.union` kill)+ f (bbgen, bbkill) (gen', kill') =+ ((bbgen IS.\\ kill') `IS.union` gen', (bbkill IS.\\ gen') `IS.union` kill') -- Set of all AST-block labels that also define variables defined by AST-block b-rdDefs :: Data a => DefMap -> Block (Analysis a) -> IS.IntSet+rdDefs :: Data a => DefMap -> Block (Analysis a) -> ASTBlockNodeSet rdDefs dm b = IS.unions [ IS.empty `fromMaybe` M.lookup y dm | y <- allLhsVars b ] -------------------------------------------------- -- | DUMap : definition -> { use }-type DUMap = IM.IntMap IS.IntSet+type DUMap = ASTBlockNodeMap ASTBlockNodeSet -- | def-use map: map AST-block labels of defining AST-blocks to the -- AST-blocks that may use the definition.-genDUMap :: Data a => BlockMap a -> DefMap -> BBGr (Analysis a) -> InOutMap IS.IntSet -> DUMap+genDUMap :: Data a => BlockMap a -> DefMap -> BBGr (Analysis a) -> InOutMap ASTBlockNodeSet -> DUMap genDUMap bm dm gr rdefs = IM.unionsWith IS.union duMaps where -- duMaps for each bblock duMaps = [ fst (foldl' inBBlock (IM.empty, is) bs) | (n, (is, _)) <- IM.toList rdefs,- let Just bs = lab gr n ]+ let Just bs = lab (bbgrGr gr) n ] -- internal analysis within bblock; fold over list of AST-blocks inBBlock (duMap, inSet) b = (duMap', inSet') where@@ -272,13 +274,13 @@ where Just b' = IM.lookup i' bm uses = blockVarUses b duMap' = IM.unionWith IS.union duMap bduMap- gen b | null (allLhsVars b) = IS.empty- | otherwise = IS.singleton . fromJustMsg "genDUMap" . insLabel . getAnnotation $ b+ gen b' | null (allLhsVars b') = IS.empty+ | otherwise = IS.singleton . fromJustMsg "genDUMap" . insLabel . getAnnotation $ b' kill = rdDefs dm- inSet' = (inSet IS.\\ (kill b)) `IS.union` (gen b)+ inSet' = (inSet IS.\\ kill b) `IS.union` gen b -- | UDMap : use -> { definition }-type UDMap = IM.IntMap IS.IntSet+type UDMap = ASTBlockNodeMap ASTBlockNodeSet -- | Invert the DUMap into a UDMap duMapToUdMap :: DUMap -> UDMap@@ -288,18 +290,18 @@ -- | use-def map: map AST-block labels of variable-using AST-blocks to -- the AST-blocks that define those variables.-genUDMap :: Data a => BlockMap a -> DefMap -> BBGr (Analysis a) -> InOutMap IS.IntSet -> UDMap+genUDMap :: Data a => BlockMap a -> DefMap -> BBGr (Analysis a) -> InOutMap ASTBlockNodeSet -> UDMap genUDMap bm dm gr = duMapToUdMap . genDUMap bm dm gr -------------------------------------------------- -- | Convert a UD or DU Map into a graph.-mapToGraph :: DynGraph gr => BlockMap a -> IM.IntMap IS.IntSet -> gr (Block (Analysis a)) ()-mapToGraph bm m = mkGraph nodes edges+mapToGraph :: DynGraph gr => BlockMap a -> ASTBlockNodeMap ASTBlockNodeSet -> gr (Block (Analysis a)) ()+mapToGraph bm m = mkGraph nodes' edges' where- nodes = [ (i, iLabel) | i <- IM.keys m ++ concatMap IS.toList (IM.elems m)+ nodes' = [ (i, iLabel) | i <- IM.keys m ++ concatMap IS.toList (IM.elems m) , let iLabel = fromJustMsg "mapToGraph" (IM.lookup i bm) ]- edges = [ (i, j, ()) | (i, js) <- IM.toList m+ edges' = [ (i, j, ()) | (i, js) <- IM.toList m , j <- IS.toList js ] -- | FlowsGraph : nodes as AST-block (numbered by label), edges@@ -310,7 +312,7 @@ genFlowsToGraph :: Data a => BlockMap a -> DefMap -> BBGr (Analysis a)- -> InOutMap IS.IntSet -- ^ result of reaching definitions+ -> InOutMap ASTBlockNodeSet -- ^ result of reaching definitions -> FlowsGraph a genFlowsToGraph bm dm gr = mapToGraph bm . genDUMap bm dm gr @@ -328,22 +330,115 @@ -- planning to make revDM a surjection, after I flatten-out Fortran functions revDM = IM.fromListWith (curry fst) [ (i, v) | (v, is) <- M.toList dm, i <- IS.toList is ] -{-|-Finds the transitive closure of a directed graph.-Given a graph G=(V,E), its transitive closure is the graph:-G* = (V,E*) where E*={(i,j): i,j in V and there is a path from i to j in G}--}-tc :: (DynGraph gr) => gr a b -> gr a ()-tc g = newEdges `insEdges` insNodes ln empty+--------------------------------------------------++-- Integer arithmetic can be compile-time evaluated if we guard+-- against overflow, divide-by-zero. We must interpret the various+-- lexical forms of integers.+--+-- Floating point arithmetic requires knowing the target machine and+-- being very careful with all the possible effects of IEEE FP. Will+-- leave it alone for now.++-- conservative assumption: stay within bounds of signed 32-bit integer+minConst :: Integer+minConst = (-2::Integer) ^ (31::Integer)++maxConst :: Integer+maxConst = (2::Integer) ^ (31::Integer) - (1::Integer)++inBounds :: Integer -> Bool+inBounds x = minConst <= x && x <= maxConst++-- | Evaluate possible constant expressions within tree.+constantFolding :: Constant -> Constant+constantFolding c = case c of+ ConstBinary binOp a b | ConstInt x <- constantFolding a+ , ConstInt y <- constantFolding b -> case binOp of+ Addition | inBounds (x + y) -> ConstInt (x + y)+ Subtraction | inBounds (x - y) -> ConstInt (x - y)+ Multiplication | inBounds (x * y) -> ConstInt (x * y)+ Division | y /= 0 -> ConstInt (x `div` y)+ _ -> ConstBinary binOp (ConstInt x) (ConstInt y)+ ConstUnary Minus a | ConstInt x <- constantFolding a -> ConstInt (-x)+ ConstUnary Plus a -> constantFolding a+ _ -> c++-- | The map of all parameter variables and their corresponding values+type ParameterVarMap = M.Map Name Constant+-- | The map of all expressions and whether they are undecided (not+-- present in map), a constant value (Just Constant), or probably not+-- constant (Nothing).+type ConstExpMap = ASTExprNodeMap (Maybe Constant)++-- | Generate a constant-expression map with information about the+-- expressions (identified by insLabel numbering) in the ProgramFile+-- pf (must have analysis initiated & basic blocks generated) .+genConstExpMap :: forall a. Data a => ProgramFile (Analysis a) -> ConstExpMap+genConstExpMap pf = ceMap where- ln = labNodes g- newEdges = [ toLEdge (u, v) () | (u, _) <- ln, (_, v) <- bfen (outU g u) g ]- outU gr = map toEdge . out gr+ -- Generate map of 'parameter' variables, obtaining their value from ceMap below, lazily.+ pvMap = M.fromList $+ [ (varName v, getE e)+ | st@(StDeclaration _ _ (TypeSpec _ _ _ _) _ _) <- universeBi pf :: [Statement (Analysis a)]+ , AttrParameter _ _ <- universeBi st :: [Attribute (Analysis a)]+ , (DeclVariable _ _ v _ (Just e)) <- universeBi st ] +++ [ (varName v, getE e)+ | st@StParameter{} <- universeBi pf :: [Statement (Analysis a)]+ , (DeclVariable _ _ v _ (Just e)) <- universeBi st ]+ getV :: Expression (Analysis a) -> Maybe Constant+ getV e = constExp (getAnnotation e) `mplus` (join . flip M.lookup pvMap . varName $ e) + -- Generate map of information about 'constant expressions'.+ ceMap = IM.fromList [ (label, doExpr e) | e <- universeBi pf, Just label <- [labelOf e] ]+ getE :: Expression (Analysis a) -> Maybe Constant+ getE = join . (flip IM.lookup ceMap <=< labelOf)+ labelOf = insLabel . getAnnotation+ doExpr :: Expression (Analysis a) -> Maybe Constant+ doExpr e = case e of+ ExpValue _ _ (ValInteger str)+ | Just i <- readInteger str -> Just . ConstInt $ fromIntegral i+ ExpValue _ _ (ValInteger str) -> Just $ ConstUninterpInt str+ ExpValue _ _ (ValReal str) -> Just $ ConstUninterpReal str+ ExpValue _ _ (ValVariable _) -> getV e+ -- Recursively seek information about sub-expressions, relying on laziness.+ ExpBinary _ _ binOp e1 e2 -> constantFolding <$> liftM2 (ConstBinary binOp) (getE e1) (getE e2)+ ExpUnary _ _ unOp e' -> constantFolding <$> ConstUnary unOp <$> getE e'+ _ -> Nothing++-- | Get constant-expression information and put it into the AST+-- analysis annotation. Must occur after analyseBBlocks.+analyseConstExps :: forall a. Data a => ProgramFile (Analysis a) -> ProgramFile (Analysis a)+analyseConstExps pf = pf'+ where+ ceMap = genConstExpMap pf+ -- transform both the AST and the basic block graph+ pf' = transformBB (bbgrMap (nmap (transformExpr insertConstExp))) $ transformBi insertConstExp pf+ -- insert info about constExp into Expression annotation+ insertConstExp :: Expression (Analysis a) -> Expression (Analysis a)+ insertConstExp e = flip modifyAnnotation e $ \ a ->+ a { constExp = constExp a `mplus` join (flip IM.lookup ceMap =<< insLabel (getAnnotation e)) }+ -- utility functions for transforming expressions tucked away inside of the basic block graph+ transformBB :: (BBGr (Analysis a) -> BBGr (Analysis a)) -> ProgramFile (Analysis a) -> ProgramFile (Analysis a)+ transformBB = transformBi+ transformExpr :: (Expression (Analysis a) -> Expression (Analysis a)) ->+ [Block (Analysis a)] -> [Block (Analysis a)]+ transformExpr = transformBi++-- | Annotate AST with constant-expression information based on given+-- ParameterVarMap.+analyseParameterVars :: forall a. Data a => ParameterVarMap -> ProgramFile (Analysis a) -> ProgramFile (Analysis a)+analyseParameterVars pvm = transformBi expr+ where+ expr :: Expression (Analysis a) -> Expression (Analysis a)+ expr e@(ExpValue _ _ ValVariable{})+ | Just con <- M.lookup (varName e) pvm = flip modifyAnnotation e $ \ a -> a { constExp = Just con }+ expr e = e+ -------------------------------------------------- --- | BackEdgeMap : node -> node-type BackEdgeMap = IM.IntMap Node+-- | BackEdgeMap : bblock node -> bblock node+type BackEdgeMap = BBNodeMap BBNode -- | Find the edges that 'loop back' in the graph; ones where the -- target node dominates the source node. If the backedges are viewed@@ -351,7 +446,7 @@ genBackEdgeMap :: Graph gr => DomMap -> gr a b -> BackEdgeMap genBackEdgeMap domMap = IM.fromList . filter isBackEdge . edges where- isBackEdge (s, t) = t `IS.member` (fromJustMsg "genBackEdgeMap" $ s `IM.lookup` domMap)+ isBackEdge (s, t) = t `IS.member` fromJustMsg "genBackEdgeMap" (s `IM.lookup` domMap) -- | For each loop in the program, find out which bblock nodes are -- part of the loop by looking through the backedges (m, n) where n is@@ -360,13 +455,13 @@ -- of interest. Intersect this with the strongly-connected component -- containing m, in case of 'improper' graphs with weird control -- transfers.-loopNodes :: Graph gr => BackEdgeMap -> gr a b -> [IS.IntSet]+loopNodes :: Graph gr => BackEdgeMap -> gr a b -> [BBNodeSet] loopNodes bedges gr = [ IS.fromList (n:intersect (sccWith n gr) (rdfs [m] (delNode n gr))) | (m, n) <- IM.toList bedges ] --- | LoopNodeMap : node -> { node }-type LoopNodeMap = IM.IntMap IS.IntSet+-- | LoopNodeMap : bblock node -> { bblock node }+type LoopNodeMap = BBNodeMap BBNodeSet -- | Similar to loopNodes except it creates a map from loop-header to -- the set of loop nodes, for each loop-header.@@ -382,7 +477,7 @@ c:_ -> c -- | Map of loop header nodes to the induction variables within that loop.-type InductionVarMap = IM.IntMap (S.Set Name)+type InductionVarMap = BBNodeMap (S.Set Name) -- | Basic induction variables are induction variables that are the -- most easily derived from the syntactic structure of the program:@@ -390,8 +485,8 @@ basicInductionVars :: Data a => BackEdgeMap -> BBGr (Analysis a) -> InductionVarMap basicInductionVars bedges gr = IM.fromListWith S.union [ (n, S.singleton v) | (_, n) <- IM.toList bedges- , let Just bs = lab gr n- , b@(BlDo {}) <- bs+ , let Just bs = lab (bbgrGr gr) n+ , b@BlDo{} <- bs , v <- blockVarDefs b ] @@ -402,19 +497,19 @@ genInductionVarMap = basicInductionVars -- | InductionVarMapByASTBlock : AST-block label -> { name }-type InductionVarMapByASTBlock = IM.IntMap (S.Set Name)+type InductionVarMapByASTBlock = ASTBlockNodeMap (S.Set Name) -- | Generate an induction variable map that is indexed by the labels -- on AST-blocks within those loops. genInductionVarMapByASTBlock :: forall a. Data a => BackEdgeMap -> BBGr (Analysis a) -> InductionVarMapByASTBlock genInductionVarMapByASTBlock bedges gr = loopsToLabs . genInductionVarMap bedges $ gr where- lnMap = genLoopNodeMap bedges gr- get = fromMaybe (error "missing loop-header node") . flip IM.lookup lnMap- astLabels n = [ i | b <- (universeBi :: Maybe [Block (Analysis a)] -> [Block (Analysis a)]) (lab gr n)+ lnMap = genLoopNodeMap bedges $ bbgrGr gr+ get' = fromMaybe (error "missing loop-header node") . flip IM.lookup lnMap+ astLabels n = [ i | b <- (universeBi :: Maybe [Block (Analysis a)] -> [Block (Analysis a)]) (lab (bbgrGr gr) n) , let Just i = insLabel (getAnnotation b) ] loopsToLabs = IM.fromListWith S.union . concatMap loopToLabs . IM.toList- loopToLabs (n, ivs) = (map (,ivs) . astLabels) =<< IS.toList (get n)+ loopToLabs (n, ivs) = (map (,ivs) . astLabels) =<< IS.toList (get' n) -- It's a 'lattice' but will leave it ungeneralised for the moment. data InductionExpr@@ -423,14 +518,21 @@ | IEBottom -- too difficult deriving (Show, Eq, Ord, Typeable, Generic, Data) -type DerivedInductionMap = IM.IntMap InductionExpr+type DerivedInductionMap = ASTExprNodeMap InductionExpr data IEFlow = IEFlow { ieFlowVars :: M.Map Name InductionExpr, ieFlowExprs :: DerivedInductionMap } deriving (Show, Eq, Ord, Typeable, Generic, Data) +ieFlowInsertVar :: Name -> InductionExpr -> IEFlow -> IEFlow ieFlowInsertVar v ie flow = flow { ieFlowVars = M.insert v ie (ieFlowVars flow) }++ieFlowInsertExpr :: ASTExprNode -> InductionExpr -> IEFlow -> IEFlow ieFlowInsertExpr i ie flow = flow { ieFlowExprs = IM.insert i ie (ieFlowExprs flow) }++emptyIEFlow :: IEFlow emptyIEFlow = IEFlow M.empty IM.empty++joinIEFlows :: [IEFlow] -> IEFlow joinIEFlows flows = IEFlow flowV flowE where flowV = M.unionsWith joinInductionExprs (map ieFlowVars flows)@@ -442,13 +544,13 @@ genDerivedInductionMap bedges gr = ieFlowExprs . joinIEFlows . map snd . IM.elems . IM.filterWithKey inLoop $ inOutMaps where bivMap = basicInductionVars bedges gr -- basic indvars indexed by loop header node- loopNodeSet = IS.unions (loopNodes bedges gr) -- set of nodes within a loop+ loopNodeSet = IS.unions (loopNodes bedges $ bbgrGr gr) -- set of nodes within a loop inLoop i _ = i `IS.member` loopNodeSet step :: IEFlow -> Block (Analysis a) -> IEFlow step flow b = case b of BlStatement _ _ _ (StExpressionAssign _ _ lv@(ExpValue _ _ (ValVariable _)) rhs)- | rhsLabel <- insLabel (getAnnotation rhs)+ | _ <- insLabel (getAnnotation rhs) , flow'' <- ieFlowInsertVar (varName lv) (derivedInductionExpr flow' rhs) flow' -> stepExpr flow'' lv _ -> flow' where@@ -461,12 +563,12 @@ label = fromJustMsg "stepExpr" $ insLabel (getAnnotation e) out :: InF IEFlow -> OutF IEFlow- out inF node = foldl' step flow (fromJustMsg ("analyseDerivedIE out(" ++ show node ++ ")") $ lab gr node)+ out inF node = foldl' step flow (fromJustMsg ("analyseDerivedIE out(" ++ show node ++ ")") $ lab (bbgrGr gr) node) where flow = joinIEFlows [fst (initF node), inF node] inn :: OutF IEFlow -> InF IEFlow- inn outF node = joinIEFlows [ outF p | p <- pre gr node ]+ inn outF node = joinIEFlows [ outF p | p <- pre (bbgrGr gr) node ] initF :: Node -> InOut IEFlow initF node = case IM.lookup node bivMap of@@ -496,8 +598,8 @@ | lc == 0 = IELinear rn rc (lo + ro) | rc == 0 = IELinear ln lc (lo + ro) | otherwise = IEBottom -- maybe for future...-addInductionExprs ie1 IETop = IETop-addInductionExprs IETop ie2 = IETop+addInductionExprs _ IETop = IETop+addInductionExprs IETop _ = IETop addInductionExprs _ _ = IEBottom -- Negate an induction variable relationship.@@ -508,8 +610,8 @@ -- Combine two induction variable relationships through multiplication. mulInductionExprs :: InductionExpr -> InductionExpr -> InductionExpr-mulInductionExprs (IELinear "" lc lo) (IELinear rn rc ro) = IELinear rn (rc * lo) (ro * lo)-mulInductionExprs (IELinear ln lc lo) (IELinear "" rc ro) = IELinear ln (lc * ro) (lo * ro)+mulInductionExprs (IELinear "" _ lo) (IELinear rn rc ro) = IELinear rn (rc * lo) (ro * lo)+mulInductionExprs (IELinear ln lc lo) (IELinear "" _ ro) = IELinear ln (lc * ro) (lo * ro) mulInductionExprs _ IETop = IETop mulInductionExprs IETop _ = IETop mulInductionExprs _ _ = IEBottom@@ -528,7 +630,7 @@ showDataFlow :: (Data a, Out a, Show a) => ProgramFile (Analysis a) -> String showDataFlow pf = perPU =<< uni pf where- uni = (universeBi :: Data a => ProgramFile (Analysis a) -> [ProgramUnit (Analysis a)])+ uni = universeBi :: Data a => ProgramFile (Analysis a) -> [ProgramUnit (Analysis a)] perPU pu | Analysis { bBlocks = Just gr } <- getAnnotation pu = dashes ++ "\n" ++ p ++ "\n" ++ dashes ++ "\n" ++ dfStr gr ++ "\n\n" where p = "| Program Unit " ++ show (puName pu) ++ " |"@@ -544,25 +646,54 @@ , ("lva", show (IM.toList $ lva gr)) , ("rd", show (IM.toList $ rd gr)) , ("backEdges", show bedges)- , ("topsort", show (topsort gr))- , ("scc ", show (scc gr))- , ("loopNodes", show (loopNodes bedges gr))+ , ("topsort", show (topsort $ bbgrGr gr))+ , ("scc ", show (scc $ bbgrGr gr))+ , ("loopNodes", show (loopNodes bedges $ bbgrGr gr)) , ("duMap", show (genDUMap bm dm gr (rd gr))) , ("udMap", show (genUDMap bm dm gr (rd gr)))- , ("flowsTo", show (edges $ genFlowsToGraph bm dm gr (rd gr)))+ , ("flowsTo", show (edges flTo)) , ("varFlowsTo", show (genVarFlowsToMap dm (genFlowsToGraph bm dm gr (rd gr)))) , ("ivMap", show (genInductionVarMap bedges gr)) , ("ivMapByAST", show (genInductionVarMapByASTBlock bedges gr))- , ("noPredNodes", show (noPredNodes gr))+ , ("constExpMap", show (genConstExpMap pf))+ , ("entries", show (bbgrEntries gr))+ , ("exits", show (bbgrExits gr)) ] where- bedges = genBackEdgeMap (dominators gr) gr- perPU _ = ""+ bedges = genBackEdgeMap (dominators gr) $ bbgrGr gr+ flTo = genFlowsToGraph bm dm gr (rd gr)++ perPU pu = dashes ++ "\n" ++ p ++ "\n" ++ dashes ++ "\n" ++ dfStr ++ "\n\n"+ where p = "| Program Unit " ++ show (puName pu) ++ " |"+ dashes = replicate (length p) '-'+ dfStr = (\ (l, x) -> '\n':l ++ ": " ++ x) =<< [+ ("constExpMap", show (genConstExpMap pf))+ ]+ lva = liveVariableAnalysis bm = genBlockMap pf dm = genDefMap bm rd = reachingDefinitions dm cm = genCallMap pf +-- | Outputs a DOT-formatted graph showing flow-to data starting at+-- the given AST-Block node in the given Basic Block graph.+showFlowsDOT :: (Data a, Out a, Show a) => ProgramFile (Analysis a) -> BBGr (Analysis a) -> ASTBlockNode -> Bool -> String+showFlowsDOT pf bbgr astBlockId isFrom = execWriter $ do+ let bm = genBlockMap pf+ dm = genDefMap bm+ flowsTo = genFlowsToGraph bm dm bbgr (reachingDefinitions dm bbgr)+ flows | isFrom = grev flowsTo+ | otherwise = flowsTo+ tell "strict digraph {\n"+ forM_ (bfsn [astBlockId] flows) $ \ n -> do+ let pseudocode = maybe "<N/A>" showBlock $ IM.lookup n bm+ tell "node [shape=box,fontname=\"Courier New\"]\n"+ tell $ "Bl" ++ show n ++ "[label=\"B" ++ show n ++ "\\l" ++ pseudocode ++ "\"]\n"+ tell $ "Bl" ++ show n ++ " -> {"+ forM_ (suc flows n) $ \ m -> tell (" Bl" ++ show m)+ tell "}\n"+ tell "}\n"+ -------------------------------------------------- -- | CallMap : program unit name -> { name of function or subroutine }@@ -571,7 +702,7 @@ -- | Create a call map showing the structure of the program. genCallMap :: Data a => ProgramFile (Analysis a) -> CallMap genCallMap pf = flip execState M.empty $ do- let uP = (universeBi :: Data a => ProgramFile a -> [ProgramUnit a])+ let uP = universeBi :: Data a => ProgramFile a -> [ProgramUnit a] forM_ (uP pf) $ \ pu -> do let n = puName pu let uS :: Data a => ProgramUnit a -> [Statement a]@@ -579,18 +710,31 @@ let uE :: Data a => ProgramUnit a -> [Expression a] uE = universeBi m <- get- let ns = [ varName v | StCall _ _ v@(ExpValue _ _ _) _ <- uS pu ] ++- [ varName v | ExpFunctionCall _ _ v@(ExpValue _ _ _) _ <- uE pu ]+ let ns = [ varName v | StCall _ _ v@ExpValue{} _ <- uS pu ] +++ [ varName v | ExpFunctionCall _ _ v@ExpValue{} _ <- uE pu ] put $ M.insert n (S.fromList ns) m -------------------------------------------------- --- helper: iterate until predicate is satisfied.+-- | Finds the transitive closure of a directed graph.+-- Given a graph G=(V,E), its transitive closure is the graph:+-- G* = (V,E*) where E*={(i,j): i,j in V and there is a path from i to j in G}+--tc :: (DynGraph gr) => gr a b -> gr a ()+--tc g = newEdges `insEdges` insNodes ln empty+-- where+-- ln = labNodes g+-- newEdges = [ toLEdge (u, v) () | (u, _) <- ln, (_, v) <- bfen (outU g u) g ]+-- outU gr = map toEdge . out gr++-- helper: iterate until predicate is satisfied; expects infinite list. converge :: (a -> a -> Bool) -> [a] -> a converge p (x:ys@(y:_)) | p x y = y | otherwise = converge p ys+converge _ [] = error "converge: empty list"+converge _ [_] = error "converge: finite list" +fromJustMsg :: String -> Maybe a -> a fromJustMsg _ (Just x) = x fromJustMsg msg _ = error msg
src/Language/Fortran/Analysis/Renaming.hs view
@@ -11,26 +11,25 @@ ( analyseRenames, analyseRenamesWithModuleMap, rename, unrename, ModuleMap ) where -import Debug.Trace- import Language.Fortran.AST hiding (fromList) import Language.Fortran.Intrinsics import Language.Fortran.Analysis import Language.Fortran.ParserMonad (FortranVersion(..)) import Prelude hiding (lookup)-import Data.Maybe (maybe, fromMaybe)+import Data.Maybe (mapMaybe, maybe, fromMaybe) import qualified Data.List as L-import Data.Map (insert, union, empty, lookup, Map, fromList)+import Data.Map (insert, empty, lookup, Map) import qualified Data.Map.Strict as M+import Control.Monad (void) import Control.Monad.State.Strict import Data.Generics.Uniplate.Data import Data.Data+import Data.Functor.Identity (Identity) -------------------------------------------------- type ModuleMap = Map ProgramUnitName ModEnv-type NameMap = Map String String -- DEPRECATED type Renamer a = State RenameState a -- the monad. data RenameState = RenameState { langVersion :: FortranVersion@@ -47,17 +46,15 @@ -- | Annotate unique names for variable and function declarations and uses. analyseRenames :: Data a => ProgramFile (Analysis a) -> ProgramFile (Analysis a)-analyseRenames (ProgramFile mi pus) = ProgramFile mi pus'+analyseRenames (ProgramFile mi pus) = cleanupUseRenames $ ProgramFile mi pus' where- (Just pus', _) = runRenamer (skimProgramUnits pus >> renameSubPUs (Just pus))- (renameState0 (miVersion mi))+ (Just pus', _) = runRenamer (renameSubPUs (Just pus)) (renameState0 (miVersion mi)) -- | Annotate unique names for variable and function declarations and uses. With external module map. analyseRenamesWithModuleMap :: Data a => ModuleMap -> ProgramFile (Analysis a) -> ProgramFile (Analysis a)-analyseRenamesWithModuleMap mmap (ProgramFile mi pus) = ProgramFile mi pus'+analyseRenamesWithModuleMap mmap (ProgramFile mi pus) = cleanupUseRenames $ ProgramFile mi pus' where- (Just pus', _) = runRenamer (skimProgramUnits pus >> renameSubPUs (Just pus))- (renameState0 (miVersion mi)) { moduleMap = mmap }+ (Just pus', _) = runRenamer (renameSubPUs (Just pus)) (renameState0 (miVersion mi)) { moduleMap = mmap } -- | Take the unique name annotations and substitute them into the actual AST. rename :: Data a => ProgramFile (Analysis a) -> ProgramFile (Analysis a)@@ -81,7 +78,7 @@ -- | Take a renamed program and undo the renames. unrename :: Data a => ProgramFile (Analysis a) -> ProgramFile (Analysis a)-unrename pf = trPU fPU . trE fE $ pf+unrename = trPU fPU . trE fE where trE :: Data a => (Expression (Analysis a) -> Expression (Analysis a)) -> ProgramFile (Analysis a) -> ProgramFile (Analysis a) trE = transformBi@@ -93,9 +90,9 @@ trPU :: Data a => (ProgramUnit (Analysis a) -> ProgramUnit (Analysis a)) -> ProgramFile (Analysis a) -> ProgramFile (Analysis a) trPU = transformBi fPU :: Data a => ProgramUnit (Analysis a) -> ProgramUnit (Analysis a)- fPU (PUFunction a s ty r n args res b subs)+ fPU (PUFunction a s ty r _ args res b subs) | Just srcN <- sourceName a = PUFunction a s ty r srcN args res b subs- fPU (PUSubroutine a s r n args b subs)+ fPU (PUSubroutine a s r _ args b subs) | Just srcN <- sourceName a = PUSubroutine a s r srcN args b subs fPU pu = pu @@ -107,40 +104,42 @@ programUnit (PUModule a s name blocks m_contains) = do env0 <- initialEnv blocks pushScope name env0- blocks' <- mapM renameDeclDecls blocks -- handle declarations+ blocks1 <- mapM renameModDecls blocks -- handle declarations+ blocks2 <- mapM renameUseSt blocks1 -- handle use statements m_contains' <- renameSubPUs m_contains -- handle contained program units+ blocks3 <- mapM renameBlock blocks2 -- process all uses of functions/subroutine names env <- getEnv addModEnv name env -- save the module environment let a' = a { moduleEnv = Just env } -- also annotate it on the module popScope- return (PUModule a' s name blocks' m_contains')+ return (PUModule a' s name blocks3 m_contains') programUnit (PUFunction a s ty rec name args res blocks m_contains) = do- Just name' <- getFromEnv name -- get renamed function name- blocks1 <- mapM renameEntryPointDecl blocks -- rename any entry points- env0 <- initialEnv blocks1- pushScope name env0+ ~(Just name') <- getFromEnv name -- get renamed function name+ (blocks1, _) <- returnBlocksEnv blocks name blocks2 <- mapM renameEntryPointResultDecl blocks1 -- rename the result res' <- mapM renameGenericDecls res -- variable(s) if needed args' <- mapM renameGenericDecls args -- rename arguments blocks3 <- mapM renameDeclDecls blocks2 -- handle declarations m_contains' <- renameSubPUs m_contains -- handle contained program units blocks4 <- mapM renameBlock blocks3 -- process all uses of variables+ let env = M.singleton name (name', NTSubprogram)+ let a' = a { moduleEnv = Just env } -- also annotate it on the program unit popScope- let pu' = PUFunction a s ty rec name args' res' blocks4 m_contains'+ let pu' = PUFunction a' s ty rec name args' res' blocks4 m_contains' return . setSourceName name . setUniqueName name' $ pu' programUnit (PUSubroutine a s rec name args blocks m_contains) = do- Just name' <- getFromEnv name -- get renamed subroutine name- blocks1 <- mapM renameEntryPointDecl blocks -- rename any entry points- env0 <- initialEnv blocks1- pushScope name env0+ ~(Just name') <- getFromEnv name -- get renamed subroutine name+ (blocks1, _) <- returnBlocksEnv blocks name args' <- mapM renameGenericDecls args -- rename arguments blocks2 <- mapM renameDeclDecls blocks1 -- handle declarations m_contains' <- renameSubPUs m_contains -- handle contained program units blocks3 <- mapM renameBlock blocks2 -- process all uses of variables+ let env = M.singleton name (name', NTSubprogram)+ let a' = a { moduleEnv = Just env } -- also annotate it on the program unit popScope- let pu' = PUSubroutine a s rec name args' blocks3 m_contains'+ let pu' = PUSubroutine a' s rec name args' blocks3 m_contains' return . setSourceName name . setUniqueName name' $ pu' programUnit (PUMain a s n blocks m_contains) = do@@ -154,19 +153,26 @@ programUnit pu = return pu +returnBlocksEnv :: Data a => [Block (Analysis a)]+ -> String+ -> StateT RenameState Identity ([Block (Analysis a)], ModEnv)+returnBlocksEnv bs n = do+ bs1 <- mapM renameEntryPointDecl bs+ e0 <- initialEnv bs1+ pushScope n e0+ return (bs1, e0)+ declarator :: forall a. Data a => RenamerFunc (Declarator (Analysis a)) declarator (DeclVariable a s e1 me2 me3) = do e1' <- renameExpDecl e1- me2' <- traverse renameExp me2- me3' <- traverse renameExp me3+ me2' <- transformBiM (renameExp :: RenamerFunc (Expression (Analysis a))) me2+ me3' <- transformBiM (renameExp :: RenamerFunc (Expression (Analysis a))) me3 return $ DeclVariable a s e1' me2' me3' declarator (DeclArray a s e1 ddAList me2 me3) = do e1' <- renameExpDecl e1- let trans :: RenamerFunc (Expression (Analysis a)) -> RenamerFunc (AList DimensionDeclarator (Analysis a))- trans = transformBiM- ddAList' <- trans renameExp ddAList- me2' <- traverse renameExp me2- me3' <- traverse renameExp me3+ ddAList' <- transformBiM (renameExp :: RenamerFunc (Expression (Analysis a))) ddAList+ me2' <- transformBiM (renameExp :: RenamerFunc (Expression (Analysis a))) me2+ me3' <- transformBiM (renameExp :: RenamerFunc (Expression (Analysis a))) me3 return $ DeclArray a s e1' ddAList' me2' me3' expression :: Data a => RenamerFunc (Expression (Analysis a))@@ -177,6 +183,7 @@ -- transformations. -- Initial monad state.+renameState0 :: FortranVersion -> RenameState renameState0 v = RenameState { langVersion = v , intrinsics = getVersionIntrinsics v , scopeStack = []@@ -185,7 +192,8 @@ , moduleMap = empty } -- Run the monad.-runRenamer m = runState m+runRenamer :: State a b -> a -> (b, a)+runRenamer = runState -- Get a freshly generated number. getUniqNum :: Renamer Int@@ -201,38 +209,56 @@ n <- getUniqNum return $ scope ++ "_" ++ var ++ show n -isModule (PUModule {}) = True; isModule _ = False--isUseStatement (BlStatement _ _ _ (StUse _ _ (ExpValue _ _ (ValVariable _)) _ _)) = True-isUseStatement _ = False+--isModule :: ProgramUnit a -> Bool+--isModule (PUModule {}) = True; isModule _ = False -isUseID (UseID {}) = True; isUseID _ = False+isUseStatement :: Block a -> Bool+isUseStatement (BlStatement _ _ _ (StUse _ _ (ExpValue _ _ (ValVariable _)) _ _ _)) = True+isUseStatement _ = False -- Generate an initial environment for a scope based upon any Use -- statements in the blocks.-initialEnv :: Data a => [Block (Analysis a)] -> Renamer ModEnv+initialEnv :: forall a. Data a => [Block (Analysis a)] -> Renamer ModEnv initialEnv blocks = do- -- FIXME: add "use renaming" declarations (requires change in- -- NameMap because it would be possible for the same program object- -- to have two different names used by different parts of the- -- program). let uses = filter isUseStatement blocks- fmap M.unions . forM uses $ \ use -> case use of- (BlStatement _ _ _ (StUse _ _ (ExpValue _ _ (ValVariable m)) _ Nothing)) -> do- mMap <- gets moduleMap+ mMap <- gets moduleMap+ modEnv <- fmap M.unions . forM uses $ \ use -> case use of+ (BlStatement _ _ _ (StUse _ _ (ExpValue _ _ (ValVariable m)) _ _ Nothing)) -> return $ fromMaybe empty (Named m `lookup` mMap)- (BlStatement _ _ _ (StUse _ _ (ExpValue _ _ (ValVariable m)) _ (Just onlyAList)))- | only <- aStrip onlyAList, all isUseID only -> do- mMap <- gets moduleMap+ (BlStatement _ _ _ (StUse _ _ (ExpValue _ _ (ValVariable m)) _ _ (Just onlyAList)))+ | only <- aStrip onlyAList -> do let env = fromMaybe empty (Named m `lookup` mMap)- let onlyNames = map (\ (UseID _ _ v) -> varName v) only- -- filter for the the mod remappings mentioned in the list, only- return $ M.filterWithKey (\ k _ -> k `elem` onlyNames) env- _ -> trace "WARNING: USE renaming not supported (yet)" $ return empty+ -- list of (local name, original name) from USE declaration:+ let localNamePairs = flip mapMaybe only $ \ r -> case r of+ UseID _ _ v@(ExpValue _ _ ValVariable{}) -> Just (varName v, varName v)+ UseRename _ _ u v -> Just (varName u, varName v)+ _ -> Nothing+ -- create environment based on local name written in ONLY list+ -- (if applicable) and variable information found in imported+ -- mod env.+ let re = M.fromList [ (local, info) | (local, orig) <- localNamePairs+ , Just info <- [M.lookup orig env] ]+ return re+ _ -> return empty + -- Include any global names from program units defined outside of+ -- modules as well.+ let global = fromMaybe M.empty $ M.lookup NamelessMain mMap++ -- Include any mappings defined by COMMON blocks: use variable+ -- source name prefixed by name of COMMON block.+ let common = M.fromList [ (v, (v', NTVariable))+ | CommonGroup _ _ me1 alist <- universeBi blocks :: [CommonGroup (Analysis a)]+ , let prefix = case me1 of Just e1 -> srcName e1; _ -> ""+ , e@(ExpValue _ _ ValVariable{}) <- universeBi (aStrip alist) :: [Expression (Analysis a)]+ , let v = srcName e+ , let v' = prefix ++ "_" ++ v ++ "_common" ]++ return $ M.unions [modEnv, global, common]+ -- Get the current scope name.-getScope :: Renamer String-getScope = gets (head . scopeStack)+--getScope :: Renamer String+--getScope = gets (head . scopeStack) -- Get the concatenated scopes. getScopes :: Renamer String@@ -295,7 +321,7 @@ case mEntry of Just (v', NTSubprogram) -> return $ Just v' Just (_, NTVariable) -> getFromEnv v- _ -> return $ Nothing+ _ -> return Nothing -- Add a renaming mapping to the environment. addToEnv :: String -> String -> NameType -> Renamer ()@@ -309,7 +335,7 @@ return v' addUnique_ :: String -> NameType -> Renamer ()-addUnique_ v nt = addUnique v nt >> return ()+addUnique_ v nt = void (addUnique v nt) -- This function will be invoked by occurrences of -- declarations. First, search to see if v is a subprogram name that@@ -324,17 +350,17 @@ -- If uniqueName/sourceName property is not set, then set it. setUniqueName, setSourceName :: (Annotated f, Data a) => String -> f (Analysis a) -> f (Analysis a) setUniqueName un x- | a@(Analysis { uniqueName = Nothing }) <- getAnnotation x = setAnnotation (a { uniqueName = Just un }) x- | otherwise = x+ | a@Analysis { uniqueName = Nothing } <- getAnnotation x = setAnnotation (a { uniqueName = Just un }) x+ | otherwise = x setSourceName sn x- | a@(Analysis { sourceName = Nothing }) <- getAnnotation x = setAnnotation (a { sourceName = Just sn }) x- | otherwise = x+ | a@Analysis { sourceName = Nothing } <- getAnnotation x = setAnnotation (a { sourceName = Just sn }) x+ | otherwise = x -- Work recursively into sub-program units. renameSubPUs :: Data a => RenamerFunc (Maybe [ProgramUnit (Analysis a)]) renameSubPUs Nothing = return Nothing-renameSubPUs (Just pus) = skimProgramUnits pus >> Just `fmap` (mapM programUnit pus)+renameSubPUs (Just pus) = skimProgramUnits pus >> Just <$> mapM programUnit pus -- Go through all program units at the same level and add their names -- to the environment.@@ -367,6 +393,24 @@ renameExpDecl e@(ExpValue _ _ (ValIntrinsic v)) = flip setUniqueName (setSourceName v e) `fmap` addUnique v NTIntrinsic renameExpDecl e = return e +renameInterfaces :: (Data a, Data (f (Analysis a))) => RenamerFunc (f (Analysis a))+renameInterfaces = trans interface+ where+ trans :: (Data a, Data (f (Analysis a))) => RenamerFunc (Block (Analysis a)) -> RenamerFunc (f (Analysis a))+ trans = transformBiM++interface :: Data a => RenamerFunc (Block (Analysis a))+interface (BlInterface a s (Just e@(ExpValue _ _ (ValVariable v))) abst pus bs) = do+ e' <- flip setUniqueName (setSourceName v e) `fmap` maybeAddUnique v NTSubprogram+ pure $ BlInterface a s (Just e') abst pus bs+interface b = pure b++-- Handle generic-interfaces as if they were subprograms, then handle+-- other declarations, assuming they might possibly need the creation+-- of new unique mappings.+renameModDecls :: (Data a, Data (f (Analysis a))) => RenamerFunc (f (Analysis a))+renameModDecls = renameDeclDecls <=< renameInterfaces+ -- Find all declarators within a value and then dive within those -- declarators to rename any ExpValue variables, assuming they might -- possibly need the creation of new unique mappings.@@ -399,7 +443,7 @@ -- Rename an ExpValue variable, assuming that it is to be treated as a -- reference to a previous declaration, possibly in an outer scope. renameExp :: Data a => RenamerFunc (Expression (Analysis a))-renameExp e@(ExpValue _ _ (ValVariable v)) = maybe e (flip setUniqueName (setSourceName v e)) `fmap` getFromEnvs v+renameExp e@(ExpValue _ _ (ValVariable v)) = maybe e (`setUniqueName` setSourceName v e) `fmap` getFromEnvs v -- Intrinsics get unique names for each use. renameExp e@(ExpValue _ _ (ValIntrinsic v)) = flip setUniqueName (setSourceName v e) `fmap` addUnique v NTIntrinsic renameExp e = return e@@ -413,7 +457,26 @@ trans :: Data a => RenamerFunc (Expression a) -> RenamerFunc (Block a) trans = transformBiM -- search all expressions, bottom-up +-- Rename the components of a Use statement contained in the block.+renameUseSt :: Data a => RenamerFunc (Block (Analysis a))+renameUseSt (BlStatement a s l st@StUse{}) = BlStatement a s l <$> trans expression st+ where+ trans :: Data a => RenamerFunc (Expression a) -> RenamerFunc (Statement a)+ trans = transformBiM -- search all expressions, bottom-up+renameUseSt b = return b+ --------------------------------------------------++-- Ensure second part of UseRename has the right uniqueName &+-- sourceName, since that name does not appear in our mod env, because+-- it has been given a different local name by the programmer.+cleanupUseRenames :: forall a. Data a => ProgramFile (Analysis a) -> ProgramFile (Analysis a)+cleanupUseRenames = transformBi (\ u -> case u :: Use (Analysis a) of+ UseRename a s e1 e2@(ExpValue _ _ (ValVariable v)) -> UseRename a s e1 $ setUniqueName (varName e1) (setSourceName v e2)+ _ -> u)+++ -- Local variables: -- mode: haskell
src/Language/Fortran/Analysis/Types.hs view
@@ -1,17 +1,22 @@ {-# LANGUAGE ScopedTypeVariables #-}-module Language.Fortran.Analysis.Types ( analyseTypes, analyseTypesWithEnv, extractTypeEnv, TypeEnv ) where+module Language.Fortran.Analysis.Types+ ( analyseTypes, analyseTypesWithEnv, analyseAndCheckTypesWithEnv, extractTypeEnv, TypeEnv, TypeError )+where import Language.Fortran.AST -import Prelude hiding (lookup)+import Prelude hiding (lookup, EQ, LT, GT) import Data.Map (insert) import qualified Data.Map as M import Data.Maybe (maybeToList)+import Data.List (find) import Control.Monad.State.Strict import Data.Generics.Uniplate.Data import Data.Data+import Data.Functor.Identity (Identity ()) import Language.Fortran.Analysis import Language.Fortran.Intrinsics+import Language.Fortran.Util.Position import Language.Fortran.ParserMonad (FortranVersion(..)) @@ -20,6 +25,9 @@ -- | Mapping of names to type information. type TypeEnv = M.Map Name IDType +-- | Information about a detected type error.+type TypeError = (String, SrcSpan)+ -------------------------------------------------- -- Monad for type inference work@@ -27,7 +35,8 @@ data InferState = InferState { langVersion :: FortranVersion , intrinsics :: IntrinsicsTable , environ :: TypeEnv- , entryPoints :: M.Map Name (Name, Maybe Name) }+ , entryPoints :: M.Map Name (Name, Maybe Name)+ , typeErrors :: [TypeError] } deriving Show type InferFunc t = t -> Infer () @@ -42,7 +51,24 @@ -- environment mapping names to type information; provided with a -- starting type environment. analyseTypesWithEnv :: Data a => TypeEnv -> ProgramFile (Analysis a) -> (ProgramFile (Analysis a), TypeEnv)-analyseTypesWithEnv env pf@(ProgramFile mi _) = fmap environ . runInfer (miVersion mi) env $ do+analyseTypesWithEnv env pf = (pf', tenv)+ where+ (pf', endState) = analyseTypesWithEnv' env pf+ tenv = environ endState++-- | Annotate AST nodes with type information, return a type+-- environment mapping names to type information and return any type+-- errors found; provided with a starting type environment.+analyseAndCheckTypesWithEnv+ :: Data a => TypeEnv -> ProgramFile (Analysis a) -> (ProgramFile (Analysis a), TypeEnv, [TypeError])+analyseAndCheckTypesWithEnv env pf = (pf', tenv, terrs)+ where+ (pf', endState) = analyseTypesWithEnv' env pf+ tenv = environ endState+ terrs = typeErrors endState++analyseTypesWithEnv' :: Data a => TypeEnv -> ProgramFile (Analysis a) -> (ProgramFile (Analysis a), InferState)+analyseTypesWithEnv' env pf@(ProgramFile mi _) = runInfer (miVersion mi) env $ do -- Gather information. mapM_ intrinsicsExp (allExpressions pf) mapM_ programUnit (allProgramUnits pf)@@ -51,7 +77,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@@ -68,7 +94,7 @@ puEnv = M.fromList [ (n, ty) | pu <- universeBi pf :: [ProgramUnit (Analysis a)] , Named n <- [puName pu] , ty <- maybeToList (idType (getAnnotation pu)) ]- expEnv = M.fromList [ (n, ty) | e <- universeBi pf :: [Expression (Analysis a)]+ expEnv = M.fromList [ (n, ty) | e@(ExpValue _ _ ValVariable{}) <- universeBi pf :: [Expression (Analysis a)] , let n = varName e , ty <- maybeToList (idType (getAnnotation e)) ] @@ -82,10 +108,11 @@ intrinsicsExp (ExpFunctionCall _ _ nexp _) = intrinsicsHelper nexp intrinsicsExp _ = return () +intrinsicsHelper :: Expression (Analysis a) -> StateT InferState Identity () intrinsicsHelper nexp | isNamedExpression nexp = do itab <- gets intrinsics case getIntrinsicReturnType (srcName nexp) itab of- Just itype -> do+ Just _ -> do let n = varName nexp recordCType CTIntrinsic n -- recordBaseType _ n -- FIXME: going to skip base types for the moment@@ -103,7 +130,7 @@ _ -> return () -- record entry points for later annotation forM_ blocks $ \ block ->- sequence_ [ recordEntryPoint n (varName v) (fmap varName mRetVar) | (StEntry _ _ v _ mRetVar) <- allStatements block ]+ sequence_ [ recordEntryPoint n (varName v) (fmap varName mRetVar') | (StEntry _ _ v _ mRetVar') <- allStatements block ] programUnit pu@(PUSubroutine _ _ _ _ _ blocks _) | Named n <- puName pu = do -- record the fact that this is a subroutine recordCType CTSubroutine n@@ -113,29 +140,42 @@ programUnit _ = return () declarator :: Data a => InferFunc (Declarator (Analysis a))-declarator (DeclArray _ _ v _ _ _) = recordCType CTArray (varName v)-declarator _ = return ()+declarator (DeclArray _ _ v ddAList _ _) = recordCType (CTArray $ dimDeclarator ddAList) (varName v)+declarator _ = return () +dimDeclarator :: AList DimensionDeclarator a -> [(Maybe Int, Maybe Int)]+dimDeclarator ddAList = [ (lb, ub) | DimensionDeclarator _ _ lbExp ubExp <- aStrip ddAList+ , let lb = do ExpValue _ _ (ValInteger i) <- lbExp+ return $ read i+ , let ub = do ExpValue _ _ (ValInteger i) <- ubExp+ 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) | mAttrs <- maybe [] aStrip mAttrAList- , isArray <- any isAttrDimension mAttrs+ , attrDim <- find isAttrDimension mAttrs , isParam <- any isAttrParameter mAttrs , isExtrn <- any isAttrExternal mAttrs , decls <- aStrip declAList = do env <- gets environ- forM_ decls $ \ decl -> case decl of- DeclArray _ _ v _ _ _ -> recordType baseType CTArray (varName v)- DeclVariable _ _ v (Just _) _ -> recordType baseType CTVariable (varName v)- DeclVariable _ _ v Nothing _ -> recordType baseType cType n- where- n = varName v- cType | isExtrn = CTExternal- | isArray = CTArray+ let cType n | isExtrn = CTExternal+ | Just (AttrDimension _ _ ddAList) <- attrDim = CTArray (dimDeclarator ddAList) | isParam = CTParameter- | Just (IDType _ (Just ct)) <- M.lookup n env = ct+ | 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+ statement (StExternal _ _ varAList) = do let vars = aStrip varAList mapM_ (recordCType CTExternal . varName) vars@@ -145,45 +185,193 @@ let n = varName v mIDType <- getRecordedType n case mIDType of- Just (IDType mBT (Just CTArray)) -> return () -- do nothing, it's already known to be an array+ Just (IDType _ (Just CTArray{})) -> return () -- do nothing, it's already known to be an array _ -> recordCType CTFunction n -- assume it's a function statement -- FIXME: if StFunctions can only be identified after types analysis -- is complete and disambiguation is performed, then how do we get -- them in the first place? (iterate until fixed point?) statement (StFunction _ _ v _ _) = recordCType CTFunction (varName v)+-- (part of answer to above is) nullary function statement: foo() = ...+statement (StExpressionAssign _ _ (ExpFunctionCall _ _ v Nothing) _) = recordCType CTFunction (varName v) statement (StDimension _ _ declAList) = do let decls = aStrip declAList forM_ decls $ \ decl -> case decl of- DeclArray _ _ v _ _ _ -> recordCType CTArray (varName v)- _ -> return ()+ DeclArray _ _ v ddAList _ _ -> recordCType (CTArray $ dimDeclarator ddAList) (varName v)+ _ -> return () statement _ = return () annotateExpression :: Data a => Expression (Analysis a) -> Infer (Expression (Analysis a))-annotateExpression e@(ExpValue _ _ (ValVariable _)) = maybe e (flip setIDType e) `fmap` getRecordedType (varName e)-annotateExpression e@(ExpValue _ _ (ValIntrinsic _)) = maybe e (flip setIDType e) `fmap` getRecordedType (varName e)-annotateExpression e = return e+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@(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+annotateExpression e@(ExpFunctionCall _ _ e1 parAList) = flip setIDType e `fmap` functionCallType (getSpan e) e1 parAList+annotateExpression e = return e annotateProgramUnit :: Data a => ProgramUnit (Analysis a) -> Infer (ProgramUnit (Analysis a))-annotateProgramUnit pu | Named n <- puName pu = maybe pu (flip setIDType pu) `fmap` getRecordedType n+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++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++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+ _ -> typeError "Unable to obtain type for first operand" (getSpan e1) >> return Nothing+ mbt2 <- case getIDType e2 of+ Just (IDType (Just bt) _) -> return $ Just bt+ _ -> typeError "Unable to obtain type for second operand" (getSpan e2) >> return Nothing+ case (mbt1, mbt2) 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+ | 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+ | BinCustom{} <- op -> typeError "custom binary ops not supported" ss >> return Nothing+ _ -> return Nothing++ return $ IDType mbt' Nothing++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+ _ -> typeError "Unable to obtain type for" (getSpan e) >> return Nothing+ mbt' <- case (mbt, op) of+ (Nothing, _) -> return Nothing+ (Just TypeCustom{}, _) -> 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, _)+ | op `elem` [Plus, Minus] &&+ bt `elem` numericTypes -> return $ Just bt+ _ -> typeError "Type error for unary operator" ss >> return Nothing+ return $ IDType mbt' Nothing++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+ forM_ idxs $ \ idx -> case idx of+ IxSingle _ _ _ ie+ | not (isInteger ie) -> typeError "Invalid or unknown type for index" (getSpan ie)+ IxRange _ _ mie1 mie2 mie3+ | Just ie1 <- mie1, not (isInteger ie1) -> typeError "Invalid or unknown type for index" (getSpan ie1)+ | Just ie2 <- mie2, not (isInteger ie2) -> typeError "Invalid or unknown type for index" (getSpan ie2)+ | 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+ 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+ else return ty+ _ -> return emptyType++functionCallType :: Data a => SrcSpan -> Expression (Analysis a) -> Maybe (AList Argument (Analysis a)) -> Infer IDType+functionCallType ss (ExpValue _ _ (ValIntrinsic n)) (Just (AList _ _ params)) = do+ itab <- gets intrinsics+ let mRetType = getIntrinsicReturnType n itab+ 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+ 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+ Nothing -> return emptyType+ Just _ -> return $ IDType mbt Nothing+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+ _ -> 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]+ -------------------------------------------------- -- Monadic helper combinators. -inferState0 v = InferState { environ = M.empty, entryPoints = M.empty, langVersion = v, intrinsics = getVersionIntrinsics v }+inferState0 :: FortranVersion -> InferState+inferState0 v = InferState { environ = M.empty, entryPoints = M.empty, langVersion = v+ , intrinsics = getVersionIntrinsics v, typeErrors = [] } runInfer :: FortranVersion -> TypeEnv -> State InferState a -> (a, InferState) runInfer v env = flip runState ((inferState0 v) { environ = env }) +typeError :: String -> SrcSpan -> Infer ()+typeError msg ss = modify $ \ s -> s { typeErrors = (msg, ss):typeErrors s }++emptyType :: IDType+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) } -- 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 bt ct n = modify $ \ s -> s { environ = insert n (IDType bt ct) (environ s) } -- Record the CType of the given name. recordCType :: ConstructType -> Name -> Infer ()@@ -204,7 +392,7 @@ -- Set the idType annotation setIDType :: Annotated f => IDType -> f (Analysis a) -> f (Analysis a) setIDType ty x- | a@(Analysis {}) <- getAnnotation x = setAnnotation (a { idType = Just ty }) x+ | a@Analysis {} <- getAnnotation x = setAnnotation (a { idType = Just ty }) x | otherwise = x -- Get the idType annotation@@ -212,10 +400,10 @@ getIDType x = idType (getAnnotation x) -- Set the CType part of idType annotation-setCType :: (Annotated f, Data a) => ConstructType -> f (Analysis a) -> f (Analysis a)-setCType ct x- | a@(Analysis { idType = Nothing }) <- getAnnotation x = setAnnotation (a { idType = Just (IDType Nothing (Just ct)) }) x- | a@(Analysis { idType = Just it }) <- getAnnotation x = setAnnotation (a { idType = Just (it { idCType = Just ct }) }) x+--setCType :: (Annotated f, Data a) => ConstructType -> f (Analysis a) -> f (Analysis a)+--setCType ct x+-- | a@(Analysis { idType = Nothing }) <- getAnnotation x = setAnnotation (a { idType = Just (IDType Nothing (Just ct)) }) x+-- | a@(Analysis { idType = Just it }) <- getAnnotation x = setAnnotation (a { idType = Just (it { idCType = Just ct }) }) x type UniFunc f g a = f (Analysis a) -> [g (Analysis a)] @@ -231,16 +419,20 @@ allExpressions :: (Data a, Data (f (Analysis a))) => UniFunc f Expression a allExpressions = universeBi -isAttrDimension (AttrDimension {}) = True-isAttrDimension _ = False+isAttrDimension :: Attribute a -> Bool+isAttrDimension AttrDimension {} = True+isAttrDimension _ = False -isAttrParameter (AttrParameter {}) = True+isAttrParameter :: Attribute a -> Bool+isAttrParameter AttrParameter {} = True isAttrParameter _ = False -isAttrExternal (AttrExternal {}) = True+isAttrExternal :: Attribute a -> Bool+isAttrExternal AttrExternal {} = True isAttrExternal _ = False -isIxSingle (IxSingle {}) = True+isIxSingle :: Index a -> Bool+isIxSingle IxSingle {} = True isIxSingle _ = False --------------------------------------------------
src/Language/Fortran/Intrinsics.hs view
@@ -19,11 +19,13 @@ data IntrinsicsEntry = IEntry { iType :: IntrinsicType, iDefsUses :: ([Int], [Int]) } deriving (Show, Eq, Ord, Typeable, Generic) -mkIEntry ty du = IEntry ty du+mkIEntry :: IntrinsicType -> ([Int], [Int]) -> IntrinsicsEntry+mkIEntry = IEntry type IntrinsicsTable = M.Map String IntrinsicsEntry -- Main table of Fortran intrinsics by version+fortranVersionIntrinsics :: [(FortranVersion, IntrinsicsTable)] fortranVersionIntrinsics = [ (Fortran66, fortran77intrinsics) -- FIXME: find list of original '66 intrinsics , (Fortran77, fortran77intrinsics)@@ -48,10 +50,15 @@ allIntrinsics :: IntrinsicsTable allIntrinsics = M.unions (map snd fortranVersionIntrinsics) +func1 :: ([Int], [Int]) func1 = ([0],[1])+func2 :: ([Int], [Int]) func2 = ([0],[1,2])+func3 :: ([Int], [Int]) func3 = ([0],[1,2,3])+func4 :: ([Int], [Int]) func4 = ([0],[1,2,3,4])+funcN :: ([Int], [Int]) funcN = func2 -- FIXME: implement arbitrary-# parameter functions -- | name => (return-unit, parameter-units)@@ -68,6 +75,7 @@ , ("cmplx" , mkIEntry ITComplex func1) , ("ichar" , mkIEntry ITInteger func1) , ("char" , mkIEntry ITCharacter func1)+ , ("achar" , mkIEntry ITCharacter func1) , ("aint" , mkIEntry (ITParam 1) func1) , ("dint" , mkIEntry ITDouble func1) , ("anint" , mkIEntry (ITParam 1) func1)@@ -151,19 +159,19 @@ fortran90intrinisics :: IntrinsicsTable fortran90intrinisics = fortran77intrinsics `M.union` M.fromList- [ ("present" , mkIEntry (ITLogical) func1)+ [ ("present" , mkIEntry ITLogical func1) , ("modulo" , mkIEntry (ITParam 1) func2) , ("ceiling" , mkIEntry (ITParam 1) func1)- , ("iand" , mkIEntry (ITInteger) func2)- , ("ior" , mkIEntry (ITInteger) func2)- , ("ieor" , mkIEntry (ITInteger) func2)- , ("iany" , mkIEntry (ITInteger) func2)- , ("ibclr" , mkIEntry (ITInteger) func2)- , ("ibits" , mkIEntry (ITInteger) func3)- , ("ibset" , mkIEntry (ITInteger) func2)- , ("ishftc" , mkIEntry (ITInteger) func3)- , ("btest" , mkIEntry (ITInteger) func2)- , ("not" , mkIEntry (ITInteger) func1)+ , ("iand" , mkIEntry ITInteger func2)+ , ("ior" , mkIEntry ITInteger func2)+ , ("ieor" , mkIEntry ITInteger func2)+ , ("iany" , mkIEntry ITInteger func2)+ , ("ibclr" , mkIEntry ITInteger func2)+ , ("ibits" , mkIEntry ITInteger func3)+ , ("ibset" , mkIEntry ITInteger func2)+ , ("ishftc" , mkIEntry ITInteger func3)+ , ("btest" , mkIEntry ITInteger func2)+ , ("not" , mkIEntry ITInteger func1) , ("dot_product" , mkIEntry (ITParam 1) func2) , ("matmul" , mkIEntry (ITParam 1) func2) , ("all" , mkIEntry ITLogical func2)@@ -187,4 +195,5 @@ , ("transpose" , mkIEntry (ITParam 1) func1) , ("maxloc" , mkIEntry (ITParam 1) func2) , ("minloc" , mkIEntry (ITParam 1) func2)+ , ("epsilon" , mkIEntry (ITReal) func1) ]
src/Language/Fortran/LValue.hs view
@@ -6,6 +6,7 @@ module Language.Fortran.LValue where +import Prelude hiding (exp) import Data.Data import GHC.Generics (Generic)
src/Language/Fortran/Lexer/FixedForm.x view
@@ -29,6 +29,7 @@ import Language.Fortran.Util.FirstParameter import Language.Fortran.Util.Position+import Language.Fortran.Parser.Utils (readInteger) } @@ -37,6 +38,8 @@ $hexDigit = [a-f $digit] $bit = 0-1 +$hash = [\#]+ @binary = b\'$bit+\' | \'$bit+\'b @octal = o\'$octalDigit+\' | \'$octalDigit+\'o @hex = x\'$hexDigit+\' | \'$hexDigit+\'x | z\'$hexDigit+\' | \'$hexDigit+\'z@@ -72,12 +75,14 @@ tokens :- - <0> [c!\*d] / { commentP } { lexComment Nothing }- "!" / { bangCommentP &&& legacy77P } { lexComment Nothing }+ <0> [c!\*d] / { commentP } { lexComment }+ "!" / { bangCommentP &&& legacy77P } { lexComment } <0> @label / { withinLabelColsP } { addSpanAndMatch TLabel } <0> . / { \_ ai _ _ -> atColP 6 ai } { toSC keyword } <0> " " ; + <0> $hash { lexHash }+ <0,st,keyword,iif,assn,doo> \n { resetPar >> toSC 0 >> addSpan TNewline } <0,st,keyword,iif,assn,doo> \r ; <0,st,keyword,iif,assn,doo> ";" { resetPar >> toSC keyword >> addSpan TNewline }@@ -279,7 +284,7 @@ implicitTypeExtendedP fv b c d = extended77P fv b c d && implicitStP fv b c d implicitStP :: FortranVersion -> AlexInput -> Int -> AlexInput -> Bool-implicitStP fv _ _ ai = checkPreviousTokensInLine f ai+implicitStP _ _ _ ai = checkPreviousTokensInLine f ai where f (TImplicit _) = True f _ = False@@ -296,7 +301,7 @@ doP :: FortranVersion -> AlexInput -> Bool doP fv ai = isPrefixOf "do" (reverse . lexemeMatch . aiLexeme $ ai) &&- case unParse (lexer $ f 0) ps of+ case unParse (lexer $ f (0::Integer)) ps of ParseOk True _ -> True _ -> False where@@ -357,14 +362,14 @@ _ -> return False hollerithP :: FortranVersion -> AlexInput -> Int -> AlexInput -> Bool-hollerithP fv _ _ ai = isDigit (lookBack 2 ai)+hollerithP _ _ _ ai = isDigit (lookBack 2 ai) notToP :: FortranVersion -> AlexInput -> Int -> AlexInput -> Bool-notToP fv _ _ ai = not $ "to" `isPrefixOf` (reverse . lexemeMatch . aiLexeme $ ai)+notToP _ _ _ ai = not $ "to" `isPrefixOf` (reverse . lexemeMatch . aiLexeme $ ai) equalFollowsP :: FortranVersion -> AlexInput -> Bool equalFollowsP fv ai =- case unParse (lexer $ f False 0) ps of+ case unParse (lexer $ f False (0::Integer)) ps of ParseOk True _ -> True _ -> False where@@ -383,6 +388,7 @@ TDot{} -> lexer $ f False 0 TId{} -> lexer $ f False 0 _ -> return False+ f False _ _ = return False f True 0 t = case t of TOpAssign{} -> return True@@ -421,7 +427,7 @@ _endsWithLine = (posColumn . aiPosition) aiNew /= 1 bangCommentP :: FortranVersion -> AlexInput -> Int -> AlexInput -> Bool-bangCommentP fv aiOld i aiNew = _endsWithLine+bangCommentP _ _ _ aiNew = _endsWithLine where _endsWithLine = (posColumn . aiPosition) aiNew /= 1 @@ -558,38 +564,44 @@ lexeme <- getLexeme return $ getSpan lexeme --- With the existing alexGetByte implementation comments are matched without--- whitespace characters. However, we have access to final column number,--- we know the comment would start at column, and we have access to the absolute--- offset so instead of using match, lexComment takes a slice from the original--- source input-lexComment :: Maybe Char -> LexAction (Maybe Token)-lexComment mc = do- m <- getMatch- s <- getLexemeSpan+-- Handle pragmas that begin with #+lexHash :: LexAction (Maybe Token)+lexHash = do+ lexLineWithWhitespace $ \ m -> do+ ai <- getAlex+ case words (drop 1 m) of+ -- 'line' pragma - rewrite the current line and filename+ "line":lineStr:_+ | Just line <- readInteger lineStr -> do+ let revdropWNQ = reverse . drop 1 . dropWhile (flip notElem "'\"")+ let file = revdropWNQ . revdropWNQ $ m+ let lineOffs = fromIntegral line - posLine (aiPosition ai) - 1+ let newP = (aiPosition ai) { posPragmaOffset = Just (lineOffs, file)+ , posColumn = 1 }+ putAlex $ ai { aiPosition = newP }+ _ -> return ()+ return Nothing++-- Lex comments with whitespace included+lexComment :: LexAction (Maybe Token)+lexComment =+ lexLineWithWhitespace $ \ m -> do+ s <- getLexemeSpan+ return . Just . TComment s $ tail m++-- Get a line without losing the whitespace, then call continuation with it.+lexLineWithWhitespace :: (String -> LexAction (Maybe Token)) -> LexAction (Maybe Token)+lexLineWithWhitespace k = do alex <- getAlex- version <- getVersion- let emitComment = case version of- Fortran77Legacy- -> return Nothing- _ -> return $ Just $ TComment s $ tail m let modifiedAlex = alex { aiWhiteSensitiveCharCount = 1 }- case mc of- Just '\n' -> emitComment- Just _ ->- case alexGetByte modifiedAlex of- Just (w, _) | fromIntegral w == ord '\n' -> do- emitComment- Just (_, newAlex) -> do- putAlex newAlex- lexComment Nothing- Nothing -> fail "Comment abruptly ended."- Nothing ->- case alexGetByte modifiedAlex of- Just (_, newAlex) -> lexComment (Just $ (head . lexemeMatch . aiLexeme) newAlex)- Nothing -> emitComment+ case alexGetByte modifiedAlex of+ Just (w, newAlex)+ | fromIntegral w /= ord '\n' -> putAlex newAlex >> lexLineWithWhitespace k+ _ -> getMatch >>= k +--------------------------------------------------+ {- Chars +-+@@ -635,13 +647,13 @@ strAutomaton c 0 else strAutomaton c 2 Nothing -> strAutomaton c 2-strAutomaton c 2 = do+strAutomaton _ 2 = do s <- getLexemeSpan m <- getMatch resetWhiteSensitiveCharCount setCaseInsensitive return $ Just $ TString s $ (init . tail) m-strAutomaton c 3 = fail "Unmatched string."+strAutomaton _ _ = fail "Unmatched string." lexHollerith :: LexAction (Maybe Token) lexHollerith = do@@ -665,7 +677,7 @@ then return $ Just match' else case alexGetByte alex of- Just (w, newAlex) | fromIntegral w == ord '\n' -> do+ Just (w, _) | fromIntegral w == ord '\n' -> do return . Just $! pad match' Just (_, newAlex) -> do putAlex newAlex@@ -677,8 +689,8 @@ maybeToKeyword :: LexAction (Maybe Token) maybeToKeyword = do decPar- pcActual <- pcActual . psParanthesesCount <$> get- if pcActual == 0+ pcActual' <- pcActual . psParanthesesCount <$> get+ if pcActual' == 0 then toSC keyword else return Nothing @@ -910,8 +922,8 @@ -- Skip the continuation line altogether | isContinuation ai && _isWhiteInsensitive = skip Continuation ai -- Skip the newline before a comment- | aiFortranVersion ai == Fortran77Legacy &&- _isWhiteInsensitive && isNewlineComment ai = skip NewlineComment ai+ | aiFortranVersion ai == Fortran77Legacy && _isWhiteInsensitive+ && isNewlineCommentsFollowedByContinuation ai = skip NewlineComment ai -- If we are not parsing a Hollerith skip whitespace | _curChar `elem` [ ' ', '\t' ] && _isWhiteInsensitive = skip Char ai -- Ignore inline comments@@ -968,6 +980,13 @@ _next1 = takeNChars 1 ai p = (aiPosition ai) { posAbsoluteOffset = posAbsoluteOffset (aiPosition ai) + 1 } +isNewlineCommentsFollowedByContinuation :: AlexInput -> Bool+isNewlineCommentsFollowedByContinuation ai+ | isNewlineComment ai+ = isNewlineCommentsFollowedByContinuation (ai { aiPosition = advance NewlineComment ai })+ | isContinuation ai = True+ | otherwise = False+ skip :: Move -> AlexInput -> Maybe (Word8, AlexInput) skip move ai = let _newPosition = advance move ai in@@ -1004,12 +1023,12 @@ skipCommentLines :: AlexInput -> Position -> Position skipCommentLines ai p = go p p where- go p' p+ go p' p'' -- eof is not a comment line | not (null line)- , isCommentLine ai p- = go p p{ posAbsoluteOffset = posAbsoluteOffset p + length line + 1 -- skip the newline- , posColumn = 1, posLine = posLine p + 1+ , isCommentLine ai p''+ = go p'' p''{ posAbsoluteOffset = posAbsoluteOffset p'' + length line + 1 -- skip the newline+ , posColumn = 1, posLine = posLine p'' + 1 } | isContinuation ai' = advance Continuation ai'@@ -1017,7 +1036,7 @@ -- after skipping comment lines, place cursor right at the last newline = p2 where- line = takeLine p ai+ line = takeLine p'' ai line' = takeLine p' ai p2 = p' { posAbsoluteOffset = posAbsoluteOffset p' + length line' , posColumn = length line' + 1@@ -1081,7 +1100,7 @@ parseState <- get fail $ psFilename parseState ++ ": lexing failed. " AlexSkip newAlex _ -> putAlex newAlex >> lexer'- AlexToken newAlex startCode action -> do+ AlexToken newAlex _ action -> do putAlex newAlex maybeToken <- action case maybeToken of@@ -1110,7 +1129,8 @@ _vanillaAlexInput = vanillaAlexInput { aiSourceBytes = srcBytes , aiEndOffset = fromIntegral $ B.length srcBytes- , aiFortranVersion = fortranVersion }+ , aiFortranVersion = fortranVersion+ , aiPosition = initPosition {filePath = filename} } collectFixedTokens :: FortranVersion -> B.ByteString -> [Token] collectFixedTokens version srcInput =
src/Language/Fortran/Lexer/FreeForm.x view
@@ -10,8 +10,10 @@ module Language.Fortran.Lexer.FreeForm where +import Prelude hiding (span) import Data.Data import Data.Maybe (fromMaybe)+import Data.List (foldl') import Data.Char (toLower) import Data.Word (Word8) import qualified Data.ByteString.Char8 as B@@ -24,7 +26,7 @@ import Language.Fortran.ParserMonad import Language.Fortran.Util.Position import Language.Fortran.Util.FirstParameter-+import Language.Fortran.Parser.Utils (readInteger) } @@ -36,6 +38,8 @@ $letter = a-z $alphanumeric = [$letter $digit \_] +$hash = [\#]+ @label = $digit{1,5} @name = $letter $alphanumeric* @@ -77,8 +81,11 @@ -------------------------------------------------------------------------------- tokens :- +<0> "/*" { skipCComment } <0,scN> "!".*$ { adjustComment $ addSpanAndMatch TComment } +<0> $hash.*$ { lexHash }+ <0,scN,scT> (\n\r|\r\n|\n) { resetPar >> toSC 0 >> addSpan TNewline } <0,scN,scI,scT> [\t\ ]+ ; @@ -87,6 +94,8 @@ <scN> ")" { decPar >> addSpan TRightPar } <scN> "(/" / { notDefinedOperP } { addSpan TLeftInitPar } <scN> "/)" / { notDefinedOperP } { addSpan TRightInitPar }+<scN> "[" / { notDefinedOperP } { addSpan TLeftInitPar }+<scN> "]" / { notDefinedOperP } { addSpan TRightInitPar } <scN> "," { comma } <scN> ";" { resetPar >> toSC 0 >> addSpan TSemiColon } <scN> ":" { addSpan TColon }@@ -120,8 +129,12 @@ <0> "contains" { addSpan TContains } <0> "use" { addSpan TUse } <scN> "only" / { useStP } { addSpan TOnly }+<0> "import" { addSpan TImport }+<0> "abstract" { addSpan TAbstract } <0> "interface" { addSpan TInterface }+<scN> "interface" / { genericSpecP } { addSpan TInterface } <0> "end"\ *"interface" { addSpan TEndInterface }+<0> "procedure" { addSpan TProcedure } <0> "module"\ \ *"procedure" { addSpan TModuleProcedure } <scN> "assignment"\ *"("\ *"="\ *")" / { genericSpecP } { addSpan TAssignment } <scN> "operator" / { genericSpecP } { addSpan TOperator }@@ -132,16 +145,27 @@ -- Type def related <0,scT> "type" { addSpan TType }+<scN> "type" / { allocateP } { addSpan TType } <0> "end"\ *"type" { addSpan TEndType }+<scN> "class" / { followsProcedureP } { addSpan TClass } <0> "sequence" { addSpan TSequence }+<0> "enum" { addSpan TEnum }+<0> "end"\ *"enum" { addSpan TEndEnum }+<0> "enumerator" { addSpan TEnumerator } -- Intrinsic types <0,scT> "integer" { addSpan TInteger }+<scN> "integer" / { allocateP } { addSpan TInteger } <0,scT> "real" { addSpan TReal }+<scN> "real" / { allocateP } { addSpan TReal } <0,scT> "double"\ *"precision" { addSpan TDoublePrecision }+<scN> "double"\ *"precision" / { allocateP } { addSpan TDoublePrecision } <0,scT> "logical" { addSpan TLogical }+<scN> "logical" / { allocateP } { addSpan TLogical } <0,scT> "character" { addSpan TCharacter }+<scN> "character" / { allocateP } { addSpan TCharacter } <0,scT> "complex" { addSpan TComplex }+<scN> "complex" / { allocateP } { addSpan TComplex } <scN> "kind" / { selectorP } { addSpan TKind } <scN> "len" / { selectorP } { addSpan TLen }@@ -151,10 +175,14 @@ <scN> "public" / { attributeP } { addSpan TPublic } <0> "private" { addSpan TPrivate } <scN> "private" / { attributeP } { addSpan TPrivate }+<0> "protected" { addSpan TProtected }+<scN> "protected" / { attributeP } { addSpan TProtected } <0> "parameter" { addSpan TParameter } <scN> "parameter" / { attributeP } { addSpan TParameter } <0> "allocatable" { addSpan TAllocatable } <scN> "allocatable" / { attributeP } { addSpan TAllocatable }+<0> "asynchronous" { addSpan TAsynchronous }+<scN> "asynchronous" / { attributeP } { addSpan TAsynchronous } <0> "dimension" { addSpan TDimension } <scN> "dimension" / { attributeP } { addSpan TDimension } <0> "external" { addSpan TExternal }@@ -163,6 +191,8 @@ <scN> "intent" / { attributeP } { addSpan TIntent } <0> "intrinsic" { addSpan TIntrinsic } <scN> "intrinsic" / { attributeP } { addSpan TIntrinsic }+<0> "non_intrinsic" { addSpan TNonIntrinsic }+<scN> "non_intrinsic" / { attributeP } { addSpan TNonIntrinsic } <0> "optional" { addSpan TOptional } <scN> "optional" / { attributeP } { addSpan TOptional } <0> "pointer" { addSpan TPointer }@@ -171,12 +201,23 @@ <scN> "save" / { attributeP } { addSpan TSave } <0> "target" { addSpan TTarget } <scN> "target" / { attributeP } { addSpan TTarget }+<0> "save" { addSpan TSave }+<scN> "save" / { attributeP } { addSpan TSave }+<0> "value" { addSpan TValue }+<scN> "value" / { attributeP } { addSpan TValue }+<0> "volatile" { addSpan TVolatile }+<scN> "volatile" / { attributeP } { addSpan TVolatile } -- Attribute values <scN> "in"\ *"out" / { followsIntentP } { addSpan TInOut } <scN> "in" / { followsIntentP } { addSpan TIn } <scN> "out" / { followsIntentP } { addSpan TOut } +-- language-binding-spec+<scN> "bind" / { bindP } { addSpan TBind }+<scN> "name" / { followsCP } { addSpan TName }+<scN> "c" / { followsBindP } { addSpan TC }+ -- Control flow <0> "do" { addSpan TDo } <scN> "do" / { followsColonP } { addSpan TDo }@@ -207,12 +248,17 @@ -- Where construct <0,scI> "where" { addSpan TWhere }+<scN> "where" / { labelledWhereP } { addSpan TWhere } <0> "elsewhere" { addSpan TElsewhere }+<0> "else"\ *"where" { addSpan TElsewhere } <0> "end"\ *"where" { addSpan TEndWhere } -- Beginning keyword <0> "data" { addSpan TData } <0,scI> "allocate" { addSpan TAllocate }+<scN> "stat" / { allocateP } { addSpan TStat }+<scN> "errmsg" / { allocateP } { addSpan TErrMsg }+<scN> "source" / { allocateP } { addSpan TSource } <0,scI> "deallocate" { addSpan TDeallocate } <0,scI> "nullify" { addSpan TNullify } <0> "namelist" { addSpan TNamelist }@@ -233,6 +279,11 @@ <0,scI> "rewind" { addSpan TRewind } <0,scI> "inquire" { addSpan TInquire } <0,scI> "end"\ *"file" { addSpan TEndfile }+<0> "flush" { addSpan TFlush }+<scN> "unit" / { followsFlushP } { addSpan TUnit }+<scN> "iostat" / { followsFlushP } { addSpan TIOStat }+<scN> "iomsg" / { followsFlushP } { addSpan TIOMsg }+<scN> "err" / { followsFlushP } { addSpan TErr } -- Format <0> "format" { addSpan TFormat }@@ -293,6 +344,13 @@ | Just TColon{} <- aiPreviousToken ai = True | otherwise = False +labelledWhereP :: User -> AlexInput -> Int -> AlexInput -> Bool+labelledWhereP _ _ _ ai+ | TId{}:TColon{}:[] <- prevTokens = True+ | otherwise = False+ where+ prevTokens = reverse . aiPreviousTokensInLine $ ai+ selectorP :: User -> AlexInput -> Int -> AlexInput -> Bool selectorP user _ _ ai = followsType && nextTokenIsOpAssign && precedesDoubleColon ai@@ -324,7 +382,7 @@ partOfExpOrPointerAssignmentP :: User -> AlexInput -> Int -> AlexInput -> Bool partOfExpOrPointerAssignmentP (User fv pc) _ _ ai =- case unParse (lexer $ f False 0) ps of+ case unParse (lexer $ f False (0::Integer)) ps of ParseOk True _ -> True _ -> False where@@ -351,6 +409,8 @@ TOpAssign{} -> return True TArrow{} -> return True TPercent{} -> return True+ TLeftPar{} -> lexer $ f True 1+ TLeftPar2{} -> lexer $ f True 1 _ -> return False | parCount > 0 = case token of@@ -367,18 +427,88 @@ precedesDoubleColon :: AlexInput -> Bool precedesDoubleColon ai = not . flip seenConstr ai . fillConstr $ TDoubleColon +parenLevel :: [Token] -> Int+parenLevel = foldl' f 0+ where+ f n tok | fillConstr TLeftPar == toConstr tok = n + 1+ | fillConstr TRightPar == toConstr tok = n - 1+ | otherwise = n++allocateP :: User -> AlexInput -> Int -> AlexInput -> Bool+allocateP _ _ _ ai+ | alloc:lpar:rest <- prevTokens+ , toConstr alloc `elem` [fillConstr TAllocate, fillConstr TDeallocate]+ , fillConstr TLeftPar == toConstr lpar+ = null rest || (followsComma && parenLevel prevTokens == 1)+ | otherwise = False+ where+ prevTokens = reverse . aiPreviousTokensInLine $ ai+ followsComma+ | Just TComma{} <- aiPreviousToken ai = True+ | otherwise = False+ attributeP :: User -> AlexInput -> Int -> AlexInput -> Bool-attributeP _ _ _ ai = followsComma && precedesDoubleColon ai && startsWithTypeSpec+attributeP _ _ _ ai = followsComma && precedesDoubleColon ai && lineStartOK where followsComma | Just TComma{} <- aiPreviousToken ai = True | otherwise = False- startsWithTypeSpec- | (token:_) <- prevTokens =- isTypeSpec token || fillConstr TType == toConstr token++ lineStartOK+ -- matches e.g.: TYPE (FOO), ATTR+ | typ:lpar:_:rpar:com:_ <- prevTokens+ , toConstr typ `elem` [fillConstr TType, fillConstr TClass]+ , toConstr lpar == fillConstr TLeftPar+ , toConstr rpar == fillConstr TRightPar+ = fillConstr TComma == toConstr com++ -- matches e.g.: TYPE FOO, ATTR+ | typ:com:_ <- prevTokens+ , toConstr typ == fillConstr TType+ = fillConstr TComma == toConstr com++ -- matches e.g.: INTEGER (KIND=...), ATTR+ -- or: PROCEDURE (...), ATTR+ | tok:lpar:rest <- prevTokens+ , isTypeSpec tok || fillConstr TProcedure == toConstr tok+ , fillConstr TLeftPar == toConstr lpar+ , (_, _:com:_) <- break ((fillConstr TRightPar ==) . toConstr) rest+ = fillConstr TComma == toConstr com++ -- matches e.g.: INTEGER*NUM, ATTR+ | tok:star:num:com:_ <- prevTokens+ , isTypeSpec tok+ , fillConstr TStar == toConstr star+ , TIntegerLiteral{} <- num+ = fillConstr TComma == toConstr com++ -- matches e.g.: INTEGER, ATTR+ -- or: USE, ATTR+ | tok:com:_ <- prevTokens+ , isTypeSpec tok || fillConstr TUse == toConstr tok+ = fillConstr TComma == toConstr com+ | otherwise = False+ prevTokens = reverse . aiPreviousTokensInLine $ ai +bindP :: User -> AlexInput -> Int -> AlexInput -> Bool+bindP _ _ _ ai = (followsRightPar && isFunSub) || (followsComma && isProcEnum)+ where+ followsComma+ | Just TComma{} <- aiPreviousToken ai = True+ | otherwise = False+ followsRightPar+ | Just TRightPar{} <- aiPreviousToken ai = True+ | otherwise = False+ isFunSub = flip any prevTokens $ \ token ->+ fillConstr TFunction == toConstr token ||+ fillConstr TSubroutine == toConstr token+ isProcEnum = flip any prevTokens $ \ token ->+ fillConstr TProcedure == toConstr token ||+ fillConstr TEnum == toConstr token+ prevTokens = reverse . aiPreviousTokensInLine $ ai+ constructNameP :: User -> AlexInput -> Int -> AlexInput -> Bool constructNameP user _ _ ai = case nextTokenConstr user ai of@@ -388,10 +518,13 @@ genericSpecP :: User -> AlexInput -> Int -> AlexInput -> Bool genericSpecP _ _ _ ai = Just True == do constr <- prevTokenConstr ai- if constr `elem` fmap fillConstr [ TInterface, TPublic, TPrivate ]+ if constr `elem` fmap fillConstr [ TAbstract, TInterface, TPublic, TPrivate, TProtected ] then return True- else if constr `elem` fmap fillConstr [ TComma, TDoubleColon ]- then return $ seenConstr (fillConstr TPublic) ai || seenConstr (fillConstr TPrivate) ai+ else if constr `elem` fmap fillConstr [ TComma, TDoubleColon, TColon ]+ then return $ seenConstr (fillConstr TPublic) ai ||+ seenConstr (fillConstr TPrivate) ai ||+ seenConstr (fillConstr TProtected) ai ||+ seenConstr (fillConstr TOnly) ai else Nothing notDefinedOperP :: User -> AlexInput -> Int -> AlexInput -> Bool@@ -411,7 +544,7 @@ , isTypeSpec prevToken = True | otherwise = isTypeSpecImmediatelyBefore $ reverse prevTokens where- isTypeSpecImmediatelyBefore tokens@(x:xs)+ isTypeSpecImmediatelyBefore tokens@(_:xs) | isTypeSpec tokens = True | otherwise = isTypeSpecImmediatelyBefore xs isTypeSpecImmediatelyBefore [] = False@@ -431,6 +564,25 @@ (map toConstr . take 2 . aiPreviousTokensInLine) ai == map fillConstr [ TLeftPar, TIntent ] +followsProcedureP :: User -> AlexInput -> Int -> AlexInput -> Bool+followsProcedureP _ _ _ ai =+ (map toConstr . take 2 . aiPreviousTokensInLine) ai ==+ map fillConstr [ TLeftPar, TProcedure ]++followsBindP :: User -> AlexInput -> Int -> AlexInput -> Bool+followsBindP _ _ _ ai =+ (map toConstr . take 2 . aiPreviousTokensInLine) ai ==+ map fillConstr [ TLeftPar, TBind ]++followsCP :: User -> AlexInput -> Int -> AlexInput -> Bool+followsCP _ _ _ ai =+ (map toConstr . take 2 . aiPreviousTokensInLine) ai ==+ map fillConstr [ TComma, TC ]++followsFlushP :: User -> AlexInput -> Int -> AlexInput -> Bool+followsFlushP _ _ _ ai = not (null toks) && fillConstr TFlush == toConstr (last toks)+ where toks = aiPreviousTokensInLine ai+ useStP :: User -> AlexInput -> Int -> AlexInput -> Bool useStP _ _ _ ai = seenConstr (toConstr $ TUse undefined) ai @@ -484,7 +636,7 @@ ParseOk tokenCons _ -> do span <- getLexemeSpan return $ Just $ tokenCons span- ParseFailed e -> fail "Left parantheses is not matched."+ ParseFailed _ -> fail "Left parantheses is not matched." else addSpan TLeftPar where f :: LexAction (SrcSpan -> Token)@@ -493,7 +645,7 @@ mPrevToken <- aiPreviousToken <$> getAlex case mPrevToken of Just TRightPar{} | pc == 0 -> do- span <- getLexemeSpan+ _ <- getLexemeSpan curToken <- lexer' case curToken of TComma{} -> return TLeftPar2@@ -620,7 +772,7 @@ putAlex $ alex { aiStartCode = StartCode scC Stable } match <- getMatch let boundaryMarker = last match- _lexChar 0 boundaryMarker+ _lexChar (0::Integer) boundaryMarker where _lexChar 0 bm = do alex <- getAlex@@ -650,6 +802,7 @@ match <- getMatch putMatch . init . tail $ match addSpanAndMatch TString+ _lexChar _ _ = do fail "unhandled lexCharacter" toSC :: Int -> LexAction () toSC startCode = do@@ -675,7 +828,7 @@ -------------------------------------------------------------------------------- invalidPosition :: Position-invalidPosition = Position 0 0 0+invalidPosition = Position 0 0 0 "" Nothing {-# INLINE isValidPosition #-} isValidPosition :: Position -> Bool@@ -774,8 +927,10 @@ currentChar :: AlexInput -> Char currentChar !ai -- case sensitivity matters only in character literals- | sCode == scC = _currentChar- | otherwise = {-# SCC toLower_currentChar #-} toLower _currentChar+ | sCode == scC = _currentChar+ | 'A' <= _currentChar &&+ _currentChar <= 'Z' = {-# SCC toLower_currentChar #-} toLower _currentChar+ | otherwise = _currentChar where sCode = scActual (aiStartCode ai) -- _currentChar = w2c (BU.unsafeIndex srcBytes i)@@ -806,26 +961,27 @@ (scActual . aiStartCode) ai /= scC -- No continuation while lexing a comment. && (null match || not (lexemeIsCmt lexeme))- && _isContinuation ai 0+ && _isContinuation ai (0::Integer) where match = lexemeMatch lexeme lexeme = aiLexeme $ ai- _isContinuation !ai 0 =- if currentChar ai == '&'- then _advance ai+ _isContinuation !ai' 0 =+ if currentChar ai' == '&'+ then _advance ai' else False- _isContinuation !ai 1 =- case currentChar ai of- ' ' -> _advance ai- '\t' -> _advance ai- '\r' -> _advance ai+ _isContinuation !ai' 1 =+ case currentChar ai' of+ ' ' -> _advance ai'+ '\t' -> _advance ai'+ '\r' -> _advance ai' '!' -> True '\n' -> True _ -> False+ _isContinuation _ _ = False _advance :: AlexInput -> Bool- _advance !ai =- case advanceWithoutContinuation ai of- Just ai' -> _isContinuation ai' 1+ _advance !ai' =+ case advanceWithoutContinuation ai' of+ Just ai'' -> _isContinuation ai'' (1::Integer) Nothing -> False -- Here's the skip continuation automaton:@@ -850,7 +1006,7 @@ -- This version is more permissive than the specification -- as it allows empty lines to be used between continuations. skipContinuation :: AlexInput -> AlexInput-skipContinuation ai = _skipCont ai 0+skipContinuation ai' = _skipCont ai' (0::Integer) where _skipCont ai 0 = if currentChar ai == '&'@@ -888,11 +1044,24 @@ -- previous ai, which either has whitespace or newline, so it will -- nicely delimit. else ai+ _skipCont _ _ = error "unhandled _skipCont in skipContinuation" _advance ai state = case advanceWithoutContinuation ai of- Just ai' -> _skipCont ai' state+ Just ai'' -> _skipCont ai'' state Nothing -> error "File has ended prematurely during a continuation." +-- skip a C comment (read until first "*/")+skipCComment :: LexAction (Maybe Token)+skipCComment = do+ let loop (Just ai) 0 | currentChar ai == '*' = loop (advanceWithoutContinuation ai) 1+ | otherwise = loop (advanceWithoutContinuation ai) 0+ loop (Just ai) 1 | currentChar ai == '/' = ai `fromMaybe` advanceWithoutContinuation ai+ | otherwise = loop (advanceWithoutContinuation ai) 0+ loop _ _ = error "File has ended prematurely during a C comment."+ ai <- getAlex+ putAlex $ loop (Just ai) (0 :: Int)+ return Nothing+ advance :: Move -> Position -> Position advance move position = case move of@@ -901,11 +1070,31 @@ { posAbsoluteOffset = _absl + 1 , posColumn = 1 , posLine = _line + 1 } Char -> position { posAbsoluteOffset = _absl + 1 , posColumn = _col + 1 }+-- for now just return the original position+ _ -> position { posAbsoluteOffset = _absl, posColumn = _col } where _col = posColumn position _line = posLine position _absl = posAbsoluteOffset position +-- Handle pragmas that begin with #+lexHash :: LexAction (Maybe Token)+lexHash = do+ ai <- getAlex+ m <- getMatch+ case words (drop 1 m) of+ -- 'line' pragma - rewrite the current line and filename+ "line":lineStr:_+ | Just line <- readInteger lineStr -> do+ let revdropWNQ = reverse . drop 1 . dropWhile (flip notElem "'\"")+ let file = revdropWNQ . revdropWNQ $ m+ let lineOffs = fromIntegral line - posLine (aiPosition ai) - 1+ let newP = (aiPosition ai) { posPragmaOffset = Just (lineOffs, file)+ , posColumn = 1 }+ putAlex $ ai { aiPosition = newP }+ _ -> return ()+ return Nothing+ -------------------------------------------------------------------------------- -- Lexer definition --------------------------------------------------------------------------------@@ -919,11 +1108,11 @@ alex <- getAlex let startCode = scActual . aiStartCode $ alex normaliseStartCode- newAlex <- getAlex+ newAlex' <- getAlex version <- getVersion paranthesesCount <- getParanthesesCount let user = User version paranthesesCount- case alexScanUser user newAlex startCode of+ case alexScanUser user newAlex' startCode of AlexEOF -> return $ TEOF $ SrcSpan (getPos alex) (getPos alex) AlexError _ -> do parseState <- get@@ -997,7 +1186,7 @@ | TFunction SrcSpan | TEndFunction SrcSpan | TResult SrcSpan- | TPure SrcSpan+ | TPure SrcSpan | TElemental SrcSpan | TRecursive SrcSpan | TSubroutine SrcSpan@@ -1009,8 +1198,11 @@ | TContains SrcSpan | TUse SrcSpan | TOnly SrcSpan+ | TImport SrcSpan+ | TAbstract SrcSpan | TInterface SrcSpan | TEndInterface SrcSpan+ | TProcedure SrcSpan | TModuleProcedure SrcSpan | TAssignment SrcSpan | TOperator SrcSpan@@ -1018,19 +1210,28 @@ | TReturn SrcSpan | TEntry SrcSpan | TInclude SrcSpan+ -- language-binding-spec+ | TBind SrcSpan+ | TC SrcSpan+ | TName SrcSpan -- Attributes- | TPublic SrcSpan- | TPrivate SrcSpan- | TParameter SrcSpan | TAllocatable SrcSpan+ | TAsynchronous SrcSpan | TDimension SrcSpan | TExternal SrcSpan | TIntent SrcSpan | TIntrinsic SrcSpan+ | TNonIntrinsic SrcSpan | TOptional SrcSpan+ | TParameter SrcSpan | TPointer SrcSpan+ | TPrivate SrcSpan+ | TPublic SrcSpan+ | TProtected SrcSpan | TSave SrcSpan | TTarget SrcSpan+ | TValue SrcSpan+ | TVolatile SrcSpan -- Attribute values | TIn SrcSpan | TOut SrcSpan@@ -1044,6 +1245,9 @@ | TFormat SrcSpan | TBlob SrcSpan String | TAllocate SrcSpan+ | TStat SrcSpan+ | TErrMsg SrcSpan+ | TSource SrcSpan | TDeallocate SrcSpan | TNullify SrcSpan -- Misc@@ -1079,6 +1283,10 @@ | TType SrcSpan | TEndType SrcSpan | TSequence SrcSpan+ | TClass SrcSpan+ | TEnum SrcSpan+ | TEnumerator SrcSpan+ | TEndEnum SrcSpan -- Selector | TKind SrcSpan | TLen SrcSpan@@ -1103,6 +1311,11 @@ | TEnd SrcSpan | TNewline SrcSpan | TEOF SrcSpan+ | TFlush SrcSpan+ | TUnit SrcSpan+ | TIOStat SrcSpan+ | TIOMsg SrcSpan+ | TErr SrcSpan deriving (Eq, Show, Data, Typeable, Generic) instance FirstParameter Token SrcSpan@@ -1158,7 +1371,8 @@ , psContext = [ ConStart ] } _vanillaAlexInput = vanillaAlexInput { aiSourceBytes = srcBytes- , aiEndOffset = B.length srcBytes }+ , aiEndOffset = B.length srcBytes+ , aiPosition = initPosition {filePath = filename} } collectFreeTokens :: FortranVersion -> B.ByteString -> [Token] collectFreeTokens version srcInput =
src/Language/Fortran/Parser/Any.hs view
@@ -10,6 +10,7 @@ , legacy77Parser, legacy77ParserWithModFiles ) import Language.Fortran.Parser.Fortran90 ( fortran90Parser, fortran90ParserWithModFiles ) import Language.Fortran.Parser.Fortran95 ( fortran95Parser, fortran95ParserWithModFiles )+import Language.Fortran.Parser.Fortran2003 ( fortran2003Parser, fortran2003ParserWithModFiles ) import qualified Data.ByteString.Char8 as B import Data.Char (toLower)@@ -39,7 +40,8 @@ , (Fortran77Extended, fromParseResult `after` extended77Parser) , (Fortran77Legacy, fromParseResult `after` legacy77Parser) , (Fortran90, fromParseResult `after` fortran90Parser)- , (Fortran95, fromParseResult `after` fortran95Parser) ]+ , (Fortran95, fromParseResult `after` fortran95Parser)+ , (Fortran2003, fromParseResult `after` fortran2003Parser) ] type ParserWithModFiles = ModFiles -> B.ByteString -> String -> Either ParseErrorSimple (ProgramFile A0) parserWithModFilesVersions :: [(FortranVersion, ParserWithModFiles)]@@ -49,9 +51,11 @@ , (Fortran77Extended, \m s -> fromParseResult . extended77ParserWithModFiles m s) , (Fortran77Legacy, \m s -> fromParseResult . legacy77ParserWithModFiles m s) , (Fortran90, \m s -> fromParseResult . fortran90ParserWithModFiles m s)- , (Fortran95, \m s -> fromParseResult . fortran95ParserWithModFiles m s) ]+ , (Fortran95, \m s -> fromParseResult . fortran95ParserWithModFiles m s)+ , (Fortran2003, \m s -> fromParseResult . fortran2003ParserWithModFiles m s) ] -after g f x = g . (f x)+after :: (b -> c) -> (t -> a -> b) -> t -> a -> c+after g f x = g . f x -- | Deduce the type of parser from the filename and parse the -- contents of the file.@@ -65,4 +69,17 @@ fortranParserWithModFiles :: ParserWithModFiles fortranParserWithModFiles mods contents filename = do let Just parserF = lookup (deduceVersion filename) parserWithModFilesVersions+ parserF mods contents filename++-- | Given a FortranVersion, parse the contents of the file.+fortranParserWithVersion :: FortranVersion -> Parser+fortranParserWithVersion v contents filename = do+ let Just parserF = lookup v parserVersions+ parserF contents filename++-- | Given a FortranVersion, parse the contents of the file, within+-- the context of given "mod files".+fortranParserWithModFilesAndVersion :: FortranVersion -> ParserWithModFiles+fortranParserWithModFilesAndVersion v mods contents filename = do+ let Just parserF = lookup v parserWithModFilesVersions parserF mods contents filename
+ src/Language/Fortran/Parser/Fortran2003.y view
@@ -0,0 +1,1328 @@+-- -*- Mode: Haskell -*-+{+-- Incomplete work-in-progress.+module Language.Fortran.Parser.Fortran2003 ( functionParser+ , statementParser+ , fortran2003Parser+ , fortran2003ParserWithModFiles+ ) where++import Prelude hiding (EQ,LT,GT) -- Same constructors exist in the AST+import Control.Monad.State+import Data.Maybe (fromMaybe, isJust)+import Data.List (nub)+import Data.Either (either, lefts, rights, partitionEithers)+import Control.Applicative+import qualified Data.ByteString.Char8 as B++#ifdef DEBUG+import Data.Data (toConstr)+#endif++import Language.Fortran.Util.Position+import Language.Fortran.Util.ModFile+import Language.Fortran.ParserMonad+import Language.Fortran.Lexer.FreeForm+import Language.Fortran.AST+import Language.Fortran.Transformer++import Debug.Trace++}++%name programParser PROGRAM+%name statementParser STATEMENT+%name functionParser SUBPROGRAM_UNIT+%monad { LexAction }+%lexer { lexer } { TEOF _ }+%tokentype { Token }+%error { parseError }++%token+ id { TId _ _ }+ comment { TComment _ _ }+ string { TString _ _ }+ int { TIntegerLiteral _ _ }+ float { TRealLiteral _ _ }+ boz { TBozLiteral _ _ }+ ',' { TComma _ }+ ',2' { TComma2 _ }+ ';' { TSemiColon _ }+ ':' { TColon _ }+ '::' { TDoubleColon _ }+ '=' { TOpAssign _ }+ '=>' { TArrow _ }+ '%' { TPercent _ }+ '(' { TLeftPar _ }+ '(2' { TLeftPar2 _ }+ ')' { TRightPar _ }+ '(/' { TLeftInitPar _ }+ '/)' { TRightInitPar _ }+ opCustom { TOpCustom _ _ }+ '**' { TOpExp _ }+ '+' { TOpPlus _ }+ '-' { TOpMinus _ }+ '*' { TStar _ }+ '/' { TOpDivision _ }+ slash { TSlash _ }+ or { TOpOr _ }+ and { TOpAnd _ }+ not { TOpNot _ }+ eqv { TOpEquivalent _ }+ neqv { TOpNotEquivalent _ }+ '<' { TOpLT _ }+ '<=' { TOpLE _ }+ '==' { TOpEQ _ }+ '!=' { TOpNE _ }+ '>' { TOpGT _ }+ '>=' { TOpGE _ }+ bool { TLogicalLiteral _ _ }+ program { TProgram _ }+ endProgram { TEndProgram _ }+ function { TFunction _ }+ endFunction { TEndFunction _ }+ result { TResult _ }+ pure { TPure _ }+ elemental { TElemental _ }+ recursive { TRecursive _ }+ subroutine { TSubroutine _ }+ endSubroutine { TEndSubroutine _ }+ blockData { TBlockData _ }+ endBlockData { TEndBlockData _ }+ module { TModule _ }+ endModule { TEndModule _ }+ contains { TContains _ }+ use { TUse _ }+ only { TOnly _ }+ import { TImport _ }+ abstract { TAbstract _ }+ interface { TInterface _ }+ endInterface { TEndInterface _ }+ moduleProcedure { TModuleProcedure _ }+ procedure { TProcedure _ }+ assignment { TAssignment _ }+ operator { TOperator _ }+ call { TCall _ }+ return { TReturn _ }+ entry { TEntry _ }+ include { TInclude _ }+ public { TPublic _ }+ private { TPrivate _ }+ protected { TProtected _ }+ parameter { TParameter _ }+ allocatable { TAllocatable _ }+ asynchronous { TAsynchronous _ }+ dimension { TDimension _ }+ external { TExternal _ }+ intent { TIntent _ }+ intrinsic { TIntrinsic _ }+ nonintrinsic { TNonIntrinsic _ }+ optional { TOptional _ }+ pointer { TPointer _ }+ save { TSave _ }+ target { TTarget _ }+ value { TValue _ }+ volatile { TVolatile _ }+ bind { TBind _ }+ 'c' { TC _ }+ name { TName _ }+ in { TIn _ }+ out { TOut _ }+ inout { TInOut _ }+ data { TData _ }+ namelist { TNamelist _ }+ implicit { TImplicit _ }+ equivalence { TEquivalence _ }+ common { TCommon _ }+ allocate { TAllocate _ }+ deallocate { TDeallocate _ }+ stat { TStat _ }+ errmsg { TErrMsg _ }+ source { TSource _ }+ nullify { TNullify _ }+ none { TNone _ }+ goto { TGoto _ }+ to { TTo _ }+ continue { TContinue _ }+ stop { TStop _ }+ do { TDo _ }+ enddo { TEndDo _ }+ while { TWhile _ }+ if { TIf _ }+ then { TThen _ }+ else { TElse _ }+ elsif { TElsif _ }+ endif { TEndIf _ }+ case { TCase _ }+ selectcase { TSelectCase _ }+ endselect { TEndSelect _ }+ default { TDefault _ }+ cycle { TCycle _ }+ exit { TExit _ }+ where { TWhere _ }+ elsewhere { TElsewhere _ }+ endwhere { TEndWhere _ }+ type { TType _ }+ endType { TEndType _ }+ class { TClass _ }+ enum { TEnum _ }+ enumerator { TEnumerator _ }+ endEnum { TEndEnum _ }+ sequence { TSequence _ }+ kind { TKind _ }+ len { TLen _ }+ integer { TInteger _ }+ real { TReal _ }+ doublePrecision { TDoublePrecision _ }+ logical { TLogical _ }+ character { TCharacter _ }+ complex { TComplex _ }+ open { TOpen _ }+ close { TClose _ }+ read { TRead _ }+ write { TWrite _ }+ print { TPrint _ }+ flush { TFlush _ }+ unit { TUnit _ }+ iostat { TIOStat _ }+ iomsg { TIOMsg _ }+ err { TErr _ }+ backspace { TBackspace _ }+ rewind { TRewind _ }+ inquire { TInquire _ }+ endfile { TEndfile _ }+ format { TFormat _ }+ blob { TBlob _ _ }+ end { TEnd _ }+ newline { TNewline _ }+ forall { TForall _ }+ endforall { TEndForall _ }+-- Precedence of operators++-- Level 6+%left opCustom++-- Level 5+%left eqv neqv+%left or+%left and+%right not++-- Level 4+%nonassoc '==' '!=' '>' '<' '>=' '<='+%nonassoc RELATIONAL++-- Level 3+%left CONCAT++-- Level 2+%left '+' '-'+%left '*' '/'+%right SIGN+%right '**'++-- Level 1+%right DEFINED_UNARY++-- Level 0+%left '%'++%%++-- This rule is to ignore leading whitespace+PROGRAM :: { ProgramFile A0 }+: NEWLINE PROGRAM_INNER { $2 }+| PROGRAM_INNER { $1 }++PROGRAM_INNER :: { ProgramFile A0 }+: PROGRAM_UNITS { ProgramFile (MetaInfo { miVersion = Fortran2003, miFilename = "" }) (reverse $1) }++PROGRAM_UNITS :: { [ ProgramUnit A0 ] }+: PROGRAM_UNITS PROGRAM_UNIT MAYBE_NEWLINE { $2 : $1 }+| PROGRAM_UNIT MAYBE_NEWLINE { [ $1 ] }++PROGRAM_UNIT :: { ProgramUnit A0 }+: program NAME NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS PROGRAM_END+ {% do { unitNameCheck $6 $2;+ return $ PUMain () (getTransSpan $1 $6) (Just $2) (reverse $4) $5 } }+| module NAME NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS MODULE_END+ {% do { unitNameCheck $6 $2;+ return $ PUModule () (getTransSpan $1 $6) $2 (reverse $4) $5 } }+| blockData NEWLINE BLOCKS BLOCK_DATA_END+ { PUBlockData () (getTransSpan $1 $4) Nothing (reverse $3) }+| blockData NAME NEWLINE BLOCKS BLOCK_DATA_END+ {% do { unitNameCheck $5 $2;+ return $ PUBlockData () (getTransSpan $1 $5) (Just $2) (reverse $4) } }+| SUBPROGRAM_UNIT { $1 }++MAYBE_SUBPROGRAM_UNITS :: { Maybe [ ProgramUnit A0 ] }+: contains NEWLINE SUBPROGRAM_UNITS { Just $ reverse $3 }+| {- Empty -} { Nothing }++SUBPROGRAM_UNITS :: { [ ProgramUnit A0 ] }+: SUBPROGRAM_UNITS SUBPROGRAM_UNIT NEWLINE { $2 : $1 }+| {- EMPTY -} { [ ] }++SUBPROGRAM_UNIT :: { ProgramUnit A0 }+: PREFIXES function NAME MAYBE_ARGUMENTS FUNC_SUFFIX MAYBE_COMMENT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS FUNCTION_END+ {% do { unitNameCheck $10 $3;+ let (pfxs, typeSpec) = case partitionEithers $1 of+ { (ps, t:_) -> (fromReverseList' ps, Just t)+ ; (ps, []) -> (fromReverseList' ps, Nothing) } in+ let (sfx, result) = $5 in+ let sfx' = fmap (\ s -> AList () (getSpan s) [s]) sfx in+ let ss = if null $1 then getTransSpan $2 $10 else getTransSpan (reverse $1) $10 in+ if validPrefixSuffix (pfxs, sfx') then+ return $ PUFunction () ss typeSpec (pfxs, sfx') $3 $4 result (reverse $8) $9+ else fail "Cannot specify elemental along with recursive and/or bind." } }+| PREFIXES subroutine NAME MAYBE_ARGUMENTS SUBR_SUFFIX MAYBE_COMMENT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS SUBROUTINE_END+ {% do { unitNameCheck $10 $3;+ (pfxs, typeSpec) <- case partitionEithers $1 of+ { (ps, t:_) -> fail "Subroutines cannot have return types."+ ; (ps, []) -> return (fromReverseList' ps, Nothing) };+ let sfx' = fmap (\ s -> AList () (getSpan s) [s]) $5 in+ let ss = if null $1 then getTransSpan $2 $10 else getTransSpan (reverse $1) $10 in+ if validPrefixSuffix (pfxs, sfx') then+ return $ PUSubroutine () ss (pfxs, sfx') $3 $4 (reverse $8) $9+ else fail "Cannot specify elemental along with recursive and/or bind." } }+| comment { let (TComment s c) = $1 in PUComment () s (Comment c) }++-- (Fortran2003) R1227, Fortran95 (...)+PREFIXES :: { [Either (Prefix A0) (TypeSpec A0)] }+: PREFIXES PREFIX { $2:$1 }+| {- EMPTY -} { [] }++-- (Fortran2003) R1228, Fortran95 (...)+PREFIX :: { Either (Prefix A0) (TypeSpec A0) }+: recursive { Left $ PfxRecursive () (getSpan $1) }+| elemental { Left $ PfxElemental () (getSpan $1) }+| pure { Left $ PfxPure () (getSpan $1) }+| TYPE_SPEC { Right $1 }++FUNC_SUFFIX :: { (Maybe (Suffix A0), Maybe (Expression A0)) }+: SUFFIX RESULT { (Just $1, Just $2) }+| RESULT SUFFIX { (Just $2, Just $1) }+| SUFFIX { (Just $1, Nothing) }+| RESULT { (Nothing, Just $1) }+| {- empty -} { (Nothing, Nothing) }++SUBR_SUFFIX :: { Maybe (Suffix A0) }+: SUFFIX { Just $1 }+| {- empty -} { Nothing }++-- (Fortran2003) R1229+SUFFIX :: { Suffix A0 }+-- (Fortran2003) R509+: bind '(' 'c' ',' name '=' EXPRESSION ')' { SfxBind () (getTransSpan $1 $8) (Just $7) }+| bind '(' 'c' ')' { SfxBind () (getTransSpan $1 $4) Nothing }++MAYBE_ARGUMENTS :: { Maybe (AList Expression A0) }+: '(' MAYBE_VARIABLES ')' { $2 }+| {- Nothing -} { Nothing }++RESULT :: { Expression A0 }+: result '(' VARIABLE ')' { $3 }++MAYBE_RESULT :: { Maybe (Expression A0) }+: RESULT { Just $1 }+| {- empty -} { Nothing}++PROGRAM_END :: { Token }+: end { $1 } | endProgram { $1 } | endProgram id { $2 }+MODULE_END :: { Token }+: end { $1 } | endModule { $1 } | endModule id { $2 }+FUNCTION_END :: { Token }+: end { $1 } | endFunction { $1 } | endFunction id { $2 }+SUBROUTINE_END :: { Token }+: end { $1 } | endSubroutine { $1 } | endSubroutine id { $2 }+BLOCK_DATA_END :: { Token }+: end { $1 } | endBlockData { $1 } | endBlockData id { $2 }+INTERFACE_END :: { Token }+: end { $1 } | endInterface { $1 } | endInterface id { $2 }++NAME :: { Name } : id { let (TId _ name) = $1 in name }++IMPORT_NAME_LIST :: { [Expression A0] }+: IMPORT_NAME_LIST ',' VARIABLE { $3:$1 }+| VARIABLE { [$1] }++BLOCKS :: { [ Block A0 ] } : BLOCKS BLOCK { $2 : $1 } | {- EMPTY -} { [ ] }++BLOCK :: { Block A0 }+: INTEGER_LITERAL STATEMENT MAYBE_COMMENT NEWLINE+ { BlStatement () (getTransSpan $1 $2) (Just $1) $2 }+| STATEMENT MAYBE_COMMENT NEWLINE { BlStatement () (getSpan $1) Nothing $1 }+| ABSTRACTP interface MAYBE_EXPRESSION MAYBE_COMMENT NEWLINE SUBPROGRAM_UNITS2 MODULE_PROCEDURES INTERFACE_END MAYBE_COMMENT NEWLINE+ { BlInterface () (getTransSpan $2 $10) $3 $1 (reverse $6) (reverse $7) }+| ABSTRACTP interface MAYBE_EXPRESSION MAYBE_COMMENT NEWLINE MODULE_PROCEDURES INTERFACE_END MAYBE_COMMENT NEWLINE+ { BlInterface () (getTransSpan $2 $9) $3 $1 [ ] (reverse $6) }+| COMMENT_BLOCK { $1 }++ABSTRACTP :: { Bool }+: abstract { True }+| {- EMPTY -} { False }++MAYBE_EXPRESSION :: { Maybe (Expression A0) }+: EXPRESSION { Just $1 }+| {- EMPTY -} { Nothing }++MAYBE_COMMENT :: { Maybe Token }+: comment { Just $1 }+| {- EMPTY -} { Nothing }++SUBPROGRAM_UNITS2 :: { [ ProgramUnit A0 ] }+: SUBPROGRAM_UNITS SUBPROGRAM_UNIT NEWLINE { $2 : $1 }++MODULE_PROCEDURES :: { [ Block A0 ] }+: MODULE_PROCEDURES MODULE_PROCEDURE { $2 : $1 }+| MODULE_PROCEDURES MODULE_PROCEDURE COMMENT_BLOCK { $3 : $2 : $1 }+| { [ ] }++MODULE_PROCEDURE :: { Block A0 }+: moduleProcedure VARIABLES MAYBE_COMMENT NEWLINE+ { let { al = fromReverseList $2;+ st = StModuleProcedure () (getTransSpan $1 al) (fromReverseList $2) }+ in BlStatement () (getTransSpan $1 $4) Nothing st }++COMMENT_BLOCK :: { Block A0 }+: comment NEWLINE { let (TComment s c) = $1 in BlComment () s (Comment c) }++MAYBE_NEWLINE :: { Maybe Token } : NEWLINE { Just $1 } | {- EMPTY -} { Nothing }++NEWLINE :: { Token }+: NEWLINE newline { $1 }+| NEWLINE ';' { $1 }+| newline { $1 }+| ';' { $1 }++STATEMENT :: { Statement A0 }+: NONEXECUTABLE_STATEMENT { $1 }+| EXECUTABLE_STATEMENT { $1 }++EXPRESSION_ASSIGNMENT_STATEMENT :: { Statement A0 }+: DATA_REF '=' EXPRESSION { StExpressionAssign () (getTransSpan $1 $3) $1 $3 }++NONEXECUTABLE_STATEMENT :: { Statement A0 }+: DECLARATION_STATEMENT { $1 }+| intent '(' INTENT_CHOICE ')' MAYBE_DCOLON EXPRESSION_LIST+ { let expAList = fromReverseList $6+ in StIntent () (getTransSpan $1 expAList) $3 expAList }+| optional MAYBE_DCOLON EXPRESSION_LIST+ { let expAList = fromReverseList $3+ in StOptional () (getTransSpan $1 expAList) expAList }+| public MAYBE_DCOLON EXPRESSION_LIST+ { let expAList = fromReverseList $3+ in StPublic () (getTransSpan $1 expAList) (Just expAList) }+| public { StPublic () (getSpan $1) Nothing }+| private MAYBE_DCOLON EXPRESSION_LIST+ { let expAList = fromReverseList $3+ in StPrivate () (getTransSpan $1 expAList) (Just expAList) }+| private { StPrivate () (getSpan $1) Nothing }+| protected MAYBE_DCOLON EXPRESSION_LIST+ { let expAList = fromReverseList $3+ in StProtected () (getTransSpan $1 expAList) (Just expAList) }+| protected { StProtected () (getSpan $1) Nothing }+| save MAYBE_DCOLON SAVE_ARGS+ { let saveAList = (fromReverseList $3)+ in StSave () (getTransSpan $1 saveAList) (Just saveAList) }+| save { StSave () (getSpan $1) Nothing }+| procedure '(' MAYBE_PROC_INTERFACE ')' ',' ATTRIBUTE_SPEC '::' PROC_DECLS+ { let declAList = fromReverseList $8+ in StProcedure () (getTransSpan $1 $8) $3 (Just $6) declAList }+| procedure '(' MAYBE_PROC_INTERFACE ')' MAYBE_DCOLON PROC_DECLS+ { let declAList = fromReverseList $6+ in StProcedure () (getTransSpan $1 $6) $3 Nothing declAList }+| dimension MAYBE_DCOLON DECLARATOR_LIST+ { let declAList = fromReverseList $3+ in StDimension () (getTransSpan $1 declAList) declAList }+| allocatable MAYBE_DCOLON DECLARATOR_LIST+ { let declAList = fromReverseList $3+ in StAllocatable () (getTransSpan $1 declAList) declAList }+| asynchronous MAYBE_DCOLON DECLARATOR_LIST+ { let declAList = fromReverseList $3+ in StAsynchronous () (getTransSpan $1 declAList) declAList }+| pointer MAYBE_DCOLON DECLARATOR_LIST+ { let declAList = fromReverseList $3+ in StPointer () (getTransSpan $1 declAList) declAList }+| target MAYBE_DCOLON DECLARATOR_LIST+ { let declAList = fromReverseList $3+ in StTarget () (getTransSpan $1 declAList) declAList }+| value MAYBE_DCOLON DECLARATOR_LIST+ { let declAList = fromReverseList $3+ in StValue () (getTransSpan $1 declAList) declAList }+| volatile MAYBE_DCOLON DECLARATOR_LIST+ { let declAList = fromReverseList $3+ in StVolatile () (getTransSpan $1 declAList) declAList }+| data cDATA DATA_GROUPS cPOP+ { let dataAList = fromReverseList $3+ in StData () (getTransSpan $1 dataAList) dataAList }+| parameter '(' PARAMETER_ASSIGNMENTS ')'+ { let declAList = fromReverseList $3+ in StParameter () (getTransSpan $1 $4) declAList }+| implicit none { StImplicit () (getTransSpan $1 $2) Nothing }+| implicit cIMPLICIT IMP_LISTS cPOP+ { let impAList = fromReverseList $3+ in StImplicit () (getTransSpan $1 impAList) $ Just $ impAList }+| namelist cNAMELIST NAMELISTS cPOP+ { let nameALists = fromReverseList $3+ in StNamelist () (getTransSpan $1 nameALists) nameALists }+| equivalence EQUIVALENCE_GROUPS+ { let eqALists = fromReverseList $2+ in StEquivalence () (getTransSpan $1 eqALists) eqALists }+| common cCOMMON COMMON_GROUPS cPOP+ { let commonAList = fromReverseList $3+ in StCommon () (getTransSpan $1 commonAList) commonAList }+| external MAYBE_DCOLON VARIABLES+ { let alist = fromReverseList $3+ in StExternal () (getTransSpan $1 alist) alist }+| intrinsic MAYBE_DCOLON VARIABLES+ { let alist = fromReverseList $3+ in StIntrinsic () (getTransSpan $1 alist) alist }+| use MODULE_NATURE VARIABLE { StUse () (getTransSpan $1 $3) $3 $2 Permissive Nothing }+| use MODULE_NATURE VARIABLE ',' RENAME_LIST+ { let alist = fromReverseList $5+ in StUse () (getTransSpan $1 alist) $3 $2 Permissive (Just alist) }+| use MODULE_NATURE VARIABLE ',' only ':' MAYBE_RENAME_LIST+ { StUse () (getTransSpan $1 ($6, $7)) $3 $2 Exclusive $7 }+| entry VARIABLE MAYBE_RESULT+ { StEntry () (getTransSpan $1 $ maybe (getSpan $2) getSpan $3) $2 Nothing $3 }+| entry VARIABLE '(' ')' MAYBE_RESULT+ { StEntry () (getTransSpan $1 $ maybe (getSpan $4) getSpan $5) $2 Nothing $5 }+| entry VARIABLE '(' VARIABLES ')' MAYBE_RESULT+ { StEntry () (getTransSpan $1 $ maybe (getSpan $5) getSpan $6) $2 (Just $ fromReverseList $4) $6 }+| sequence { StSequence () (getSpan $1) }+| type ATTRIBUTE_LIST '::' id+ { let { TId span id = $4;+ alist = if null $2 then Nothing else (Just . fromReverseList) $2 }+ in StType () (getTransSpan $1 span) alist id }+| type id+ { let TId span id = $2 in StType () (getTransSpan $1 span) Nothing id }+| endType { StEndType () (getSpan $1) Nothing }+| endType id+ { let TId span id = $2 in StEndType () (getTransSpan $1 span) (Just id) }+-- R461-R464+| enum ',' bind '(' 'c' ')' { StEnum () (getTransSpan $1 $6) }+| enumerator MAYBE_DCOLON ENUMERATOR_LIST { StEnumerator () (getTransSpan $1 $3) (fromReverseList $3) }+| endEnum { StEndEnum () (getSpan $1) }+| include STRING { StInclude () (getTransSpan $1 $2) $2 Nothing }+-- R1209+| import '::' IMPORT_NAME_LIST { StImport () (getTransSpan $1 $3) (fromReverseList $3) }+| import IMPORT_NAME_LIST { StImport () (getTransSpan $1 $2) (fromReverseList $2) }+-- Following is a fake node to make arbitrary FORMAT statements parsable.+-- Must be fixed in the future. TODO+| format blob+ { let TBlob s blob = $2 in StFormatBogus () (getTransSpan $1 s) blob }++ENUMERATOR_LIST :: { [Declarator A0] }+: ENUMERATOR_LIST ',' ENUMERATOR { $3:$1 }+| ENUMERATOR { [$1] }++-- R463+ENUMERATOR :: { Declarator A0 }+: VARIABLE '=' EXPRESSION { DeclVariable () (getTransSpan $1 $3) $1 Nothing (Just $3) }+| VARIABLE { DeclVariable () (getSpan $1) $1 Nothing Nothing }++MAYBE_PROC_INTERFACE :: { Maybe (ProcInterface A0) }+: TYPE_SPEC { Just $ ProcInterfaceType () (getSpan $1) $1 }+| VARIABLE { Just $ ProcInterfaceName () (getSpan $1) $1 }+| {- EMPTY -} { Nothing }++PROC_DECLS :: { [ProcDecl A0] }+: PROC_DECLS ',' PROC_DECL { $3 : $1 }+| PROC_DECL { [ $1 ] }++PROC_DECL :: { ProcDecl A0 }+: VARIABLE '=>' EXPRESSION { ProcDecl () (getTransSpan $1 $3) $1 (Just $3) }+| VARIABLE { ProcDecl () (getSpan $1) $1 Nothing }++MODULE_NATURE :: { Maybe ModuleNature }+: ',' intrinsic '::' { Just ModIntrinsic }+| ',' nonintrinsic '::' { Just ModNonIntrinsic }+| '::' { Nothing }+| {- empty -} { Nothing }++EXECUTABLE_STATEMENT :: { Statement A0 }+: allocate '(' MAYBE_TYPE_SPEC DATA_REFS MAYBE_ALLOC_OPT_LIST ')'+ { StAllocate () (getTransSpan $1 $6) $3 (fromReverseList $4) $5 }+| nullify '(' DATA_REFS ')'+ { StNullify () (getTransSpan $1 $4) (fromReverseList $3) }+| deallocate '(' DATA_REFS MAYBE_ALLOC_OPT_LIST ')'+ { StDeallocate () (getTransSpan $1 $5) (fromReverseList $3) $4 }+| EXPRESSION_ASSIGNMENT_STATEMENT { $1 }+| POINTER_ASSIGNMENT_STMT { $1 }+| where '(' EXPRESSION ')' EXPRESSION_ASSIGNMENT_STATEMENT+ { StWhere () (getTransSpan $1 $5) $3 $5 }+| id ':' where '(' EXPRESSION ')' { let (TId s1 id) = $1 in StWhereConstruct () (getTransSpan $1 $6) (Just id) $5 }+| where '(' EXPRESSION ')' { StWhereConstruct () (getTransSpan $1 $4) Nothing $3 }+| elsewhere '(' EXPRESSION ')' id { let TId _ id = $5 in StElsewhere () (getTransSpan $1 $5) (Just id) (Just $3) }+| elsewhere '(' EXPRESSION ')' { StElsewhere () (getTransSpan $1 $4) Nothing (Just $3) }+| elsewhere id { let TId _ id = $2 in StElsewhere () (getTransSpan $1 $2) (Just id) Nothing }+| elsewhere { StElsewhere () (getSpan $1) Nothing Nothing }+| endwhere id { let TId _ id = $2 in StEndWhere () (getTransSpan $1 $2) (Just id) }+| endwhere { StEndWhere () (getSpan $1) Nothing }+| if '(' EXPRESSION ')' INTEGER_LITERAL ',' INTEGER_LITERAL ',' INTEGER_LITERAL+ { StIfArithmetic () (getTransSpan $1 $9) $3 $5 $7 $9 }+| if '(' EXPRESSION ')' then { StIfThen () (getTransSpan $1 $5) Nothing $3 }+| id ':' if '(' EXPRESSION ')' then+ { let TId s id = $1 in StIfThen () (getTransSpan s $7) (Just id) $5 }+| elsif '(' EXPRESSION ')' then { StElsif () (getTransSpan $1 $5) Nothing $3 }+| elsif '(' EXPRESSION ')' then id+ { let TId s id = $6 in StElsif () (getTransSpan $1 s) (Just id) $3 }+| else { StElse () (getSpan $1) Nothing }+| else id { let TId s id = $2 in StElse () (getTransSpan $1 s) (Just id) }+| endif { StEndif () (getSpan $1) Nothing }+| endif id { let TId s id = $2 in StEndif () (getTransSpan $1 s) (Just id) }+| do { StDo () (getSpan $1) Nothing Nothing Nothing }+| id ':' do+ { let TId s id = $1+ in StDo () (getTransSpan s $3) (Just id) Nothing Nothing }+| do INTEGER_LITERAL MAYBE_COMMA DO_SPECIFICATION+ { StDo () (getTransSpan $1 $4) Nothing (Just $2) (Just $4) }+| do DO_SPECIFICATION { StDo () (getTransSpan $1 $2) Nothing Nothing (Just $2) }+| id ':' do DO_SPECIFICATION+ { let TId s id = $1+ in StDo () (getTransSpan s $4) (Just id) Nothing (Just $4) }+| do INTEGER_LITERAL MAYBE_COMMA while '(' EXPRESSION ')'+ { StDoWhile () (getTransSpan $1 $7) Nothing (Just $2) $6 }+| do while '(' EXPRESSION ')'+ { StDoWhile () (getTransSpan $1 $5) Nothing Nothing $4 }+| id ':' do while '(' EXPRESSION ')'+ { let TId s id = $1+ in StDoWhile () (getTransSpan s $7) (Just id) Nothing $6 }+| enddo { StEnddo () (getSpan $1) Nothing }+| enddo id+ { let TId s id = $2 in StEnddo () (getTransSpan $1 s) (Just id) }+| cycle { StCycle () (getSpan $1) Nothing }+| cycle VARIABLE { StCycle () (getTransSpan $1 $2) (Just $2) }+| exit { StExit () (getSpan $1) Nothing }+| exit VARIABLE { StExit () (getTransSpan $1 $2) (Just $2) }+-- GO TO label+| goto INTEGER_LITERAL { StGotoUnconditional () (getTransSpan $1 $2) $2 }+-- GO TO label-list [,] scalar-int-expression+| goto '(' INTEGERS ')' MAYBE_COMMA EXPRESSION+ { StGotoComputed () (getTransSpan $1 $6) (fromReverseList $3) $6 }+| continue { StContinue () (getSpan $1) }+| stop { StStop () (getSpan $1) Nothing }+| stop EXPRESSION { StStop () (getTransSpan $1 $2) (Just $2) }+| selectcase '(' EXPRESSION ')'+ { StSelectCase () (getTransSpan $1 $4) Nothing $3 }+| id ':' selectcase '(' EXPRESSION ')'+ { let TId s id = $1 in StSelectCase () (getTransSpan s $6) (Just id) $5 }+| case default { StCase () (getTransSpan $1 $2) Nothing Nothing }+| case default id+ { let TId s id = $3 in StCase () (getTransSpan $1 s) (Just id) Nothing }+| case '(' INDICIES ')'+ { StCase () (getTransSpan $1 $4) Nothing (Just $ fromReverseList $3) }+| case '(' INDICIES ')' id+ { let TId s id = $5+ in StCase () (getTransSpan $1 s) (Just id) (Just $ fromReverseList $3) }+| endselect { StEndcase () (getSpan $1) Nothing }+| endselect id+ { let TId s id = $2 in StEndcase () (getTransSpan $1 s) (Just id) }+| if '(' EXPRESSION ')' EXECUTABLE_STATEMENT+ { StIfLogical () (getTransSpan $1 $5) $3 $5 }+| read CILIST IN_IOLIST+ { let alist = fromReverseList $3+ in StRead () (getTransSpan $1 alist) $2 (Just alist) }+| read CILIST { StRead () (getTransSpan $1 $2) $2 Nothing }+| read FORMAT_ID ',' IN_IOLIST+ { let alist = fromReverseList $4+ in StRead2 () (getTransSpan $1 alist) $2 (Just alist) }+| read FORMAT_ID { StRead2 () (getTransSpan $1 $2) $2 Nothing }+| write CILIST OUT_IOLIST+ { let alist = fromReverseList $3+ in StWrite () (getTransSpan $1 alist) $2 (Just alist) }+| write CILIST { StWrite () (getTransSpan $1 $2) $2 Nothing }+| print FORMAT_ID ',' OUT_IOLIST+ { let alist = fromReverseList $4+ in StPrint () (getTransSpan $1 alist) $2 (Just alist) }+| print FORMAT_ID { StPrint () (getTransSpan $1 $2) $2 Nothing }+| open CILIST { StOpen () (getTransSpan $1 $2) $2 }+| close CILIST { StClose () (getTransSpan $1 $2) $2 }+| inquire CILIST { StInquire () (getTransSpan $1 $2) $2 }+| rewind CILIST { StRewind () (getTransSpan $1 $2) $2 }+| rewind UNIT { StRewind2 () (getTransSpan $1 $2) $2 }+| endfile CILIST { StEndfile () (getTransSpan $1 $2) $2 }+| endfile UNIT { StEndfile2 () (getTransSpan $1 $2) $2 }+| backspace CILIST { StBackspace () (getTransSpan $1 $2) $2 }+| backspace UNIT { StBackspace2 () (getTransSpan $1 $2) $2 }+| flush INTEGER_LITERAL { StFlush () (getTransSpan $1 $2) (AList () (getSpan $2) [FSUnit () (getSpan $2) $2]) }+| flush '(' FLUSH_SPEC_LIST ')' { StFlush () (getTransSpan $1 $4) (fromReverseList $3) }+| call VARIABLE { StCall () (getTransSpan $1 $2) $2 Nothing }+| call VARIABLE '(' ')' { StCall () (getTransSpan $1 $4) $2 Nothing }+| call VARIABLE '(' ARGUMENTS ')'+ { let alist = fromReverseList $4+ in StCall () (getTransSpan $1 $5) $2 (Just alist) }+| return { StReturn () (getSpan $1) Nothing }+| return EXPRESSION { StReturn () (getTransSpan $1 $2) (Just $2) }+| FORALL { $1 }+| END_FORALL { $1 }++ARGUMENTS :: { [ Argument A0 ] }+: ARGUMENTS ',' ARGUMENT { $3 : $1 }+| ARGUMENT { [ $1 ] }++ARGUMENT :: { Argument A0 }+: id '=' EXPRESSION+ { let TId span keyword = $1+ in Argument () (getTransSpan span $3) (Just keyword) $3 }+| EXPRESSION+ { Argument () (getSpan $1) Nothing $1 }++MAYBE_RENAME_LIST :: { Maybe (AList Use A0) }+: RENAME_LIST { Just $ fromReverseList $1 }+| {- empty -} { Nothing }++RENAME_LIST :: { [ Use A0 ] }+: RENAME_LIST ',' RENAME { $3 : $1 }+| RENAME { [ $1 ] }++RENAME :: { Use A0 }+: VARIABLE '=>' VARIABLE { UseRename () (getTransSpan $1 $3) $1 $3 }+| VARIABLE { UseID () (getSpan $1) $1 }+| operator '(' opCustom ')'+ { let TOpCustom ss op = $3+ in UseID () (getTransSpan $1 $4) (ExpValue () ss (ValOperator op)) }+| assignment { UseID () (getSpan $1) (ExpValue () (getSpan $1) ValAssignment) }++MAYBE_DCOLON :: { () } : '::' { () } | {- EMPTY -} { () }++FORMAT_ID :: { Expression A0 }+: FORMAT_ID '/' '/' FORMAT_ID %prec CONCAT+ { ExpBinary () (getTransSpan $1 $4) Concatenation $1 $4 }+| INTEGER_LITERAL { $1 }+| STRING { $1 }+| DATA_REF { $1 }+| '*' { ExpValue () (getSpan $1) ValStar }++UNIT :: { Expression A0 }+: INTEGER_LITERAL { $1 }+| DATA_REF { $1 }+| '*' { ExpValue () (getSpan $1) ValStar }++{- R928 -}+FLUSH_SPEC_LIST :: { [ FlushSpec A0 ] }+: FLUSH_SPEC_LIST ',' FLUSH_SPEC { $3 : $1 }+| FLUSH_SPEC { [ $1 ] }++{- R928 -}+FLUSH_SPEC :: { FlushSpec A0 }+: EXPRESSION { FSUnit () (getSpan $1) $1 }+| unit '=' EXPRESSION { FSUnit () (getTransSpan $1 $3) $3 }+| iostat '=' EXPRESSION { FSIOStat () (getTransSpan $1 $3) $3 }+| iomsg '=' EXPRESSION { FSIOMsg () (getTransSpan $1 $3) $3 }+| err '=' EXPRESSION { FSErr () (getTransSpan $1 $3) $3 }++CILIST :: { AList ControlPair A0 }+: '(' CILIST_ELEMENT ',' FORMAT_ID ',' CILIST_PAIRS ')'+ { let { cp1 = ControlPair () (getSpan $2) Nothing $2;+ cp2 = ControlPair () (getSpan $4) Nothing $4;+ tail = fromReverseList $6 }+ in setSpan (getTransSpan $1 $7) $ cp1 `aCons` cp2 `aCons` tail }+| '(' CILIST_ELEMENT ',' FORMAT_ID ')'+ { let { cp1 = ControlPair () (getSpan $2) Nothing $2;+ cp2 = ControlPair () (getSpan $4) Nothing $4 }+ in AList () (getTransSpan $1 $5) [ cp1, cp2 ] }+| '(' CILIST_ELEMENT ',' CILIST_PAIRS ')'+ { let { cp1 = ControlPair () (getSpan $2) Nothing $2;+ tail = fromReverseList $4 }+ in setSpan (getTransSpan $1 $5) $ cp1 `aCons` tail }+| '(' CILIST_ELEMENT ')'+ { let cp1 = ControlPair () (getSpan $2) Nothing $2+ in AList () (getTransSpan $1 $3) [ cp1 ] }+| '(' CILIST_PAIRS ')' { fromReverseList $2 }++CILIST_PAIRS :: { [ ControlPair A0 ] }+: CILIST_PAIRS ',' CILIST_PAIR { $3 : $1 }+| CILIST_PAIR { [ $1 ] }++CILIST_PAIR :: { ControlPair A0 }+: id '=' CILIST_ELEMENT+ { let (TId s id) = $1 in ControlPair () (getTransSpan s $3) (Just id) $3 }++CILIST_ELEMENT :: { Expression A0 }+: CI_EXPRESSION { $1 }+| '*' { ExpValue () (getSpan $1) ValStar }++CI_EXPRESSION :: { Expression A0 }+: CI_EXPRESSION '+' CI_EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Addition $1 $3 }+| CI_EXPRESSION '-' CI_EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Subtraction $1 $3 }+| CI_EXPRESSION '*' CI_EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Multiplication $1 $3 }+| CI_EXPRESSION '/' CI_EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Division $1 $3 }+| CI_EXPRESSION '**' CI_EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Exponentiation $1 $3 }+| CI_EXPRESSION '/' '/' CI_EXPRESSION %prec CONCAT+ { ExpBinary () (getTransSpan $1 $4) Concatenation $1 $4 }+| ARITHMETIC_SIGN CI_EXPRESSION %prec SIGN+ { ExpUnary () (getTransSpan (fst $1) $2) (snd $1) $2 }+| CI_EXPRESSION or CI_EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Or $1 $3 }+| CI_EXPRESSION and CI_EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) And $1 $3 }+| not CI_EXPRESSION+ { ExpUnary () (getTransSpan $1 $2) Not $2 }+| CI_EXPRESSION eqv CI_EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Equivalent $1 $3 }+| CI_EXPRESSION neqv CI_EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) NotEquivalent $1 $3 }+| CI_EXPRESSION RELATIONAL_OPERATOR CI_EXPRESSION %prec RELATIONAL+ { ExpBinary () (getTransSpan $1 $3) $2 $1 $3 }+| opCustom CI_EXPRESSION %prec DEFINED_UNARY+ { let TOpCustom span str = $1+ in ExpUnary () (getTransSpan span $2) (UnCustom str) $2 }+| CI_EXPRESSION opCustom CI_EXPRESSION+ { let TOpCustom _ str = $2+ in ExpBinary () (getTransSpan $1 $3) (BinCustom str) $1 $3 }+| '(' CI_EXPRESSION ')' { setSpan (getTransSpan $1 $3) $2 }+| INTEGER_LITERAL { $1 }+| LOGICAL_LITERAL { $1 }+| STRING { $1 }+| DATA_REF { $1 }++MAYBE_ALLOC_OPT_LIST :: { Maybe (AList AllocOpt A0) }+: ',' ALLOC_OPT_LIST { Just $ fromReverseList $2 }+| {- empty -} { Nothing }++ALLOC_OPT_LIST :: { [ AllocOpt A0 ] }+: ALLOC_OPT_LIST ',' ALLOC_OPT { $3 : $1 }+| ALLOC_OPT { [ $1 ] }++{- R624 -}+ALLOC_OPT :: { AllocOpt A0 }+: stat '=' EXPRESSION { AOStat () (getTransSpan $1 $3) $3 }+| errmsg '=' EXPRESSION { AOErrMsg () (getTransSpan $1 $3) $3 }+| source '=' EXPRESSION { AOSource () (getTransSpan $1 $3) $3 }++IN_IOLIST :: { [ Expression A0 ] }+: IN_IOLIST ',' IN_IO_ELEMENT { $3 : $1}+| IN_IO_ELEMENT { [ $1 ] }++IN_IO_ELEMENT :: { Expression A0 }+: DATA_REF { $1 }+| '(' IN_IOLIST ',' DO_SPECIFICATION ')'+ { ExpImpliedDo () (getTransSpan $1 $5) (fromReverseList $2) $4 }++OUT_IOLIST :: { [ Expression A0 ] }+: OUT_IOLIST ',' EXPRESSION { $3 : $1}+| EXPRESSION { [ $1 ] }++COMMON_GROUPS :: { [ CommonGroup A0 ] }+: COMMON_GROUPS COMMON_GROUP { $2 : $1 }+| COMMON_GROUPS ',2' COMMON_GROUP { $3 : $1 }+| INIT_COMMON_GROUP { [ $1 ] }++COMMON_GROUP :: { CommonGroup A0 }+: COMMON_NAME PART_REFS+ { let alist = fromReverseList $2+ in CommonGroup () (getTransSpan $1 alist) (Just $1) alist }+| '/' '/' PART_REFS+ { let alist = fromReverseList $3+ in CommonGroup () (getTransSpan $1 alist) Nothing alist }++INIT_COMMON_GROUP :: { CommonGroup A0 }+: COMMON_NAME PART_REFS+ { let alist = fromReverseList $2+ in CommonGroup () (getTransSpan $1 alist) (Just $1) alist }+| '/' '/' PART_REFS+ { let alist = fromReverseList $3+ in CommonGroup () (getTransSpan $1 alist) Nothing alist }+| PART_REFS+ { let alist = fromReverseList $1+ in CommonGroup () (getSpan alist) Nothing alist }++EQUIVALENCE_GROUPS :: { [ AList Expression A0 ] }+: EQUIVALENCE_GROUPS ',' '(' PART_REFS ')'+ { setSpan (getTransSpan $3 $5) (fromReverseList $4) : $1 }+| '(' PART_REFS ')'+ { [ setSpan (getTransSpan $1 $3) (fromReverseList $2) ] }++NAMELISTS :: { [ Namelist A0 ] }+: NAMELISTS NAMELIST { $2 : $1 }+| NAMELISTS ',2' NAMELIST { $3 : $1 }+| NAMELIST { [ $1 ] }++NAMELIST :: { Namelist A0 }+: '/' VARIABLE '/' VARIABLES+ { Namelist () (getTransSpan $1 $4) $2 $ fromReverseList $4 }++MAYBE_VARIABLES :: { Maybe (AList Expression A0) }+: VARIABLES { Just $ fromReverseList $1 } | {- EMPTY -} { Nothing }++VARIABLES :: { [ Expression A0 ] }+: VARIABLES ',' VARIABLE { $3 : $1 }+| VARIABLE { [ $1 ] }++IMP_LISTS :: { [ ImpList A0 ] }+: IMP_LISTS ',' IMP_LIST { $3 : $1 }+| IMP_LIST { [ $1 ] }++IMP_LIST :: { ImpList A0 }+: TYPE_SPEC '(2' IMP_ELEMENTS ')'+ { ImpList () (getTransSpan $1 $4) $1 (aReverse $3) }++IMP_ELEMENTS :: { AList ImpElement A0 }+: IMP_ELEMENTS ',' IMP_ELEMENT { setSpan (getTransSpan $1 $3) $ $3 `aCons` $1 }+| IMP_ELEMENT { AList () (getSpan $1) [ $1 ] }++IMP_ELEMENT :: { ImpElement A0 }+: id {% do+ let (TId s id) = $1+ if length id /= 1+ then fail "Implicit argument must be a character."+ else return $ ImpCharacter () s id+ }+| id '-' id {% do+ let (TId _ id1) = $1+ let (TId _ id2) = $3+ if length id1 /= 1 || length id2 /= 1+ then fail "Implicit argument must be a character."+ else return $ ImpRange () (getTransSpan $1 $3) id1 id2+ }++PARAMETER_ASSIGNMENTS :: { [ Declarator A0 ] }+: PARAMETER_ASSIGNMENTS ',' PARAMETER_ASSIGNMENT { $3 : $1 }+| PARAMETER_ASSIGNMENT { [ $1 ] }++PARAMETER_ASSIGNMENT :: { Declarator A0 }+: VARIABLE '=' EXPRESSION+ { DeclVariable () (getTransSpan $1 $3) $1 Nothing (Just $3) }++DECLARATION_STATEMENT :: { Statement A0 }+: TYPE_SPEC ATTRIBUTE_LIST '::' DECLARATOR_LIST+ { let { mAttrAList = if null $2 then Nothing else Just $ fromReverseList $2;+ declAList = fromReverseList $4 }+ in StDeclaration () (getTransSpan $1 declAList) $1 mAttrAList declAList }+| TYPE_SPEC DECLARATOR_LIST+ { let { declAList = fromReverseList $2 }+ in StDeclaration () (getTransSpan $1 declAList) $1 Nothing declAList }++ATTRIBUTE_LIST :: { [ Attribute A0 ] }+: ATTRIBUTE_LIST ',' ATTRIBUTE_SPEC { $3 : $1 }+| {- EMPTY -} { [ ] }++ATTRIBUTE_SPEC :: { Attribute A0 }+: public { AttrPublic () (getSpan $1) }+| private { AttrPrivate () (getSpan $1) }+| protected { AttrProtected () (getSpan $1) }+| allocatable { AttrAllocatable () (getSpan $1) }+| asynchronous { AttrAsynchronous () (getSpan $1) }+| dimension '(' DIMENSION_DECLARATORS ')'+ { AttrDimension () (getTransSpan $1 $4) (aReverse $3) }+| external { AttrExternal () (getSpan $1) }+| intent '(' INTENT_CHOICE ')' { AttrIntent () (getTransSpan $1 $4) $3 }+| intrinsic { AttrIntrinsic () (getSpan $1) }+| optional { AttrOptional () (getSpan $1) }+| pointer { AttrPointer () (getSpan $1) }+| parameter { AttrParameter () (getSpan $1) }+| save { AttrSave () (getSpan $1) }+| target { AttrTarget () (getSpan $1) }+| value { AttrValue () (getSpan $1) }+| volatile { AttrVolatile () (getSpan $1) }+| SUFFIX { AttrSuffix () (getSpan $1) $1 }++INTENT_CHOICE :: { Intent } : in { In } | out { Out } | inout { InOut }++DATA_GROUPS :: { [ DataGroup A0 ] }+: DATA_GROUPS MAYBE_COMMA DATA_LIST slash EXPRESSION_LIST slash+ { let { nameAList = fromReverseList $3;+ dataAList = fromReverseList $5 }+ in DataGroup () (getTransSpan nameAList $6) nameAList dataAList : $1 }+| DATA_LIST slash EXPRESSION_LIST slash+ { let { nameAList = fromReverseList $1;+ dataAList = fromReverseList $3 }+ in [ DataGroup () (getTransSpan nameAList $4) nameAList dataAList ] }++MAYBE_COMMA :: { () } : ',' { () } | {- EMPTY -} { () }++DATA_LIST :: { [ Expression A0 ] }+: DATA_LIST ',' DATA_ELEMENT { $3 : $1 }+| DATA_ELEMENT { [ $1 ] }++DATA_ELEMENT :: { Expression A0 }+: DATA_REF { $1 } | IMPLIED_DO { $1 }++SAVE_ARGS :: { [ Expression A0 ] }+: SAVE_ARGS ',' SAVE_ARG { $3 : $1 } | SAVE_ARG { [ $1 ] }++SAVE_ARG :: { Expression A0 } : COMMON_NAME { $1 } | VARIABLE { $1 }++COMMON_NAME :: { Expression A0 }+: '/' VARIABLE '/' { setSpan (getTransSpan $1 $3) $2 }++DECLARATOR_LIST :: { [ Declarator A0 ] }+: DECLARATOR_LIST ',' INITIALISED_DECLARATOR { $3 : $1 }+| INITIALISED_DECLARATOR { [ $1 ] }++INITIALISED_DECLARATOR :: { Declarator A0 }+: DECLARATOR '=' EXPRESSION { setInitialisation $1 $3 }+| DECLARATOR '=>' EXPRESSION { setInitialisation $1 $3 }+| DECLARATOR { $1 }++DECLARATOR :: { Declarator A0 }+: VARIABLE { DeclVariable () (getSpan $1) $1 Nothing Nothing }+| VARIABLE '*' EXPRESSION+ { DeclVariable () (getTransSpan $1 $3) $1 (Just $3) Nothing }+| VARIABLE '*' '(' '*' ')'+ { let star = ExpValue () (getSpan $4) ValStar+ in DeclVariable () (getTransSpan $1 $5) $1 (Just star) Nothing }+| VARIABLE '(' DIMENSION_DECLARATORS ')'+ { DeclArray () (getTransSpan $1 $4) $1 (aReverse $3) Nothing Nothing }+| VARIABLE '(' DIMENSION_DECLARATORS ')' '*' EXPRESSION+ { DeclArray () (getTransSpan $1 $6) $1 (aReverse $3) (Just $6) Nothing }+| VARIABLE '(' DIMENSION_DECLARATORS ')' '*' '(' '*' ')'+ { let star = ExpValue () (getSpan $7) ValStar+ in DeclArray () (getTransSpan $1 $8) $1 (aReverse $3) (Just star) Nothing }++DIMENSION_DECLARATORS :: { AList DimensionDeclarator A0 }+: DIMENSION_DECLARATORS ',' DIMENSION_DECLARATOR+ { setSpan (getTransSpan $1 $3) $ $3 `aCons` $1 }+| DIMENSION_DECLARATOR+ { AList () (getSpan $1) [ $1 ] }++DIMENSION_DECLARATOR :: { DimensionDeclarator A0 }+: EXPRESSION ':' EXPRESSION+ { DimensionDeclarator () (getTransSpan $1 $3) (Just $1) (Just $3) }+| EXPRESSION { DimensionDeclarator () (getSpan $1) Nothing (Just $1) }+-- Lower bound only+| EXPRESSION ':'+ { DimensionDeclarator () (getTransSpan $1 $2) (Just $1) Nothing }+| EXPRESSION ':' '*'+ { let { span = getSpan $3;+ star = ExpValue () span ValStar }+ in DimensionDeclarator () (getTransSpan $1 span) (Just $1) (Just star) }+| '*'+ { let { span = getSpan $1;+ star = ExpValue () span ValStar }+ in DimensionDeclarator () span Nothing (Just star) }+| ':'+ { let span = getSpan $1+ in DimensionDeclarator () span Nothing Nothing }++MAYBE_TYPE_SPEC :: { Maybe (TypeSpec A0) }+: TYPE_SPEC '::' { Just $1 }+| {- empty -} { 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 ')'+ { let TId _ id = $3+ in TypeSpec () (getTransSpan $1 $4) (TypeCustom id) Nothing }+-- R502+| class '(' '*' ')' { TypeSpec () (getSpan ($1, $4)) ClassStar Nothing }+-- FIXME: this (and TypeCustom) can accept parameterised types. See type-param-value.+-- Needs refactoring as this is used in various parts of the spec to consolidate+-- uses of ':', '*' and scalar-int-exp.+| class '(' id ')'+ { let TId _ id = $3+ in TypeSpec () (getSpan ($1, $4)) (ClassCustom id) Nothing }++KIND_SELECTOR :: { Maybe (Selector A0) }+: '(' EXPRESSION ')'+ { Just $ Selector () (getTransSpan $1 $3) Nothing (Just $2) }+| '(' kind '=' EXPRESSION ')'+ { Just $ Selector () (getTransSpan $1 $5) Nothing (Just $4) }+| '*' EXPRESSION -- non-standard but commonly used extension+ { Just $ Selector () (getTransSpan $1 $2) Nothing (Just $2) }+| {- EMPTY -} { Nothing }++CHAR_SELECTOR :: { Maybe (Selector A0) }+: '*' EXPRESSION+ { Just $ Selector () (getTransSpan $1 $2) (Just $2) Nothing }+-- The following rule is a bug in the spec.+-- | '*' EXPRESSION ','+-- { Just $ Selector () (getTransSpan $1 $2) (Just $2) Nothing }+| '*' '(' '*' ')'+ { let star = ExpValue () (getSpan $3) ValStar+ in Just $ Selector () (getTransSpan $1 $4) (Just star) Nothing }+| '(' LEN_EXPRESSION ')'+ { Just $ Selector () (getTransSpan $1 $3) (Just $2) Nothing }+| '(' len '=' LEN_EXPRESSION ')'+ { Just $ Selector () (getTransSpan $1 $5) (Just $4) Nothing }+| '(' kind '=' EXPRESSION ')'+ { Just $ Selector () (getTransSpan $1 $5) Nothing (Just $4) }+| '(' LEN_EXPRESSION ',' EXPRESSION ')'+ { Just $ Selector () (getTransSpan $1 $5) (Just $2) (Just $4) }+| '(' LEN_EXPRESSION ',' kind '=' EXPRESSION ')'+ { Just $ Selector () (getTransSpan $1 $7) (Just $2) (Just $6) }+| '(' len '=' LEN_EXPRESSION ',' kind '=' EXPRESSION ')'+ { Just $ Selector () (getTransSpan $1 $9) (Just $4) (Just $8) }+| '(' kind '=' EXPRESSION ',' len '=' LEN_EXPRESSION ')'+ { Just $ Selector () (getTransSpan $1 $9) (Just $8) (Just $4) }+| {- EMPTY -} { Nothing }++{- R402 -}+LEN_EXPRESSION :: { Expression A0 }+: EXPRESSION { $1 }+| '*' { ExpValue () (getSpan $1) ValStar }+| ':' { ExpValue () (getSpan $1) ValColon }++EXPRESSION :: { Expression A0 }+: EXPRESSION '+' EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Addition $1 $3 }+| EXPRESSION '-' EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Subtraction $1 $3 }+| EXPRESSION '*' EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Multiplication $1 $3 }+| EXPRESSION '/' EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Division $1 $3 }+| EXPRESSION '**' EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Exponentiation $1 $3 }+| EXPRESSION '/' '/' EXPRESSION %prec CONCAT+ { ExpBinary () (getTransSpan $1 $4) Concatenation $1 $4 }+| ARITHMETIC_SIGN EXPRESSION %prec SIGN+ { ExpUnary () (getTransSpan (fst $1) $2) (snd $1) $2 }+| EXPRESSION or EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Or $1 $3 }+| EXPRESSION and EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) And $1 $3 }+| not EXPRESSION+ { ExpUnary () (getTransSpan $1 $2) Not $2 }+| EXPRESSION eqv EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) Equivalent $1 $3 }+| EXPRESSION neqv EXPRESSION+ { ExpBinary () (getTransSpan $1 $3) NotEquivalent $1 $3 }+| EXPRESSION RELATIONAL_OPERATOR EXPRESSION %prec RELATIONAL+ { ExpBinary () (getTransSpan $1 $3) $2 $1 $3 }+| opCustom EXPRESSION %prec DEFINED_UNARY+ { let TOpCustom span str = $1+ in ExpUnary () (getTransSpan span $2) (UnCustom str) $2 }+| EXPRESSION opCustom EXPRESSION+ { let TOpCustom _ str = $2+ in ExpBinary () (getTransSpan $1 $3) (BinCustom str) $1 $3 }+| '(' EXPRESSION ')' { setSpan (getTransSpan $1 $3) $2 }+| NUMERIC_LITERAL { $1 }+| '(' EXPRESSION ',' EXPRESSION ')'+ { ExpValue () (getTransSpan $1 $5) (ValComplex $2 $4) }+| LOGICAL_LITERAL { $1 }+| STRING { $1 }+| DATA_REF { $1 }+| IMPLIED_DO { $1 }+| '(/' EXPRESSION_LIST '/)'+ { ExpInitialisation () (getTransSpan $1 $3) (fromReverseList $2) }+| operator '(' opCustom ')'+ { let TOpCustom _ op = $3+ in ExpValue () (getTransSpan $1 $4) (ValOperator op) }+| assignment { ExpValue () (getSpan $1) ValAssignment }+| '*' INTEGER_LITERAL { ExpReturnSpec () (getTransSpan $1 $2) $2 }++DATA_REFS :: { [ Expression A0 ] }+: DATA_REFS ',' DATA_REF { $3 : $1 }+| DATA_REF { [ $1 ] }++DATA_REF :: { Expression A0 }+: DATA_REF '%' PART_REF { ExpDataRef () (getTransSpan $1 $3) $1 $3 }+| PART_REF { $1 }++PART_REFS :: { [ Expression A0 ] }+: PART_REFS ',' PART_REF { $3 : $1 }+| PART_REF { [ $1 ] }++PART_REF :: { Expression A0 }+: VARIABLE { $1 }+| VARIABLE '(' ')'+ { ExpFunctionCall () (getTransSpan $1 $3) $1 Nothing }+| VARIABLE '(' INDICIES ')'+ { ExpSubscript () (getTransSpan $1 $4) $1 (fromReverseList $3) }+| VARIABLE '(' INDICIES ')' '(' INDICIES ')'+ { let innerSub = ExpSubscript () (getTransSpan $1 $4) $1 (fromReverseList $3)+ in ExpSubscript () (getTransSpan $1 $7) innerSub (fromReverseList $6) }++INDICIES :: { [ Index A0 ] }+: INDICIES ',' INDEX { $3 : $1 }+| INDEX { [ $1 ] }++INDEX :: { Index A0 }+: RANGE { $1 }+| RANGE ':' EXPRESSION+ { let IxRange () s lower upper _ = $1+ in IxRange () (getTransSpan s $3) lower upper (Just $3) }+| EXPRESSION { IxSingle () (getSpan $1) Nothing $1 }+-- Following is only as an intermediate stage before having been turned into+-- an argument by later transformation.+| id '=' EXPRESSION+ { let TId s id = $1 in IxSingle () (getTransSpan $1 s) (Just id) $3 }++RANGE :: { Index A0 }+: ':' { IxRange () (getSpan $1) Nothing Nothing Nothing }+| ':' EXPRESSION { IxRange () (getTransSpan $1 $2) Nothing (Just $2) Nothing }+| EXPRESSION ':' { IxRange () (getTransSpan $1 $2) (Just $1) Nothing Nothing }+| EXPRESSION ':' EXPRESSION+ { IxRange () (getTransSpan $1 $3) (Just $1) (Just $3) Nothing }++DO_SPECIFICATION :: { DoSpecification A0 }+: EXPRESSION_ASSIGNMENT_STATEMENT ',' EXPRESSION ',' EXPRESSION+ { DoSpecification () (getTransSpan $1 $5) $1 $3 (Just $5) }+| EXPRESSION_ASSIGNMENT_STATEMENT ',' EXPRESSION+ { DoSpecification () (getTransSpan $1 $3) $1 $3 Nothing }++IMPLIED_DO :: { Expression A0 }+: '(' EXPRESSION ',' DO_SPECIFICATION ')'+ { let expList = AList () (getSpan $2) [ $2 ]+ in ExpImpliedDo () (getTransSpan $1 $5) expList $4 }+| '(' EXPRESSION ',' EXPRESSION ',' DO_SPECIFICATION ')'+ { let expList = AList () (getTransSpan $2 $4) [ $2, $4 ]+ in ExpImpliedDo () (getTransSpan $1 $5) expList $6 }+| '(' EXPRESSION ',' EXPRESSION ',' EXPRESSION_LIST ',' DO_SPECIFICATION ')'+ { let { exps = reverse $6;+ expList = AList () (getTransSpan $2 exps) ($2 : $4 : reverse $6) }+ in ExpImpliedDo () (getTransSpan $1 $9) expList $8 }++FORALL :: { Statement A0 }+: id ':' forall FORALL_HEADER {+ let (TId s1 id) = $1 in+ let (h,s2) = $4 in+ StForall () (getTransSpan s1 s2) (Just id) h+}+| forall FORALL_HEADER {+ let (h,s) = $2 in+ StForall () (getTransSpan $1 s) Nothing h+}+| forall FORALL_HEADER FORALL_ASSIGNMENT_STMT {+ let (h,_) = $2 in+ StForallStatement () (getTransSpan $1 $3) h $3+}++FORALL_HEADER+ :: { (ForallHeader A0, SrcSpan) }+FORALL_HEADER :+ -- Standard simple forall header+ '(' FORALL_TRIPLET_SPEC ')' { (ForallHeader [$2] Nothing, getTransSpan $1 $3) }+ -- forall header with scale expression+ | '(' '(' FORALL_TRIPLET_SPEC ')' ',' EXPRESSION ')'+ { (ForallHeader [$3] (Just $6), getTransSpan $1 $7) }+ -- multi forall header+ | '(' FORALL_TRIPLET_SPEC_LIST_PLUS_STRIDE ')'+ { (ForallHeader $2 Nothing, getTransSpan $1 $3) }+ -- multi forall header with scale+ | '(' FORALL_TRIPLET_SPEC_LIST_PLUS_STRIDE ',' EXPRESSION ')'+ { (ForallHeader $2 (Just $4), getTransSpan $1 $5) }++FORALL_TRIPLET_SPEC_LIST_PLUS_STRIDE+ :: { [(Name, Expression A0, Expression A0, Maybe (Expression A0))] }+FORALL_TRIPLET_SPEC_LIST_PLUS_STRIDE+: '(' FORALL_TRIPLET_SPEC ')' ',' FORALL_TRIPLET_SPEC_LIST_PLUS_STRIDE { $2 : $5 }+| {- empty -} { [] }++FORALL_TRIPLET_SPEC :: { (Name, Expression A0, Expression A0, Maybe (Expression A0)) }+FORALL_TRIPLET_SPEC+: NAME '=' EXPRESSION ':' EXPRESSION { ($1, $3, $5, Nothing) }+| NAME '=' EXPRESSION ':' EXPRESSION ',' EXPRESSION { ($1, $3, $5, Just $7) }++FORALL_ASSIGNMENT_STMT :: { Statement A0 }+FORALL_ASSIGNMENT_STMT :+ EXPRESSION_ASSIGNMENT_STATEMENT { $1 }+ | POINTER_ASSIGNMENT_STMT { $1 }++POINTER_ASSIGNMENT_STMT :: { Statement A0 }+POINTER_ASSIGNMENT_STMT :+ DATA_REF '=>' EXPRESSION { StPointerAssign () (getTransSpan $1 $3) $1 $3 }++END_FORALL :: { Statement A0 }+END_FORALL :+ endforall { StEndForall () (getSpan $1) Nothing }+ | endforall id { let (TId s id) = $2 in StEndForall () (getTransSpan $1 s) (Just id)}++EXPRESSION_LIST :: { [ Expression A0 ] }+: EXPRESSION_LIST ',' EXPRESSION { $3 : $1 }+| EXPRESSION { [ $1 ] }++ARITHMETIC_SIGN :: { (SrcSpan, UnaryOp) }+: '-' { (getSpan $1, Minus) }+| '+' { (getSpan $1, Plus) }++RELATIONAL_OPERATOR :: { BinaryOp }+: '==' { EQ }+| '!=' { NE }+| '>' { GT }+| '>=' { GTE }+| '<' { LT }+| '<=' { LTE }++VARIABLE :: { Expression A0 }+: id { ExpValue () (getSpan $1) $ let (TId _ s) = $1 in ValVariable s }++NUMERIC_LITERAL :: { Expression A0 }+: INTEGER_LITERAL { $1 } | REAL_LITERAL { $1 }++INTEGERS :: { [ Expression A0 ] }+: INTEGERS ',' INTEGER_LITERAL { $3 : $1 }+| INTEGER_LITERAL { [ $1 ] }++INTEGER_LITERAL :: { Expression A0 }+: int { let TIntegerLiteral s i = $1 in ExpValue () s $ ValInteger i }+| boz { let TBozLiteral s i = $1 in ExpValue () s $ ValInteger i }++REAL_LITERAL :: { Expression A0 }+: float { let TRealLiteral s r = $1 in ExpValue () s $ ValReal r }++LOGICAL_LITERAL :: { Expression A0 }+: bool { let TLogicalLiteral s b = $1 in ExpValue () s $ ValLogical b }++STRING :: { Expression A0 }+: string { let TString s c = $1 in ExpValue () s $ ValString c }++cDATA :: { () } : {% pushContext ConData }+cIMPLICIT :: { () } : {% pushContext ConImplicit }+cNAMELIST :: { () } : {% pushContext ConNamelist }+cCOMMON :: { () } : {% pushContext ConCommon }+cPOP :: { () } : {% popContext }++{++unitNameCheck :: Token -> String -> Parse AlexInput Token ()+unitNameCheck (TId _ name1) name2+ | name1 == name2 = return ()+ | otherwise = fail "Unit name does not match the corresponding END statement."+unitNameCheck _ _ = return ()++parse = runParse programParser++transformations2003 =+ [ GroupLabeledDo+ , GroupDo+ , GroupIf+ , GroupCase+ , DisambiguateIntrinsic+ , DisambiguateFunction+ ]++fortran2003Parser ::+ B.ByteString -> String -> ParseResult AlexInput Token (ProgramFile A0)+fortran2003Parser sourceCode filename =+ (pfSetFilename filename . transform transformations2003) <$> parse parseState+ where+ parseState = initParseState sourceCode Fortran2003 filename++fortran2003ParserWithModFiles ::+ ModFiles -> B.ByteString -> String -> ParseResult AlexInput Token (ProgramFile A0)+fortran2003ParserWithModFiles mods sourceCode filename =+ fmap (pfSetFilename filename . transform) $ parse parseState+ where+ transform = transformWithModFiles mods transformations2003+ parseState = initParseState sourceCode Fortran2003 filename++parseError :: Token -> LexAction a+parseError token = do+ parseState <- get+#ifdef DEBUG+ tokens <- reverse <$> aiPreviousTokensInLine <$> getAlex+#endif+ fail $ psFilename parseState ++ ": parsing failed. "+ ++ specifics token+#ifdef DEBUG+ ++ '\n' : show tokens+#endif+ where specifics (TPause _) = "\nPAUSE statements are not supported in Fortran 2003 or later. "+ specifics (TAssign _) = "\nASSIGN statements are not supported in Fortran 2003 or later. "+ specifics _ = ""++}
src/Language/Fortran/Parser/Fortran66.y view
@@ -128,11 +128,11 @@ OTHER_PROGRAM_UNIT :: { ProgramUnit A0 } OTHER_PROGRAM_UNIT : TYPE_SPEC function NAME MAYBE_ARGUMENTS NEWLINE BLOCKS end MAYBE_NEWLINE- { PUFunction () (getTransSpan $1 $7) (Just $1) (None () initSrcSpan False) $3 $4 Nothing (reverse $6) Nothing }+ { PUFunction () (getTransSpan $1 $7) (Just $1) emptyPrefixSuffix $3 $4 Nothing (reverse $6) Nothing } | function NAME MAYBE_ARGUMENTS NEWLINE BLOCKS end MAYBE_NEWLINE- { PUFunction () (getTransSpan $1 $6) Nothing (None () initSrcSpan False) $2 $3 Nothing (reverse $5) Nothing }+ { PUFunction () (getTransSpan $1 $6) Nothing emptyPrefixSuffix $2 $3 Nothing (reverse $5) Nothing } | subroutine NAME MAYBE_ARGUMENTS NEWLINE BLOCKS end MAYBE_NEWLINE- { PUSubroutine () (getTransSpan $1 $6) (None () initSrcSpan False) $2 $3 (reverse $5) Nothing }+ { PUSubroutine () (getTransSpan $1 $6) emptyPrefixSuffix $2 $3 (reverse $5) Nothing } | blockData NEWLINE BLOCKS end MAYBE_NEWLINE { PUBlockData () (getTransSpan $1 $4) Nothing (reverse $3) } MAYBE_ARGUMENTS :: { Maybe (AList Expression A0) }
src/Language/Fortran/Parser/Fortran77.y view
@@ -207,11 +207,11 @@ : program NAME NEWLINE BLOCKS ENDPROG { PUMain () (getTransSpan $1 $5) (Just $2) (reverse $4) Nothing } | TYPE_SPEC function NAME MAYBE_ARGUMENTS NEWLINE BLOCKS ENDFUN- { PUFunction () (getTransSpan $1 $7) (Just $1) (None () initSrcSpan False) $3 $4 Nothing (reverse $6) Nothing }+ { PUFunction () (getTransSpan $1 $7) (Just $1) emptyPrefixSuffix $3 $4 Nothing (reverse $6) Nothing } | function NAME MAYBE_ARGUMENTS NEWLINE BLOCKS ENDFUN- { PUFunction () (getTransSpan $1 $6) Nothing (None () initSrcSpan False) $2 $3 Nothing (reverse $5) Nothing }+ { PUFunction () (getTransSpan $1 $6) Nothing emptyPrefixSuffix $2 $3 Nothing (reverse $5) Nothing } | subroutine NAME MAYBE_ARGUMENTS NEWLINE BLOCKS ENDSUB- { PUSubroutine () (getTransSpan $1 $6) (None () initSrcSpan False) $2 $3 (reverse $5) Nothing }+ { PUSubroutine () (getTransSpan $1 $6) emptyPrefixSuffix $2 $3 (reverse $5) Nothing } | blockData NEWLINE BLOCKS END { PUBlockData () (getTransSpan $1 $4) Nothing (reverse $3) } | blockData NAME NEWLINE BLOCKS END { PUBlockData () (getTransSpan $1 $5) (Just $2) (reverse $4) } | comment { let (TComment s c) = $1 in PUComment () s (Comment c) }@@ -1003,7 +1003,7 @@ | 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)) TypeCharacter $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 } @@ -1121,10 +1121,10 @@ doParse = case parse parseState of ParseFailed e -> return (ParseFailed e) ParseOk p x -> do- p' <- descendBiM (inlineInclude Fortran77Legacy incs) p+ p' <- descendBiM (inlineInclude Fortran77Legacy incs []) p return (ParseOk p' x) transform = transformWithModFiles emptyModFiles transformations77Legacy- parseState = initParseState sourceCode Fortran77Legacy filename+ parseState = initParseState (truncateLines sourceCode) Fortran77Legacy filename includeParser :: FortranVersion -> B.ByteString -> String -> ParseResult AlexInput Token [Block A0]@@ -1134,15 +1134,17 @@ -- ensure the file ends with a newline.. parseState = initParseState (sourceCode `B.snoc` '\n') version filename -inlineInclude :: FortranVersion -> [String] -> Statement A0 -> IO (Statement A0)-inlineInclude fv dirs st = case st of+inlineInclude :: FortranVersion -> [String] -> [String] -> Statement A0 -> IO (Statement A0)+inlineInclude fv dirs seen st = case st of StInclude a s e@(ExpValue _ _ (ValString path)) Nothing -> do- inc <- truncateLines <$> readInDirs dirs path- case includeParser fv inc path of- ParseOk blocks _ -> do- blocks' <- descendBiM (inlineInclude fv dirs) blocks- return $ StInclude a s e (Just blocks')- ParseFailed e -> throwIO e+ if notElem path seen then do+ inc <- truncateLines <$> readInDirs dirs path+ case includeParser fv inc path of+ ParseOk blocks _ -> do+ blocks' <- descendBiM (inlineInclude fv dirs (path:seen)) blocks+ return $ StInclude a s e (Just blocks')+ ParseFailed e -> throwIO e+ else return st _ -> return st readInDirs :: [String] -> String -> IO B.ByteString
src/Language/Fortran/Parser/Fortran90.y view
@@ -9,6 +9,7 @@ import Prelude hiding (EQ,LT,GT) -- Same constructors exist in the AST import Control.Monad.State (get) import Data.Maybe (fromMaybe)+import Data.Either (partitionEithers) import qualified Data.ByteString.Char8 as B import Control.Monad.State@@ -119,6 +120,7 @@ equivalence { TEquivalence _ } common { TCommon _ } allocate { TAllocate _ }+ stat { TStat _ } deallocate { TDeallocate _ } nullify { TNullify _ } none { TNone _ }@@ -237,37 +239,45 @@ | {- EMPTY -} { [ ] } SUBPROGRAM_UNIT :: { ProgramUnit A0 }-: TYPE_SPEC function NAME MAYBE_ARGUMENTS MAYBE_COMMENT RESULT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS FUNCTION_END- {% do { unitNameCheck $10 $3;- return $ PUFunction () (getTransSpan $1 $10) (Just $1) (None () initSrcSpan False) $3 $4 $6 (reverse $8) $9 } }-| TYPE_SPEC recursive function NAME MAYBE_ARGUMENTS MAYBE_COMMENT RESULT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS FUNCTION_END- {% do { unitNameCheck $11 $4;- return $ PUFunction () (getTransSpan $1 $11) (Just $1) (None () (getSpan $2) True) $4 $5 $7 (reverse $9) $10 } }-| recursive TYPE_SPEC function NAME MAYBE_ARGUMENTS RESULT MAYBE_COMMENT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS FUNCTION_END- {% do { unitNameCheck $11 $4;- return $ PUFunction () (getTransSpan $1 $11) (Just $2) (None () (getSpan $1) True) $4 $5 $6 (reverse $9) $10 } }-| function NAME MAYBE_ARGUMENTS RESULT MAYBE_COMMENT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS FUNCTION_END- {% do { unitNameCheck $9 $2;- return $ PUFunction () (getTransSpan $1 $9) Nothing (None () initSrcSpan False) $2 $3 $4 (reverse $7) $8 } }-| recursive function NAME MAYBE_ARGUMENTS RESULT MAYBE_COMMENT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS FUNCTION_END+: PREFIXES function NAME MAYBE_ARGUMENTS MAYBE_RESULT MAYBE_COMMENT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS FUNCTION_END {% do { unitNameCheck $10 $3;- return $ PUFunction () (getTransSpan $1 $10) Nothing (None () initSrcSpan True) $3 $4 $5 (reverse $8) $9 } }-| subroutine NAME MAYBE_ARGUMENTS MAYBE_COMMENT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS SUBROUTINE_END- {% do { unitNameCheck $8 $2;- return $ PUSubroutine () (getTransSpan $1 $8) (None () initSrcSpan False) $2 $3 (reverse $6) $7 } }-| recursive subroutine NAME MAYBE_ARGUMENTS MAYBE_COMMENT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS SUBROUTINE_END+ let (pfxs, typeSpec) = case partitionEithers $1 of+ { (ps, t:_) -> (fromReverseList' ps, Just t)+ ; (ps, []) -> (fromReverseList' ps, Nothing) } in+ let sfx = emptySuffixes in+ let ss = if null $1 then getTransSpan $2 $10 else getTransSpan (reverse $1) $10 in+ return $ PUFunction () ss typeSpec (pfxs, sfx) $3 $4 $5 (reverse $8) $9 } }+| PREFIXES subroutine NAME MAYBE_ARGUMENTS MAYBE_COMMENT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS SUBROUTINE_END {% do { unitNameCheck $9 $3;- return $ PUSubroutine () (getTransSpan $1 $9) (None () initSrcSpan True) $3 $4 (reverse $7) $8 } }+ (pfxs, typeSpec) <- case partitionEithers $1 of+ { (ps, t:_) -> fail "Subroutines cannot have return types."+ ; (ps, []) -> return (fromReverseList' ps, Nothing) };+ let sfx = emptySuffixes in+ let ss = if null $1 then getTransSpan $2 $9 else getTransSpan (reverse $1) $9 in+ return $ PUSubroutine () ss (pfxs, sfx) $3 $4 (reverse $7) $8 } } | comment { let (TComment s c) = $1 in PUComment () s (Comment c) } +-- (Fortran2003) R1227, Fortran95/90 (...)+PREFIXES :: { [Either (Prefix A0) (TypeSpec A0)] }+: PREFIXES PREFIX { $2:$1 }+| {- EMPTY -} { [] }++-- (Fortran2003) R1228, Fortran95/90 (...)+PREFIX :: { Either (Prefix A0) (TypeSpec A0) }+: recursive { Left $ PfxRecursive () (getSpan $1) }+| TYPE_SPEC { Right $1 }++RESULT :: { Expression A0 }+: result '(' VARIABLE ')' { $3 }++MAYBE_RESULT :: { Maybe (Expression A0) }+: RESULT { Just $1 }+| {- empty -} { Nothing }+ MAYBE_ARGUMENTS :: { Maybe (AList Expression A0) } : '(' MAYBE_VARIABLES ')' { $2 } | {- Nothing -} { Nothing } -RESULT :: { Maybe (Expression a) }-: result '(' VARIABLE ')' { Just $3 }-| {- EMPTY -} { Nothing }- PROGRAM_END :: { Token } : end { $1 } | endProgram { $1 } | endProgram id { $2 } MODULE_END :: { Token }@@ -278,6 +288,8 @@ : end { $1 } | endSubroutine { $1 } | endSubroutine id { $2 } BLOCK_DATA_END :: { Token } : end { $1 } | endBlockData { $1 } | endBlockData id { $2 }+INTERFACE_END :: { Token }+: end { $1 } | endInterface { $1 } | endInterface id { $2 } NAME :: { Name } : id { let (TId _ name) = $1 in name } @@ -287,10 +299,10 @@ : INTEGER_LITERAL STATEMENT MAYBE_COMMENT NEWLINE { BlStatement () (getTransSpan $1 $2) (Just $1) $2 } | STATEMENT MAYBE_COMMENT NEWLINE { BlStatement () (getSpan $1) Nothing $1 }-| interface MAYBE_EXPRESSION NEWLINE SUBPROGRAM_UNITS2 MODULE_PROCEDURES endInterface NEWLINE- { BlInterface () (getTransSpan $1 $7) $2 $4 $5 }-| interface MAYBE_EXPRESSION NEWLINE MODULE_PROCEDURES endInterface NEWLINE- { BlInterface () (getTransSpan $1 $6) $2 [ ] $4 }+| interface MAYBE_EXPRESSION MAYBE_COMMENT NEWLINE SUBPROGRAM_UNITS2 MODULE_PROCEDURES INTERFACE_END MAYBE_COMMENT NEWLINE+ { BlInterface () (getTransSpan $1 $9) $2 False (reverse $5) (reverse $6) }+| interface MAYBE_EXPRESSION MAYBE_COMMENT NEWLINE MODULE_PROCEDURES INTERFACE_END MAYBE_COMMENT NEWLINE+ { BlInterface () (getTransSpan $1 $8) $2 False [ ] (reverse $5) } | COMMENT_BLOCK { $1 } MAYBE_EXPRESSION :: { Maybe (Expression A0) }@@ -306,13 +318,14 @@ MODULE_PROCEDURES :: { [ Block A0 ] } : MODULE_PROCEDURES MODULE_PROCEDURE { $2 : $1 }+| MODULE_PROCEDURES MODULE_PROCEDURE COMMENT_BLOCK { $3 : $2 : $1 } | { [ ] } MODULE_PROCEDURE :: { Block A0 }-: moduleProcedure VARIABLES NEWLINE+: moduleProcedure VARIABLES MAYBE_COMMENT NEWLINE { let { al = fromReverseList $2; st = StModuleProcedure () (getTransSpan $1 al) (fromReverseList $2) }- in BlStatement () (getTransSpan $1 $3) Nothing st }+ in BlStatement () (getTransSpan $1 $4) Nothing st } COMMENT_BLOCK :: { Block A0 } : comment NEWLINE { let (TComment s c) = $1 in BlComment () s (Comment c) }@@ -383,24 +396,23 @@ | common cCOMMON COMMON_GROUPS cPOP { let commonAList = fromReverseList $3 in StCommon () (getTransSpan $1 commonAList) commonAList }-| external VARIABLES- { let alist = fromReverseList $2+| external MAYBE_DCOLON VARIABLES+ { let alist = fromReverseList $3 in StExternal () (getTransSpan $1 alist) alist }-| intrinsic VARIABLES- { let alist = fromReverseList $2+| intrinsic MAYBE_DCOLON VARIABLES+ { let alist = fromReverseList $3 in StIntrinsic () (getTransSpan $1 alist) alist }-| use VARIABLE { StUse () (getTransSpan $1 $2) $2 Permissive Nothing }+| use VARIABLE { StUse () (getTransSpan $1 $2) $2 Nothing Permissive Nothing } | use VARIABLE ',' RENAME_LIST { let alist = fromReverseList $4- in StUse () (getTransSpan $1 alist) $2 Permissive (Just alist) }-| use VARIABLE ',' only ':' RENAME_LIST- { let alist = fromReverseList $6- in StUse () (getTransSpan $1 alist) $2 Exclusive (Just alist) }-| entry VARIABLE RESULT+ in StUse () (getTransSpan $1 alist) $2 Nothing Permissive (Just alist) }+| use VARIABLE ',' only ':' MAYBE_RENAME_LIST+ { StUse () (getTransSpan $1 ($5, $6)) $2 Nothing Exclusive $6 }+| entry VARIABLE MAYBE_RESULT { StEntry () (getTransSpan $1 $ maybe (getSpan $2) getSpan $3) $2 Nothing $3 }-| entry VARIABLE '(' ')' RESULT+| entry VARIABLE '(' ')' MAYBE_RESULT { StEntry () (getTransSpan $1 $ maybe (getSpan $4) getSpan $5) $2 Nothing $5 }-| entry VARIABLE '(' VARIABLES ')' RESULT+| entry VARIABLE '(' VARIABLES ')' MAYBE_RESULT { StEntry () (getTransSpan $1 $ maybe (getSpan $5) getSpan $6) $2 (Just $ fromReverseList $4) $6 } | sequence { StSequence () (getSpan $1) } | type ATTRIBUTE_LIST '::' id@@ -419,23 +431,20 @@ { let TBlob s blob = $2 in StFormatBogus () (getTransSpan $1 s) blob } EXECUTABLE_STATEMENT :: { Statement A0 }-: allocate '(' DATA_REFS ')'- { StAllocate () (getTransSpan $1 $4) (fromReverseList $3) Nothing }-| allocate '(' DATA_REFS ',' CILIST_PAIR ')'- { StAllocate () (getTransSpan $1 $6) (fromReverseList $3) (Just $5) }+: allocate '(' DATA_REFS MAYBE_ALLOC_OPT_LIST ')'+ { StAllocate () (getTransSpan $1 $5) Nothing (fromReverseList $3) $4 } | nullify '(' DATA_REFS ')' { StNullify () (getTransSpan $1 $4) (fromReverseList $3) }-| deallocate '(' DATA_REFS ')'- { StDeallocate () (getTransSpan $1 $4) (fromReverseList $3) Nothing }-| deallocate '(' DATA_REFS ',' CILIST_PAIR ')'- { StDeallocate () (getTransSpan $1 $6) (fromReverseList $3) (Just $5) }+| deallocate '(' DATA_REFS MAYBE_ALLOC_OPT_LIST ')'+ { StDeallocate () (getTransSpan $1 $5) (fromReverseList $3) $4 } | EXPRESSION_ASSIGNMENT_STATEMENT { $1 } | DATA_REF '=>' EXPRESSION { StPointerAssign () (getTransSpan $1 $3) $1 $3 } | where '(' EXPRESSION ')' EXPRESSION_ASSIGNMENT_STATEMENT { StWhere () (getTransSpan $1 $5) $3 $5 }-| where '(' EXPRESSION ')' { StWhereConstruct () (getTransSpan $1 $4) $3 }-| elsewhere { StElsewhere () (getSpan $1) }-| endwhere { StEndWhere () (getSpan $1) }+| where '(' EXPRESSION ')' { StWhereConstruct () (getTransSpan $1 $4) Nothing $3 }+| elsewhere '(' EXPRESSION ')' { StElsewhere () (getTransSpan $1 $4) Nothing (Just $3) }+| elsewhere { StElsewhere () (getSpan $1) Nothing Nothing }+| endwhere { StEndWhere () (getSpan $1) Nothing } | if '(' EXPRESSION ')' INTEGER_LITERAL ',' INTEGER_LITERAL ',' INTEGER_LITERAL { StIfArithmetic () (getTransSpan $1 $9) $3 $5 $7 $9 } | if '(' EXPRESSION ')' then { StIfThen () (getTransSpan $1 $5) Nothing $3 }@@ -550,6 +559,10 @@ | EXPRESSION { Argument () (getSpan $1) Nothing $1 } +MAYBE_RENAME_LIST :: { Maybe (AList Use A0) }+: RENAME_LIST { Just $ fromReverseList $1 }+| {- empty -} { Nothing }+ RENAME_LIST :: { [ Use A0 ] } : RENAME_LIST ',' RENAME { $3 : $1 } | RENAME { [ $1 ] }@@ -557,6 +570,10 @@ RENAME :: { Use A0 } : VARIABLE '=>' VARIABLE { UseRename () (getTransSpan $1 $3) $1 $3 } | VARIABLE { UseID () (getSpan $1) $1 }+| operator '(' opCustom ')'+ { let TOpCustom ss op = $3+ in UseID () (getTransSpan $1 $4) (ExpValue () ss (ValOperator op)) }+| assignment { UseID () (getSpan $1) (ExpValue () (getSpan $1) ValAssignment) } MAYBE_DCOLON :: { () } : '::' { () } | {- EMPTY -} { () } @@ -643,6 +660,10 @@ | STRING { $1 } | DATA_REF { $1 } +MAYBE_ALLOC_OPT_LIST :: { Maybe (AList AllocOpt A0) }+: ',' stat '=' EXPRESSION { Just (fromReverseList [AOStat () (getTransSpan $2 $4) $4]) }+| {- empty -} { Nothing }+ IN_IOLIST :: { [ Expression A0 ] } : IN_IOLIST ',' IN_IO_ELEMENT { $3 : $1} | IN_IO_ELEMENT { [ $1 ] }@@ -755,7 +776,7 @@ | private { AttrPrivate () (getSpan $1) } | allocatable { AttrAllocatable () (getSpan $1) } | dimension '(' DIMENSION_DECLARATORS ')'- { AttrDimension () (getTransSpan $1 $4) $3 }+ { AttrDimension () (getTransSpan $1 $4) (aReverse $3) } | external { AttrExternal () (getSpan $1) } | intent '(' INTENT_CHOICE ')' { AttrIntent () (getTransSpan $1 $4) $3 } | intrinsic { AttrIntrinsic () (getSpan $1) }@@ -811,12 +832,12 @@ { let star = ExpValue () (getSpan $4) ValStar in DeclVariable () (getTransSpan $1 $5) $1 (Just star) Nothing } | VARIABLE '(' DIMENSION_DECLARATORS ')'- { DeclArray () (getTransSpan $1 $4) $1 $3 Nothing Nothing }+ { DeclArray () (getTransSpan $1 $4) $1 (aReverse $3) Nothing Nothing } | VARIABLE '(' DIMENSION_DECLARATORS ')' '*' EXPRESSION- { DeclArray () (getTransSpan $1 $6) $1 $3 (Just $6) Nothing }+ { DeclArray () (getTransSpan $1 $6) $1 (aReverse $3) (Just $6) Nothing } | VARIABLE '(' DIMENSION_DECLARATORS ')' '*' '(' '*' ')' { let star = ExpValue () (getSpan $7) ValStar- in DeclArray () (getTransSpan $1 $8) $1 $3 (Just star) Nothing }+ in DeclArray () (getTransSpan $1 $8) $1 (aReverse $3) (Just star) Nothing } DIMENSION_DECLARATORS :: { AList DimensionDeclarator A0 } : DIMENSION_DECLARATORS ',' DIMENSION_DECLARATOR@@ -848,7 +869,7 @@ | 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 }+| character CHAR_SELECTOR { TypeSpec () (getSpan ($1, $2)) (uncurry TypeCharacter $ charLenSelector $2) $2 } | logical KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeLogical $2 } | type '(' id ')' { let TId _ id = $3@@ -859,6 +880,8 @@ { Just $ Selector () (getTransSpan $1 $3) Nothing (Just $2) } | '(' kind '=' EXPRESSION ')' { Just $ Selector () (getTransSpan $1 $5) Nothing (Just $4) }+| '*' EXPRESSION -- non-standard but commonly used extension+ { Just $ Selector () (getTransSpan $1 $2) Nothing (Just $2) } | {- EMPTY -} { Nothing } CHAR_SELECTOR :: { Maybe (Selector A0) }@@ -874,6 +897,8 @@ { Just $ Selector () (getTransSpan $1 $3) (Just $2) Nothing } | '(' len '=' LEN_EXPRESSION ')' { Just $ Selector () (getTransSpan $1 $5) (Just $4) Nothing }+| '(' kind '=' EXPRESSION ')'+ { Just $ Selector () (getTransSpan $1 $5) Nothing (Just $4) } | '(' LEN_EXPRESSION ',' EXPRESSION ')' { Just $ Selector () (getTransSpan $1 $5) (Just $2) (Just $4) } | '(' LEN_EXPRESSION ',' kind '=' EXPRESSION ')'
src/Language/Fortran/Parser/Fortran95.y view
@@ -10,7 +10,7 @@ import Control.Monad.State import Data.Maybe (fromMaybe, isJust) import Data.List (nub)-import Data.Either (either, lefts, rights)+import Data.Either (either, lefts, rights, partitionEithers) import Control.Applicative import qualified Data.ByteString.Char8 as B @@ -31,7 +31,7 @@ %name programParser PROGRAM %name statementParser STATEMENT-%name functionParser SUBPROGRAM_UNIT +%name functionParser SUBPROGRAM_UNIT %monad { LexAction } %lexer { lexer } { TEOF _ } %tokentype { Token }@@ -114,6 +114,8 @@ pointer { TPointer _ } save { TSave _ } target { TTarget _ }+ value { TValue _ }+ volatile { TVolatile _ } in { TIn _ } out { TOut _ } inout { TInOut _ }@@ -123,6 +125,7 @@ equivalence { TEquivalence _ } common { TCommon _ } allocate { TAllocate _ }+ stat { TStat _ } deallocate { TDeallocate _ } nullify { TNullify _ } none { TNone _ }@@ -240,68 +243,51 @@ | {- EMPTY -} { [ ] } SUBPROGRAM_UNIT :: { ProgramUnit A0 }-: FUNCTION_SPEC function NAME MAYBE_ARGUMENTS MAYBE_COMMENT RESULT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS FUNCTION_END+: PREFIXES function NAME MAYBE_ARGUMENTS MAYBE_RESULT MAYBE_COMMENT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS FUNCTION_END {% do { unitNameCheck $10 $3;- let (fSpec, typeSpec) = $1 in- return $ PUFunction () (getTransSpan $2 $10) typeSpec fSpec $3 $4 $6 (reverse $8) $9 } }-| FUNCTION_SPEC subroutine NAME MAYBE_ARGUMENTS MAYBE_COMMENT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS SUBROUTINE_END+ let (pfxs, typeSpec) = case partitionEithers $1 of+ { (ps, t:_) -> (fromReverseList' ps, Just t)+ ; (ps, []) -> (fromReverseList' ps, Nothing) } in+ let sfx = emptySuffixes in+ let ss = if null $1 then getTransSpan $2 $10 else getTransSpan (reverse $1) $10 in+ if validPrefixSuffix (pfxs, sfx) then+ return $ PUFunction () ss typeSpec (pfxs, sfx) $3 $4 $5 (reverse $8) $9+ else fail "Cannot specify elemental along with recursive." } }+| PREFIXES subroutine NAME MAYBE_ARGUMENTS MAYBE_COMMENT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS SUBROUTINE_END {% do { unitNameCheck $9 $3;- let (fSpec, _) = $1 in- return $ PUSubroutine () (getTransSpan $2 $9) fSpec $3 $4 (reverse $7) $8 } }+ (pfxs, typeSpec) <- case partitionEithers $1 of+ { (ps, t:_) -> fail "Subroutines cannot have return types."+ ; (ps, []) -> return (fromReverseList' ps, Nothing) };+ let sfx = emptySuffixes in+ let ss = if null $1 then getTransSpan $2 $9 else getTransSpan (reverse $1) $9 in+ if validPrefixSuffix (pfxs, sfx) then+ return $ PUSubroutine () ss (pfxs, sfx) $3 $4 (reverse $7) $8+ else fail "Cannot specify elemental along with recursive." } } | comment { let (TComment s c) = $1 in PUComment () s (Comment c) }-| recursive RECURSIVE_SUBPROGRAM_UNIT { setSpan (getTransSpan $1 $2) $2 } -RECURSIVE_SUBPROGRAM_UNIT :: { ProgramUnit A0 }-: FUNCTION_SPEC function NAME MAYBE_ARGUMENTS MAYBE_COMMENT RESULT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS FUNCTION_END- {% do- unitNameCheck $10 $3- fSpec <- either fail return $ fst $1 `buildPUFunctionOpt` None () (getSpan $ fst $1) True- let typeSpec = snd $1- return $ PUFunction () (getTransSpan $2 $10) typeSpec fSpec $3 $4 $6 (reverse $8) $9- }-| FUNCTION_SPEC subroutine NAME MAYBE_ARGUMENTS MAYBE_COMMENT NEWLINE BLOCKS MAYBE_SUBPROGRAM_UNITS SUBROUTINE_END- {% do- unitNameCheck $9 $3- fSpec <- either fail return $ fst $1 `buildPUFunctionOpt` None () (getSpan $ fst $1) True- return $ PUSubroutine () (getTransSpan $2 $9) fSpec $3 $4 (reverse $7) $8- }---FUNCTION_SPEC :: { (PUFunctionOpt A0, Maybe (TypeSpec A0)) }-: PFUNCTION_SPECS {% do- let funcSpecs = lefts $1- let typeSpecs = rights $1- if length typeSpecs > 1- then fail "Specified a type spec multiple times in a function spec."- else if length (nub funcSpecs) /= length funcSpecs then fail "Specified a function spec multiple times."- else do- let typeSpec = case typeSpecs of- [] -> Nothing- (x:_) -> Just x- funcSpec <- either fail return $ buildPUFunctionOpts funcSpecs- return (funcSpec, typeSpec)- }+-- (Fortran2003) R1227, Fortran95 (...)+PREFIXES :: { [Either (Prefix A0) (TypeSpec A0)] }+: PREFIXES PREFIX { $2:$1 }+| {- EMPTY -} { [] } -PFUNCTION_SPECS :: { [Either (PUFunctionOpt A0) (TypeSpec A0)] }-: {- EMPTY -} { [] }-| PFUNCTION_SPEC PFUNCTION_SPECS { $1 : $2 }+-- (Fortran2003) R1228, Fortran95 (...)+PREFIX :: { Either (Prefix A0) (TypeSpec A0) }+: recursive { Left $ PfxRecursive () (getSpan $1) }+| elemental { Left $ PfxElemental () (getSpan $1) }+| pure { Left $ PfxPure () (getSpan $1) }+| TYPE_SPEC { Right $1 } --- crucically, recursive cannot appear first, which is dealt with in SUBPROGRAM_UNIT-| PFUNCTION_SPEC recursive PFUNCTION_SPECS { $1 : Left (None () (getSpan $2) True) : $3 }+RESULT :: { Expression A0 }+: result '(' VARIABLE ')' { $3 } -PFUNCTION_SPEC :: { Either (PUFunctionOpt A0) (TypeSpec A0) }-: pure { Left $ Pure () (getSpan $1) False }-| elemental { Left $ Elemental () (getSpan $1) }-| TYPE_SPEC { Right $ $1 }+MAYBE_RESULT :: { Maybe (Expression A0) }+: RESULT { Just $1 }+| {- empty -} { Nothing} MAYBE_ARGUMENTS :: { Maybe (AList Expression A0) } : '(' MAYBE_VARIABLES ')' { $2 } | {- Nothing -} { Nothing } -RESULT :: { Maybe (Expression a) }-: result '(' VARIABLE ')' { Just $3 }-| {- EMPTY -} { Nothing }- PROGRAM_END :: { Token } : end { $1 } | endProgram { $1 } | endProgram id { $2 } MODULE_END :: { Token }@@ -312,6 +298,8 @@ : end { $1 } | endSubroutine { $1 } | endSubroutine id { $2 } BLOCK_DATA_END :: { Token } : end { $1 } | endBlockData { $1 } | endBlockData id { $2 }+INTERFACE_END :: { Token }+: end { $1 } | endInterface { $1 } | endInterface id { $2 } NAME :: { Name } : id { let (TId _ name) = $1 in name } @@ -321,10 +309,10 @@ : INTEGER_LITERAL STATEMENT MAYBE_COMMENT NEWLINE { BlStatement () (getTransSpan $1 $2) (Just $1) $2 } | STATEMENT MAYBE_COMMENT NEWLINE { BlStatement () (getSpan $1) Nothing $1 }-| interface MAYBE_EXPRESSION NEWLINE SUBPROGRAM_UNITS2 MODULE_PROCEDURES endInterface NEWLINE- { BlInterface () (getTransSpan $1 $7) $2 $4 $5 }-| interface MAYBE_EXPRESSION NEWLINE MODULE_PROCEDURES endInterface NEWLINE- { BlInterface () (getTransSpan $1 $6) $2 [ ] $4 }+| interface MAYBE_EXPRESSION MAYBE_COMMENT NEWLINE SUBPROGRAM_UNITS2 MODULE_PROCEDURES INTERFACE_END MAYBE_COMMENT NEWLINE+ { BlInterface () (getTransSpan $1 $9) $2 False (reverse $5) (reverse $6) }+| interface MAYBE_EXPRESSION MAYBE_COMMENT NEWLINE MODULE_PROCEDURES INTERFACE_END MAYBE_COMMENT NEWLINE+ { BlInterface () (getTransSpan $1 $8) $2 False [ ] (reverse $5) } | COMMENT_BLOCK { $1 } MAYBE_EXPRESSION :: { Maybe (Expression A0) }@@ -340,13 +328,14 @@ MODULE_PROCEDURES :: { [ Block A0 ] } : MODULE_PROCEDURES MODULE_PROCEDURE { $2 : $1 }+| MODULE_PROCEDURES MODULE_PROCEDURE COMMENT_BLOCK { $3 : $2 : $1 } | { [ ] } MODULE_PROCEDURE :: { Block A0 }-: moduleProcedure VARIABLES NEWLINE+: moduleProcedure VARIABLES MAYBE_COMMENT NEWLINE { let { al = fromReverseList $2; st = StModuleProcedure () (getTransSpan $1 al) (fromReverseList $2) }- in BlStatement () (getTransSpan $1 $3) Nothing st }+ in BlStatement () (getTransSpan $1 $4) Nothing st } COMMENT_BLOCK :: { Block A0 } : comment NEWLINE { let (TComment s c) = $1 in BlComment () s (Comment c) }@@ -398,6 +387,12 @@ | target MAYBE_DCOLON DECLARATOR_LIST { let declAList = fromReverseList $3 in StTarget () (getTransSpan $1 declAList) declAList }+| value MAYBE_DCOLON DECLARATOR_LIST+ { let declAList = fromReverseList $3+ in StValue () (getTransSpan $1 declAList) declAList }+| volatile MAYBE_DCOLON DECLARATOR_LIST+ { let declAList = fromReverseList $3+ in StVolatile () (getTransSpan $1 declAList) declAList } | data cDATA DATA_GROUPS cPOP { let dataAList = fromReverseList $3 in StData () (getTransSpan $1 dataAList) dataAList }@@ -417,24 +412,23 @@ | common cCOMMON COMMON_GROUPS cPOP { let commonAList = fromReverseList $3 in StCommon () (getTransSpan $1 commonAList) commonAList }-| external VARIABLES- { let alist = fromReverseList $2+| external MAYBE_DCOLON VARIABLES+ { let alist = fromReverseList $3 in StExternal () (getTransSpan $1 alist) alist }-| intrinsic VARIABLES- { let alist = fromReverseList $2+| intrinsic MAYBE_DCOLON VARIABLES+ { let alist = fromReverseList $3 in StIntrinsic () (getTransSpan $1 alist) alist }-| use VARIABLE { StUse () (getTransSpan $1 $2) $2 Permissive Nothing }+| use VARIABLE { StUse () (getTransSpan $1 $2) $2 Nothing Permissive Nothing } | use VARIABLE ',' RENAME_LIST { let alist = fromReverseList $4- in StUse () (getTransSpan $1 alist) $2 Permissive (Just alist) }-| use VARIABLE ',' only ':' RENAME_LIST- { let alist = fromReverseList $6- in StUse () (getTransSpan $1 alist) $2 Exclusive (Just alist) }-| entry VARIABLE RESULT+ in StUse () (getTransSpan $1 alist) $2 Nothing Permissive (Just alist) }+| use VARIABLE ',' only ':' MAYBE_RENAME_LIST+ { StUse () (getTransSpan $1 ($5, $6)) $2 Nothing Exclusive $6 }+| entry VARIABLE MAYBE_RESULT { StEntry () (getTransSpan $1 $ maybe (getSpan $2) getSpan $3) $2 Nothing $3 }-| entry VARIABLE '(' ')' RESULT+| entry VARIABLE '(' ')' MAYBE_RESULT { StEntry () (getTransSpan $1 $ maybe (getSpan $4) getSpan $5) $2 Nothing $5 }-| entry VARIABLE '(' VARIABLES ')' RESULT+| entry VARIABLE '(' VARIABLES ')' MAYBE_RESULT { StEntry () (getTransSpan $1 $ maybe (getSpan $5) getSpan $6) $2 (Just $ fromReverseList $4) $6 } | sequence { StSequence () (getSpan $1) } | type ATTRIBUTE_LIST '::' id@@ -453,23 +447,20 @@ { let TBlob s blob = $2 in StFormatBogus () (getTransSpan $1 s) blob } EXECUTABLE_STATEMENT :: { Statement A0 }-: allocate '(' DATA_REFS ')'- { StAllocate () (getTransSpan $1 $4) (fromReverseList $3) Nothing }-| allocate '(' DATA_REFS ',' CILIST_PAIR ')'- { StAllocate () (getTransSpan $1 $6) (fromReverseList $3) (Just $5) }+: allocate '(' DATA_REFS MAYBE_ALLOC_OPT_LIST ')'+ { StAllocate () (getTransSpan $1 $5) Nothing (fromReverseList $3) $4 } | nullify '(' DATA_REFS ')' { StNullify () (getTransSpan $1 $4) (fromReverseList $3) }-| deallocate '(' DATA_REFS ')'- { StDeallocate () (getTransSpan $1 $4) (fromReverseList $3) Nothing }-| deallocate '(' DATA_REFS ',' CILIST_PAIR ')'- { StDeallocate () (getTransSpan $1 $6) (fromReverseList $3) (Just $5) }+| deallocate '(' DATA_REFS MAYBE_ALLOC_OPT_LIST ')'+ { StDeallocate () (getTransSpan $1 $5) (fromReverseList $3) $4 } | EXPRESSION_ASSIGNMENT_STATEMENT { $1 } | POINTER_ASSIGNMENT_STMT { $1 } | where '(' EXPRESSION ')' EXPRESSION_ASSIGNMENT_STATEMENT { StWhere () (getTransSpan $1 $5) $3 $5 }-| where '(' EXPRESSION ')' { StWhereConstruct () (getTransSpan $1 $4) $3 }-| elsewhere { StElsewhere () (getSpan $1) }-| endwhere { StEndWhere () (getSpan $1) }+| where '(' EXPRESSION ')' { StWhereConstruct () (getTransSpan $1 $4) Nothing $3 }+| elsewhere '(' EXPRESSION ')' { StElsewhere () (getTransSpan $1 $4) Nothing (Just $3) }+| elsewhere { StElsewhere () (getSpan $1) Nothing Nothing }+| endwhere { StEndWhere () (getSpan $1) Nothing } | if '(' EXPRESSION ')' INTEGER_LITERAL ',' INTEGER_LITERAL ',' INTEGER_LITERAL { StIfArithmetic () (getTransSpan $1 $9) $3 $5 $7 $9 } | if '(' EXPRESSION ')' then { StIfThen () (getTransSpan $1 $5) Nothing $3 }@@ -577,6 +568,10 @@ | EXPRESSION { Argument () (getSpan $1) Nothing $1 } +MAYBE_RENAME_LIST :: { Maybe (AList Use A0) }+: RENAME_LIST { Just $ fromReverseList $1 }+| {- empty -} { Nothing }+ RENAME_LIST :: { [ Use A0 ] } : RENAME_LIST ',' RENAME { $3 : $1 } | RENAME { [ $1 ] }@@ -584,6 +579,10 @@ RENAME :: { Use A0 } : VARIABLE '=>' VARIABLE { UseRename () (getTransSpan $1 $3) $1 $3 } | VARIABLE { UseID () (getSpan $1) $1 }+| operator '(' opCustom ')'+ { let TOpCustom ss op = $3+ in UseID () (getTransSpan $1 $4) (ExpValue () ss (ValOperator op)) }+| assignment { UseID () (getSpan $1) (ExpValue () (getSpan $1) ValAssignment) } MAYBE_DCOLON :: { () } : '::' { () } | {- EMPTY -} { () } @@ -670,6 +669,11 @@ | STRING { $1 } | DATA_REF { $1 } +{- p67 ALLOCATE statement -}+MAYBE_ALLOC_OPT_LIST :: { Maybe (AList AllocOpt A0) }+: ',' stat '=' EXPRESSION { Just (fromReverseList [AOStat () (getTransSpan $2 $4) $4]) }+| {- empty -} { Nothing }+ IN_IOLIST :: { [ Expression A0 ] } : IN_IOLIST ',' IN_IO_ELEMENT { $3 : $1} | IN_IO_ELEMENT { [ $1 ] }@@ -782,7 +786,7 @@ | private { AttrPrivate () (getSpan $1) } | allocatable { AttrAllocatable () (getSpan $1) } | dimension '(' DIMENSION_DECLARATORS ')'- { AttrDimension () (getTransSpan $1 $4) $3 }+ { AttrDimension () (getTransSpan $1 $4) (aReverse $3) } | external { AttrExternal () (getSpan $1) } | intent '(' INTENT_CHOICE ')' { AttrIntent () (getTransSpan $1 $4) $3 } | intrinsic { AttrIntrinsic () (getSpan $1) }@@ -791,6 +795,8 @@ | parameter { AttrParameter () (getSpan $1) } | save { AttrSave () (getSpan $1) } | target { AttrTarget () (getSpan $1) }+| value { AttrValue () (getSpan $1) }+| volatile { AttrVolatile () (getSpan $1) } INTENT_CHOICE :: { Intent } : in { In } | out { Out } | inout { InOut } @@ -838,12 +844,12 @@ { let star = ExpValue () (getSpan $4) ValStar in DeclVariable () (getTransSpan $1 $5) $1 (Just star) Nothing } | VARIABLE '(' DIMENSION_DECLARATORS ')'- { DeclArray () (getTransSpan $1 $4) $1 $3 Nothing Nothing }+ { DeclArray () (getTransSpan $1 $4) $1 (aReverse $3) Nothing Nothing } | VARIABLE '(' DIMENSION_DECLARATORS ')' '*' EXPRESSION- { DeclArray () (getTransSpan $1 $6) $1 $3 (Just $6) Nothing }+ { DeclArray () (getTransSpan $1 $6) $1 (aReverse $3) (Just $6) Nothing } | VARIABLE '(' DIMENSION_DECLARATORS ')' '*' '(' '*' ')' { let star = ExpValue () (getSpan $7) ValStar- in DeclArray () (getTransSpan $1 $8) $1 $3 (Just star) Nothing }+ in DeclArray () (getTransSpan $1 $8) $1 (aReverse $3) (Just star) Nothing } DIMENSION_DECLARATORS :: { AList DimensionDeclarator A0 } : DIMENSION_DECLARATORS ',' DIMENSION_DECLARATOR@@ -875,7 +881,7 @@ | 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 }+| character CHAR_SELECTOR { TypeSpec () (getSpan ($1, $2)) (uncurry TypeCharacter $ charLenSelector $2) $2 } | logical KIND_SELECTOR { TypeSpec () (getSpan ($1, $2)) TypeLogical $2 } | type '(' id ')' { let TId _ id = $3@@ -886,6 +892,8 @@ { Just $ Selector () (getTransSpan $1 $3) Nothing (Just $2) } | '(' kind '=' EXPRESSION ')' { Just $ Selector () (getTransSpan $1 $5) Nothing (Just $4) }+| '*' EXPRESSION -- non-standard but commonly used extension+ { Just $ Selector () (getTransSpan $1 $2) Nothing (Just $2) } | {- EMPTY -} { Nothing } CHAR_SELECTOR :: { Maybe (Selector A0) }@@ -901,6 +909,8 @@ { Just $ Selector () (getTransSpan $1 $3) (Just $2) Nothing } | '(' len '=' LEN_EXPRESSION ')' { Just $ Selector () (getTransSpan $1 $5) (Just $4) Nothing }+| '(' kind '=' EXPRESSION ')'+ { Just $ Selector () (getTransSpan $1 $5) Nothing (Just $4) } | '(' LEN_EXPRESSION ',' EXPRESSION ')' { Just $ Selector () (getTransSpan $1 $5) (Just $2) (Just $4) } | '(' LEN_EXPRESSION ',' kind '=' EXPRESSION ')'
src/Language/Fortran/Parser/Utils.hs view
@@ -3,6 +3,13 @@ import Data.Char import Numeric +breakAtDot :: String -> (String, String)+replaceDwithE :: Char -> Char+readsToMaybe :: [(a, b)] -> Maybe a+fixAtDot :: (String, String) -> (String, String)+fixAtDot' :: (String, String) -> (String, String)+combineAtDot :: (String, String) -> String+ -- | Convert a Fortran literal Real into a Haskell Double. readReal :: String -> Maybe Double readReal = readsToMaybe . reads . filter (/= '+') . combineAtDot . fixAtDot . breakAtDot . map replaceDwithE . takeWhile (/= '_')
src/Language/Fortran/ParserMonad.hs view
@@ -11,13 +11,15 @@ import GHC.IO.Exception import Control.Exception -import Control.Monad.State+import Control.Monad.State hiding (state) import Control.Monad.Except import Data.Typeable import Data.Data import GHC.Generics (Generic) import Language.Fortran.Util.Position+import Data.Char (toLower)+import Data.List (isInfixOf, find) ------------------------------------------------------------------------------- -- Helper datatype definitions@@ -43,6 +45,19 @@ show Fortran2003 = "Fortran 2003" show Fortran2008 = "Fortran 2008" +fortranVersionAliases :: [(String, FortranVersion)]+fortranVersionAliases = [ ("66" , Fortran66)+ , ("77e", Fortran77Extended)+ , ("77l", Fortran77Legacy)+ , ("77" , Fortran77)+ , ("90" , Fortran90)+ , ("95" , Fortran95)+ , ("03" , Fortran2003)+ , ("08" , Fortran2008) ]++selectFortranVersion :: String -> Maybe FortranVersion+selectFortranVersion alias = snd <$> find (\ entry -> fst entry `isInfixOf` map toLower alias) fortranVersionAliases+ data ParanthesesCount = ParanthesesCount { pcActual :: Integer , pcHasReached0 :: Bool }@@ -77,12 +92,13 @@ where lastTokenMsg = tokenMsg (errLastToken err) +tokenMsg :: Show a => Maybe a -> String tokenMsg (Just a) = "Last parsed token: " ++ show a ++ "." tokenMsg Nothing = "No token had been lexed." instance Functor (ParseResult b c) where fmap f (ParseOk a s) = ParseOk (f a) s- fmap f (ParseFailed err) = ParseFailed err+ fmap _ (ParseFailed err) = ParseFailed err instance (Typeable a, Typeable b, Show a, Show b) => Exception (ParseError a b) @@ -106,10 +122,10 @@ fromParseResult :: (Show c) => ParseResult b c a -> Either ParseErrorSimple a fromParseResult (ParseOk a _) = Right a fromParseResult (ParseFailed err) =- Left $ ParseErrorSimple+ Left ParseErrorSimple { errorPos = errPos err , errorFilename = errFilename err- , errorMsg = errMsg err ++ "\n" ++ (tokenMsg $ errLastToken err) }+ , errorMsg = errMsg err ++ "\n" ++ tokenMsg (errLastToken err) } instance Show ParseErrorSimple where show err = errorFilename err ++ ", " ++ show (errorPos err) ++ ": " ++ errorMsg err@@ -221,7 +237,8 @@ -- Generic token collection and functions ------------------------------------------------------------------------------- -throwIOerror s = throw $+throwIOerror :: String -> a+throwIOerror s = throw IOError { ioe_handle = Nothing , ioe_type = UserError , ioe_location = "fortran-src"@@ -230,7 +247,7 @@ , ioe_filename = Nothing } runParse :: (Loc b, LastToken b c, Show c) => Parse b c a -> ParseState b -> ParseResult b c a-runParse lexer initState = unParse lexer initState+runParse = unParse runParseUnsafe :: (Loc b, LastToken b c, Show c) => Parse b c a -> ParseState b -> (a, ParseState b) runParseUnsafe lexer initState =
src/Language/Fortran/PrettyPrint.hs view
@@ -2,13 +2,14 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -Wno-orphans #-} module Language.Fortran.PrettyPrint where -import Data.Maybe (isJust, isNothing)+import Data.Maybe (isJust, isNothing, listToMaybe) import Data.List (foldl') -import Prelude hiding (EQ,LT,GT,(<>))+import Prelude hiding (EQ,LT,GT,pred,exp,(<>)) import Language.Fortran.AST import Language.Fortran.ParserMonad@@ -45,8 +46,10 @@ overlay top bottom = text $ top' ++ drop (length top') (render bottom) where top' = render top +fixedForm :: Maybe Int fixedForm = Just 6 +pprintAndRender :: IndentablePretty t => FortranVersion -> t -> Indentation -> String pprintAndRender v t i = render $ pprint v t i class IndentablePretty t where@@ -108,61 +111,83 @@ where nextI = incIndentation i - pprint v (PUSubroutine _ _ funcSpec name mArgs body mSubs) i- | Pure _ _ _ <- funcSpec, v < Fortran95 = tooOld v "Pure subroutine" Fortran90- | Elemental _ _ <- funcSpec, v < Fortran90 = tooOld v "Elemental subroutine" Fortran90- | functionIsRecursive funcSpec, v < Fortran90 = tooOld v "Recursive subroutine" Fortran90- | isJust mSubs, v < Fortran90 = tooOld v "Subroutine subprogram" Fortran90- | otherwise =+ pprint v (PUSubroutine _ _ (mpfxs, msfxs) name mArgs body mSubs) i = indent curI- ((case funcSpec of- (Elemental _ _) -> "elemental"- (Pure _ _ _) -> "pure"- otherwise -> empty) <+>- (if functionIsRecursive funcSpec then "recursive" else empty) <+>- "subroutine" <+> text name <>- lparen <?> pprint' v mArgs <?> rparen <> newline) <>+ (prefix <+> "subroutine" <+> text name <>+ lparen <?> pprint' v mArgs <?> rparen <+> suffix <> newline) <> pprint v body nextI <> newline <?> indent nextI ("contains" <> newline) <?> newline <?>- pprint v mSubs nextI <>+ subs <> endGen v "subroutine" name curI- where- curI = if v >= Fortran90 then i else fixedForm- nextI = if v >= Fortran90- then incIndentation i- else incIndentation fixedForm+ where+ convPfx (PfxElemental _ _)+ | v >= Fortran95 = "elemental"+ | otherwise = tooOld v "Elemental function" Fortran95+ convPfx (PfxPure _ _)+ | v >= Fortran95 = "pure"+ | otherwise = tooOld v "Pure function" Fortran95+ convPfx (PfxRecursive _ _)+ | v >= Fortran90 = "recursive"+ | otherwise = tooOld v "Recursive function" Fortran90 - pprint v (PUFunction _ _ mRetType fSpec name mArgs mRes body mSubs) i- | (Elemental _ _) <- fSpec, v < Fortran95 = tooOld v "Elemental function" Fortran90- | (Pure _ _ _) <- fSpec, v < Fortran95 = tooOld v "Pure function" Fortran90- | functionIsRecursive fSpec, v < Fortran90 = tooOld v "Recursive function" Fortran90- | isJust mRes, v < Fortran90 = tooOld v "Function result" Fortran90- | isJust mSubs, v < Fortran90 = tooOld v "Function subprogram" Fortran90- | otherwise =+ prefix = hsep (map convPfx pfxs)++ suffix = pprint' v (listToMaybe sfxs)++ subs+ | isJust mSubs, v >= Fortran90 = pprint v mSubs nextI+ | isNothing mSubs = empty+ | otherwise = tooOld v "Function subprogram" Fortran90++ curI = if v >= Fortran90 then i else fixedForm+ nextI = if v >= Fortran90 then incIndentation i+ else incIndentation fixedForm+ pfxs = aStrip' mpfxs+ sfxs = aStrip' msfxs++ pprint v (PUFunction _ _ mRetType (mpfxs, msfxs) name mArgs mRes body mSubs) i = indent curI- (pprint' v mRetType <+>- (case fSpec of- (Elemental _ _) -> "elemental"- (Pure _ _ _) -> "pure"- otherwise -> empty) <+>- (if functionIsRecursive fSpec then "recursive" else empty) <+>- "function" <+> text name <>- lparen <?> pprint' v mArgs <?> rparen <+>- "result" <?> lparen <?> pprint' v mRes <?> rparen <> newline) <>+ (prefix <+> "function" <+> text name <>+ parens (pprint' v mArgs) <+> suffix <> newline) <> pprint v body nextI <> newline <?> indent nextI ("contains" <> newline) <?> newline <?>- pprint v mSubs nextI <>+ subs <> endGen v "function" name curI- where- curI = if v >= Fortran90 then i else fixedForm- nextI = if v >= Fortran90- then incIndentation i- else incIndentation fixedForm+ where+ convPfx (PfxElemental _ _)+ | v >= Fortran95 = "elemental"+ | otherwise = tooOld v "Elemental function" Fortran95+ convPfx (PfxPure _ _)+ | v >= Fortran95 = "pure"+ | otherwise = tooOld v "Pure function" Fortran95+ convPfx (PfxRecursive _ _)+ | v >= Fortran90 = "recursive"+ | otherwise = tooOld v "Recursive function" Fortran90 + prefix = hsep (pprint' v mRetType:map convPfx pfxs)++ result+ | isJust mRes, v >= Fortran90 = "result" <?> lparen <?> pprint' v mRes <?> rparen+ | isNothing mRes = empty+ | otherwise = tooOld v "Function result" Fortran90++ suffix = result <+> pprint' v (listToMaybe sfxs)++ subs+ | isJust mSubs, v >= Fortran90 = pprint v mSubs nextI+ | isNothing mSubs = empty+ | otherwise = tooOld v "Function subprogram" Fortran90++ curI = if v >= Fortran90 then i else fixedForm+ nextI = if v >= Fortran90 then incIndentation i+ else incIndentation fixedForm+ pfxs = aStrip' mpfxs+ sfxs = aStrip' msfxs+ pprint v (PUBlockData _ _ mName body) i | v < Fortran77, isJust mName = tooOld v "Named block data" Fortran77 | otherwise =@@ -191,6 +216,15 @@ pprint v bs i = foldl' (\b a -> b <> pprint v a i) empty bs instance IndentablePretty (Block a) where+ pprint v (BlForall _ _ mLabel mName _ body mel) i =+ labeledIndent mLabel (pprint' v mName) <> newline <>+ pprint v body nextI <>+ labeledIndent mel ("end forall" <+> pprint' v mName <> newline)+ where+ nextI = incIndentation i+ labeledIndent label stDoc =+ pprint' v label `overlay` indent i stDoc+ pprint v (BlStatement _ _ mLabel st) i = if v >= Fortran90 then indent i (pprint' v mLabel <+> pprint' v st <> newline)@@ -234,14 +268,14 @@ indent nextI ("case" <+> case mRanges of {- Just ranges -> parens (pprint' v ranges);+ Just ranges' -> parens (pprint' v ranges'); Nothing -> "default" } <> newline) <> pprint v block (incIndentation nextI) nextI = incIndentation i - pprint v (BlInterface _ _ mLabel pus moduleProcs) i+ pprint v (BlInterface _ _ mLabel abstractp pus moduleProcs) i | v >= Fortran90 =- indent i (pprint' v mLabel <+> "interface" <> newline) <>+ indent i (abstract <> "interface" <+> pprint' v mLabel <> newline) <> pprint v pus nextI <> newline <> pprint v moduleProcs nextI <>@@ -249,6 +283,8 @@ | otherwise = tooOld v "Interface" Fortran90 where nextI = incIndentation i+ abstract | v >= Fortran2003 && abstractp = "abstract "+ | otherwise = empty pprint v (BlDo _ _ mLabel mn tl doSpec body el) i | v >= Fortran77Extended =@@ -299,7 +335,7 @@ pprint' :: FortranVersion -> t -> Doc instance Pretty a => Pretty (Maybe a) where- pprint' v Nothing = empty+ pprint' _ Nothing = empty pprint' v (Just e) = pprint' v e instance Pretty String where@@ -309,15 +345,15 @@ pprint' v es = commaSep (map (pprint' v) (aStrip es)) instance Pretty BaseType where- pprint' v TypeInteger = "integer"- pprint' v TypeReal = "real"- pprint' v TypeDoublePrecision = "double precision"- pprint' v TypeComplex = "complex"+ pprint' _ TypeInteger = "integer"+ pprint' _ TypeReal = "real"+ pprint' _ TypeDoublePrecision = "double precision"+ pprint' _ TypeComplex = "complex" pprint' v TypeDoubleComplex | v == Fortran77Extended = "double complex" | otherwise = tooOld v "Double complex" Fortran77Extended- pprint' v TypeLogical = "logical"- pprint' v TypeCharacter+ pprint' _ TypeLogical = "logical"+ pprint' v (TypeCharacter _ _) | v >= Fortran77 = "character" | otherwise = tooOld v "Character data type" Fortran77 pprint' v (TypeCustom str)@@ -327,10 +363,22 @@ pprint' v TypeByte | v >= Fortran77Extended = "byte" | otherwise = tooOld v "Byte" Fortran77Extended+ pprint' v ClassStar+ | v >= Fortran2003 = "class(*)"+ | otherwise = tooOld v "Class(*)" Fortran2003+ 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) =- pprint' v baseType <+> pprint' v mSelector+ pprint' v baseType <> pprint' v mSelector instance Pretty (Selector a) where pprint' v (Selector _ _ mLenSel mKindSel)@@ -352,12 +400,13 @@ (Just lenDev, Nothing) -> parens $ len lenDev _ -> error "No way for both kind and length selectors to be empty in \ \Fortran 90 onwards."+ | otherwise = error "unhandled version" where- len e = "len=" <> pprint' Fortran90 e- kind e = "kind=" <> pprint' Fortran90 e+ len e = "len=" <> pprint' v e+ kind e = "kind=" <> pprint' v e instance Pretty (Statement a) where- pprint' v st@(StDeclaration _ s typeSpec mAttrList declList)+ pprint' v (StDeclaration _ _ typeSpec mAttrList declList) | v < Fortran90 = pprint' v typeSpec <+> pprint' v declList | v >= Fortran90 = pprint' v typeSpec <>@@ -365,8 +414,9 @@ pprint' v mAttrList <+> text "::" <+> pprint' v declList+ | otherwise = error "unhandled version" - pprint' v st@(StStructure _ _ mName itemList)+ pprint' v (StStructure _ _ mName itemList) | v /= Fortran77Extended = tooOld v "Structure" Fortran77Extended | otherwise = "structure" <> (if isJust mName then " /" <> pprint' v mName <> "/" else empty) <> newline <>@@ -390,6 +440,10 @@ | v >= Fortran90 = "private" <> " :: " <?> pprint' v mVars | otherwise = tooOld v "Private statement" Fortran90 + pprint' v (StProtected _ _ mVars)+ | v >= Fortran2003 = "protected" <> " :: " <?> pprint' v mVars+ | otherwise = tooOld v "Protected statement" Fortran2003+ pprint' v (StSave _ _ mVars) | v >= Fortran90 = "save" <> " :: " <?> pprint' v mVars | otherwise = "save" <+> pprint' v mVars@@ -402,6 +456,10 @@ | v >= Fortran90 = "allocatable ::" <+> pprint' v decls | otherwise = tooOld v "Allocatable statement" Fortran90 + pprint' v (StAsynchronous _ _ decls)+ | v >= Fortran2003 = "asynchronous ::" <+> pprint' v decls+ | otherwise = tooOld v "Asynchronous statement" Fortran2003+ pprint' v (StPointer _ _ decls) | v >= Fortran90 = "pointer ::" <+> pprint' v decls | otherwise = tooOld v "Pointer statement" Fortran90@@ -410,13 +468,21 @@ | v >= Fortran90 = "target ::" <+> pprint' v decls | otherwise = tooOld v "Target statement" Fortran90 + pprint' v (StValue _ _ decls)+ | v >= Fortran95 = "value ::" <+> pprint' v decls+ | otherwise = tooOld v "Value statement" Fortran95++ pprint' v (StVolatile _ _ decls)+ | v >= Fortran95 = "volatile ::" <+> pprint' v decls+ | otherwise = tooOld v "Volatile statement" Fortran95+ pprint' v (StData _ _ aDataGroups@(AList _ _ dataGroups)) | v >= Fortran90 = "data" <+> pprint' v aDataGroups | otherwise = "data" <+> hsep (map (pprint' v) dataGroups) pprint' v (StAutomatic _ _ decls) | v == Fortran77Extended = "automatic" <+> pprint' v decls- | otherwise = tooOld v "Target statement" Fortran90+ | otherwise = tooOld v "Automatic statement" Fortran90 pprint' v (StNamelist _ _ namelist) | v >= Fortran90 = "namelist" <+> pprint' v namelist@@ -452,7 +518,7 @@ pprint' v (StInclude _ _ file _) = "include" <+> pprint' v file - pprint' v (StDo _ s mConstructor mLabel mDoSpec)+ pprint' v (StDo _ _ mConstructor mLabel mDoSpec) | v < Fortran90 , Just _ <- mConstructor = tooOld v "Named DO block" Fortran90 | v < Fortran77Extended@@ -473,7 +539,7 @@ pprint' v (StEnddo _ _ mConstructor) | v < Fortran77Extended = tooOld v "End do" Fortran77Extended | v < Fortran90- , name <- mConstructor = tooOld v "Named DO loop" Fortran90+ , _ <- mConstructor = tooOld v "Named DO loop" Fortran90 | otherwise = "end do" <+> pprint' v mConstructor pprint' v (StExpressionAssign _ _ lhs rhs) =@@ -567,7 +633,7 @@ pprint' v (StCall _ _ name args) = pprint' v name <+> parens (pprint' v args) - pprint' v (StContinue _ _) = "continue"+ pprint' _ (StContinue _ _) = "continue" pprint' v (StReturn _ _ exp) = "return" <+> pprint' v exp @@ -577,7 +643,7 @@ pprint' v (StRead _ _ cilist mIolist) = "read" <+> parens (pprint' v cilist) <+> pprint' v mIolist- pprint' v (StRead2 _ s formatId mIolist) =+ pprint' v (StRead2 _ _ formatId mIolist) = "read" <+> pprint' v formatId <> comma <?+> pprint' v mIolist pprint' v (StWrite _ _ cilist mIolist) =@@ -591,6 +657,9 @@ pprint' v (StOpen _ _ cilist) = "open" <+> parens (pprint' v cilist) pprint' v (StClose _ _ cilist) = "close" <+> parens (pprint' v cilist)+ pprint' v (StFlush _ _ (AList _ _ fslist))+ | v >= Fortran2003 = "flush" <+> parens (commaSep $ map (pprint' v) fslist)+ | otherwise = tooOld v "Flush statement" Fortran2003 pprint' v (StInquire _ _ cilist) = "inquire" <+> parens (pprint' v cilist) pprint' v (StRewind _ _ cilist) = "rewind" <+> parens (pprint' v cilist)@@ -603,14 +672,19 @@ pprint' v (StEndfile _ _ cilist) = "endfile" <+> parens (pprint' v cilist) pprint' v (StEndfile2 _ _ unit) = "endfile" <+> pprint' v unit - pprint' v (StAllocate _ _ vars contPair)+ pprint' v (StAllocate _ _ (Just ty) vars opts)+ | v >= Fortran2003 =+ "allocate" <+> parens (pprint' v ty <+> "::" <+> pprint' v vars <> comma <?+> pprint' v opts)+ | otherwise = tooOld v "Allocate with type_spec" Fortran2003++ pprint' v (StAllocate _ _ Nothing vars opts) | v >= Fortran90 =- "allocate" <+> parens (pprint' v vars <> comma <?+> pprint' v contPair)+ "allocate" <+> parens (pprint' v vars <> comma <?+> pprint' v opts) | otherwise = tooOld v "Allocate" Fortran90 - pprint' v (StDeallocate _ _ vars contPair)+ pprint' v (StDeallocate _ _ vars opts) | v >= Fortran90 =- "deallocate" <+> parens (pprint' v vars <> comma <?+> pprint' v contPair)+ "deallocate" <+> parens (pprint' v vars <> comma <?+> pprint' v opts) | otherwise = tooOld v "Deallocate" Fortran90 pprint' v (StNullify _ _ vars) = "nullify" <+> pprint' v vars@@ -620,29 +694,56 @@ "where" <+> parens (pprint' v mask) <+> pprint' v assignment | otherwise = tooOld v "Where statement" Fortran90 - pprint' v (StWhereConstruct _ _ mask)+ pprint' v (StWhereConstruct _ _ (Just lab) mask)+ | v >= Fortran2003 = text lab <> ":" <+> "where" <+> parens (pprint' v mask)+ | otherwise = tooOld v "Labelled where construct" Fortran2003++ pprint' v (StWhereConstruct _ _ Nothing mask) | v >= Fortran90 = "where" <+> parens (pprint' v mask) | otherwise = tooOld v "Where construct" Fortran90 - pprint' v (StElsewhere _ _)- | v >= Fortran90 = "else where"+ pprint' v (StElsewhere _ _ (Just lab) mexp)+ | v >= Fortran2003 = "else where" <+> "(" <?> pprint' v mexp <?> ")" <+> text lab+ | otherwise = tooOld v "Labelled ELSEWHERE" Fortran2003++ pprint' v (StElsewhere _ _ Nothing mexp)+ | v >= Fortran90 = "else where" <+> "(" <?> pprint' v mexp <?> ")" | otherwise = tooOld v "Else where" Fortran90 - pprint' v (StEndWhere _ _)+ pprint' v (StEndWhere _ _ (Just lab))+ | v >= Fortran2003 = "end where" <+> text lab+ | otherwise = tooOld v "Labelled END WHERE" Fortran2003++ pprint' v (StEndWhere _ _ Nothing) | v >= Fortran90 = "end where" | otherwise = tooOld v "End where" Fortran90 - pprint' v (StUse _ _ moduleName only mappings)+ pprint' v (StUse _ _ moduleName mIntrinsic only mappings)+ | v >= Fortran2003 =+ "use" <> (comma <?+> intrinsic <?+> "::") <+> pprint' v moduleName <>+ (comma <?+> (pprint' v only <+> pprint' v mappings)) | v >= Fortran90 = "use" <+> pprint' v moduleName <> (comma <?+> (pprint' v only <+> pprint' v mappings)) | otherwise = tooOld v "Module system" Fortran90+ where+ intrinsic = case mIntrinsic of+ Just ModIntrinsic -> "intrinsic"+ Just ModNonIntrinsic -> "non_intrinsic"+ Nothing -> empty pprint' v (StModuleProcedure _ _ procedures) | v >= Fortran90 = "module procedure" <+> pprint' v procedures | otherwise = tooOld v "Module procedure" Fortran90 + pprint' v (StProcedure _ _ mProcInterface mSuffix (AList _ _ procDecls))+ | v >= Fortran2003 =+ "procedure" <> parens (pprint' v mProcInterface) <>+ comma <?+> pprint' v mSuffix <+> "::" <?+>+ commaSep (map (pprint' v) procDecls)+ | otherwise = tooOld v "Procedure" Fortran2003+ pprint' v (StType _ _ attrs name) | v >= Fortran90 = "type" <+> pprint' v attrs <+> pprint' v name | otherwise = tooOld v "Derived type" Fortran90@@ -651,15 +752,42 @@ | v >= Fortran90 = "end type" <+> pprint' v name | otherwise = tooOld v "Derived type" Fortran90 + pprint' v (StEnum _ _)+ | v >= Fortran2003 = "enum, bind(c)"+ | otherwise = tooOld v "Enum" Fortran2003++ pprint' v (StEnumerator _ _ decls)+ | v >= Fortran2003 = "enumerator ::" <+> pprint' v decls+ | otherwise = tooOld v "Enumator" Fortran2003++ pprint' v (StEndEnum _ _)+ | v >= Fortran2003 = "end enum"+ | otherwise = tooOld v "End enum" Fortran2003+ pprint' v (StSequence _ _) | v >= Fortran90 = "sequence" | otherwise = tooOld v "Sequence" Fortran90 + pprint' v (StImport _ _ (AList _ _ vs))+ | v >= Fortran2003 = "import" <+> commaSep (map (pprint' v) vs)+ | otherwise = tooOld v "Import" Fortran2003+ pprint' v (StFormatBogus _ _ blob) = "format" <+> pprint' v blob+ pprint' _ StForall{} = error "unhandled pprint StForall"+ pprint' _ StForallStatement{} = error "unhandled pprint StForallStatement"+ pprint' _ StEndForall{} = error "unhandled pprint StEndForall" +instance Pretty (ProcInterface a) where+ pprint' v (ProcInterfaceName _ _ e) = pprint' v e+ pprint' v (ProcInterfaceType _ _ t) = pprint' v t++instance Pretty (ProcDecl a) where+ pprint' v (ProcDecl _ _ e1 (Just e2)) = pprint' v e1 <+> "=>" <+> pprint' v e2+ pprint' v (ProcDecl _ _ e1 Nothing) = pprint' v e1+ instance Pretty Only where- pprint' v Exclusive = "only" <> colon- pprint' v Permissive = empty+ pprint' _ Exclusive = "only" <> colon+ pprint' _ Permissive = empty instance Pretty (Use a) where pprint' v use@@ -668,9 +796,10 @@ UseRename _ _ uSrc uDst -> pprint' v uSrc <+> "=>" <+> pprint' v uDst UseID _ _ u -> pprint' v u | v < Fortran90 = tooOld v "Module system" Fortran90+ | otherwise = error "unhandled version" instance Pretty (Argument a) where- pprint' v (Argument _ s key e) =+ pprint' v (Argument _ _ key e) = case key of Just keyName -> text keyName <+> char '=' <+> pprint' v e Nothing -> pprint' v e@@ -679,12 +808,28 @@ pprint' v attr | v >= Fortran90 = case attr of+ AttrAsynchronous _ _+ | v >= Fortran2003 -> "asynchronous"+ | otherwise -> tooOld v "Asynchronous attribute" Fortran2003+ AttrValue _ _+ | v >= Fortran95 -> "value"+ | otherwise -> tooOld v "Value attribute" Fortran95+ AttrVolatile _ _+ | v >= Fortran95 -> "volatile"+ | otherwise -> tooOld v "Volatile attribute" Fortran95+ AttrSuffix _ _ s+ | v >= Fortran2003 -> pprint' v s+ | otherwise -> tooOld v "Bind (language-binding-spec) attribute" Fortran2003+ AttrParameter _ _ -> "parameter" AttrPublic _ _ -> "public" AttrPrivate _ _ -> "private"+ AttrProtected _ _+ | v >= Fortran2003 -> "protected"+ | otherwise -> tooOld v "Protected attribute" Fortran2003 AttrAllocatable _ _ -> "allocatable" AttrDimension _ _ dims ->- "dimesion" <> parens (pprint' v dims)+ "dimension" <> parens (pprint' v dims) AttrExternal _ _ -> "external" AttrIntent _ _ intent -> "intent" <> parens (pprint' v intent)@@ -695,6 +840,11 @@ AttrTarget _ _ -> "target" | otherwise = tooOld v "Declaration attribute" Fortran90 +instance Pretty (Suffix a) where+ pprint' v (SfxBind _ _ mexp)+ | v >= Fortran2003 = "bind" <> parens ("c" <> comma <?+> pprint' v mexp)+ | otherwise = tooOld v "Bind suffix" Fortran2003+ instance Pretty Intent where pprint' v intent | v >= Fortran90 =@@ -711,6 +861,12 @@ text (show $ length s) <> char 'h' <> text s pprint' _ _ = error "Not yet supported." +instance Pretty (FlushSpec a) where+ pprint' v (FSUnit _ _ e) = "unit=" <> pprint' v e+ pprint' v (FSIOStat _ _ e) = "iostat=" <> pprint' v e+ pprint' v (FSIOMsg _ _ e) = "iomsg=" <> pprint' v e+ pprint' v (FSErr _ _ e) = "err=" <> pprint' v e+ instance Pretty (DoSpecification a) where pprint' v (DoSpecification _ _ s@StExpressionAssign{} limit mStride) = pprint' v s <> comma@@ -727,9 +883,18 @@ | v >= Fortran77 , Just str <- mStr = text str <> char '=' <> pprint' v exp | v < Fortran77- , Just str <- mStr = tooOld v "Named control pair" Fortran77+ , Just _ <- mStr = tooOld v "Named control pair" Fortran77 | otherwise = pprint' v exp +instance Pretty (AllocOpt a) where+ pprint' v (AOStat _ _ e) = "stat=" <> pprint' v e+ pprint' v (AOErrMsg _ _ e)+ | v >= Fortran2003 = "errmsg=" <> pprint' v e+ | otherwise = tooOld v "Allocate errmsg" Fortran2003+ pprint' v (AOSource _ _ e)+ | v >= Fortran2003 = "source=" <> pprint' v e+ | otherwise = tooOld v "Allocate source" Fortran2003+ instance Pretty (ImpList a) where pprint' v (ImpList _ _ bt els) = pprint' v bt <+> parens (pprint' v els) @@ -747,68 +912,69 @@ pprint' v vars <> char '/' <> pprint' v exps <> char '/' instance Pretty (ImpElement a) where- pprint' v (ImpCharacter _ _ c) = text c- pprint' v (ImpRange _ _ beg end) = text beg <> "-" <> text end+ pprint' _ (ImpCharacter _ _ c) = text c+ pprint' _ (ImpRange _ _ beg end) = text beg <> "-" <> text end instance Pretty (Expression a) where- pprint' v (ExpValue _ s val) =+ pprint' v (ExpValue _ _ val) = pprint' v val - pprint' v (ExpBinary _ s op e1 e2) =+ pprint' v (ExpBinary _ _ op e1 e2) = parens (pprint' v e1 <+> pprint' v op <+> pprint' v e2) - pprint' v (ExpUnary _ s op e) =+ pprint' v (ExpUnary _ _ op e) = pprint' v op <+> pprint' v e - pprint' v (ExpSubscript _ s e ixs) =+ pprint' v (ExpSubscript _ _ e ixs) = pprint' v e <> parens (pprint' v ixs) - pprint' v (ExpDataRef _ s e1 e2) =+ pprint' v (ExpDataRef _ _ e1 e2) = pprint' v e1 <+> char '%' <+> pprint' v e2 - pprint' v (ExpFunctionCall _ s e mes) =+ pprint' v (ExpFunctionCall _ _ e mes) = pprint' v e <> parens (pprint' v mes) - pprint' v (ExpImpliedDo _ s es dospec) =+ pprint' v (ExpImpliedDo _ _ es dospec) = pprint' v es <> comma <+> pprint' v dospec - pprint' v (ExpInitialisation _ s es) =+ pprint' v (ExpInitialisation _ _ es) = "(/" <> pprint' v es <> "/)" - pprint' v (ExpReturnSpec _ s e) =+ pprint' v (ExpReturnSpec _ _ e) = char '*' <> pprint' v e instance Pretty (Index a) where- pprint' v (IxSingle _ s Nothing e) = pprint' v e+ pprint' v (IxSingle _ _ Nothing e) = pprint' v e -- This is an intermediate expression form which shouldn't make it -- to the pretty printer- pprint' v (IxSingle _ s (Just _) e) = pprint' v e- pprint' v (IxRange _ s low up stride) =+ pprint' v (IxSingle _ _ (Just _) e) = pprint' v e+ pprint' v (IxRange _ _ low up stride) = pprint' v low <> colon <> pprint' v up <> colon <?> pprint' v stride -- A subset of Value permit the 'FirstParameter' operation instance FirstParameter (Value a) String instance Pretty (Value a) where- pprint' v ValStar = char '*'+ pprint' _ ValStar = char '*'+ pprint' _ ValColon = char ':' pprint' v ValAssignment | v >= Fortran90 = "assignment (=)" -- TODO better error message is needed. Assignment is too vague.- | otherwise = tooOld v "Asiggnment" Fortran90+ | otherwise = tooOld v "Assignment" Fortran90 pprint' v (ValOperator op) | v >= Fortran90 = "operator" <+> parens (text op) -- TODO better error message is needed. Operator is too vague. | otherwise = tooOld v "Operator" Fortran90 pprint' v (ValComplex e1 e2) = parens $ commaSep [pprint' v e1, pprint' v e2]- pprint' v (ValString str) = quotes $ text str- pprint' v valLit = text . getFirstParameter $ valLit+ pprint' _ (ValString str) = quotes $ text str+ pprint' _ valLit = text . getFirstParameter $ valLit instance IndentablePretty (StructureItem a) where- pprint v (StructFields a s spec mAttrs decls) i = pprint' v (StDeclaration a s spec mAttrs decls)+ pprint v (StructFields a s spec mAttrs decls) _ = pprint' v (StDeclaration a s spec mAttrs decls) pprint v (StructUnion _ _ maps) i = "union" <> newline <> foldl' (\doc item -> doc <> pprint v item (incIndentation i) <> newline) empty (aStrip maps) <> "end union"- pprint v (StructStructure a s mName items) i = pprint' v (StStructure a s mName items)+ pprint v (StructStructure a s mName items) _ = pprint' v (StStructure a s mName items) instance IndentablePretty (UnionMap a) where pprint v (UnionMap _ _ items) i =@@ -881,9 +1047,9 @@ pprint' v GTE = if v <= Fortran77Extended then ".ge." else ">=" pprint' v EQ = if v <= Fortran77Extended then ".eq." else "==" pprint' v NE = if v <= Fortran77Extended then ".ne." else "/="- pprint' v Or = ".or."- pprint' v XOr = ".xor."- pprint' v And = ".and."+ pprint' _ Or = ".or."+ pprint' _ XOr = ".xor."+ pprint' _ And = ".and." pprint' v Equivalent | v >= Fortran77 = ".eqv." | otherwise = tooOld v ".EQV. operator" Fortran77@@ -891,7 +1057,7 @@ | v >= Fortran77 = ".neqv." | otherwise = tooOld v ".NEQV. operator" Fortran77 pprint' v (BinCustom custom)- | v >= Fortran90 = "." <> text custom <> "."+ | v >= Fortran90 = text custom | otherwise = tooOld v "Custom binary operator" Fortran90 commaSep :: [Doc] -> Doc
src/Language/Fortran/Transformation/Disambiguation/Function.hs view
@@ -20,28 +20,35 @@ disambiguateFunctionStatements :: Data a => Transform a () disambiguateFunctionStatements = modifyProgramFile (trans statement) where- trans = (transformBi :: Data a => TransFunc Statement ProgramFile a)- statement st@(StExpressionAssign a1 s (ExpSubscript _ _ v@(ExpValue a _ (ValVariable _)) indicies) e2)+ trans = transformBi :: Data a => TransFunc Statement ProgramFile a+ statement (StExpressionAssign a1 s (ExpSubscript _ _ v@(ExpValue a _ (ValVariable _)) indicies) e2) | Just (IDType _ (Just CTFunction)) <- idType a , indiciesRangeFree indicies = StFunction a1 s v (aMap fromIndex indicies) e2+ -- nullary statement function+ statement (StExpressionAssign a1 s1 (ExpFunctionCall _ _ v@(ExpValue a s (ValVariable _)) Nothing) e2)+ = StFunction a1 s1 v (AList a s []) e2 statement st = st disambiguateFunctionCalls :: Data a => Transform a () disambiguateFunctionCalls = modifyProgramFile (trans expression) where- trans = (transformBi :: Data a => TransFunc Expression ProgramFile a)- expression e@(ExpSubscript a1 s v@(ExpValue a _ (ValVariable _)) indicies)+ trans = transformBi :: Data a => TransFunc Expression ProgramFile a+ expression (ExpSubscript a1 s v@(ExpValue a _ (ValVariable _)) indicies) | Just (IDType _ (Just CTFunction)) <- idType a , indiciesRangeFree indicies = ExpFunctionCall a1 s v (Just $ aMap fromIndex indicies)- expression e@(ExpSubscript a1 s v@(ExpValue a _ (ValVariable _)) indicies) | Just (IDType _ (Just CTExternal)) <- idType a , indiciesRangeFree indicies = ExpFunctionCall a1 s v (Just $ aMap fromIndex indicies)- expression e@(ExpSubscript a1 s v@(ExpValue a _ (ValIntrinsic _)) indicies)+ | Just (IDType _ (Just CTVariable)) <- idType a+ , indiciesRangeFree indicies = ExpFunctionCall a1 s v (Just $ aMap fromIndex indicies)+ | Nothing <- idType a+ , indiciesRangeFree indicies = ExpFunctionCall a1 s v (Just $ aMap fromIndex indicies)+ expression (ExpSubscript a1 s v@(ExpValue a _ (ValIntrinsic _)) indicies) | Just (IDType _ (Just CTIntrinsic)) <- idType a , indiciesRangeFree indicies = ExpFunctionCall a1 s v (Just $ aMap fromIndex indicies) expression e = e -- BEGIN: TODO STRICTLY TO BE REMOVED LATER TODO+indiciesRangeFree :: AList Index a -> Bool indiciesRangeFree aIndicies = cRange $ aStrip aIndicies where cRange [] = True
src/Language/Fortran/Transformation/Disambiguation/Intrinsic.hs view
@@ -15,8 +15,8 @@ disambiguateIntrinsic :: Data a => Transform a () disambiguateIntrinsic = modifyProgramFile (trans expression) where- trans = (transformBi :: Data a => TransFunc Expression ProgramFile a)- expression e@(ExpValue a s (ValVariable v))+ 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
src/Language/Fortran/Transformation/Grouping.hs view
@@ -11,19 +11,26 @@ import Language.Fortran.Transformation.TransformMonad import Data.Data+import Data.List (intercalate) import Data.Generics.Uniplate.Operations type ABlocks a = [ Block (Analysis a) ] -genericGroup :: Data a => (ABlocks a -> ABlocks a) -> Transform a ()-genericGroup groupingFunction =- modifyProgramFile $ transformBi groupingFunction+genericGroup :: Data a => (ABlocks a -> ABlocks a) -> (Statement (Analysis a) -> Bool) -> Transform a ()+genericGroup groupingFunction checkingFunction = do+ pf <- getProgramFile+ let pf' = transformBi groupingFunction pf+ bad = filter checkingFunction $ universeBi pf'+ if null bad+ then putProgramFile pf'+ else let spans = [ apparentFilePath p1 ++ " " ++ show ss | b <- bad, let ss@(SrcSpan p1 _) = getSpan b ] in+ error $ "Mis-matched grouping statements at these position(s): " ++ intercalate ", " spans -------------------------------------------------------------------------------- -- Grouping FORALL statement blocks into FORALL blocks in entire parse tree -------------------------------------------------------------------------------- groupForall :: Data a => Transform a ()-groupForall = genericGroup groupForall'+groupForall = genericGroup groupForall' isForall groupForall' :: ABlocks a -> ABlocks a@@ -40,8 +47,8 @@ | StForallStatement _ _ header st' <- st -> let block = BlStatement a (getSpan st') Nothing st' in ( BlForall a (getTransSpan s st') label Nothing header [block] Nothing, groupedBlocks )- b | containsGroups b ->- ( applyGroupingToSubblocks groupForall' b, groupedBlocks )+ b'' | containsGroups b'' ->+ ( applyGroupingToSubblocks groupForall' b'', groupedBlocks ) _ -> (b, groupedBlocks) groupedBlocks = groupForall' bs @@ -51,7 +58,7 @@ , Maybe (Expression (Analysis a)) ) collectNonForallBlocks blocks mNameTarget = case blocks of- b@(BlStatement _ _ mLabel (StEndForall _ _ mName)):rest+ BlStatement _ _ mLabel (StEndForall _ _ mName):rest | mName == mNameTarget -> ([], rest, mLabel) | otherwise -> error "Forall block name does not match that of the end statement."@@ -60,13 +67,17 @@ in (b : bs', rest, mLabel) _ -> error "Premature file ending while parsing structured forall block." +isForall :: Statement a -> Bool+isForall (StForall{}) = True+isForall (StForallStatement{}) = True+isForall _ = False -------------------------------------------------------------------------------- -- Grouping if statement blocks into if blocks in entire parse tree -------------------------------------------------------------------------------- groupIf :: Data a => Transform a ()-groupIf = genericGroup groupIf'+groupIf = genericGroup groupIf' isIf -- Actual grouping is done here. -- 1. Case: head is a statement block with an IF statement:@@ -86,12 +97,12 @@ (b', bs') = case b of BlStatement a s label st | StIfThen _ _ mName _ <- st -> -- If statement- let ( conditions, blocks, leftOverBlocks, endLabel ) =+ let ( conditions, blocks, leftOverBlocks, endLabel, endStmt ) = decomposeIf (b:groupedBlocks)- in ( BlIf a (getTransSpan s blocks) label mName conditions blocks endLabel+ in ( BlIf a (getTransSpan s endStmt) label mName conditions blocks endLabel , leftOverBlocks)- b | containsGroups b -> -- Map to subblocks for groupable blocks- ( applyGroupingToSubblocks groupIf' b, groupedBlocks )+ b'' | containsGroups b'' -> -- Map to subblocks for groupable blocks+ ( applyGroupingToSubblocks groupIf' b'', groupedBlocks ) _ -> ( b, groupedBlocks ) groupedBlocks = groupIf' bs -- Assume everything to the right is grouped. @@ -119,8 +130,9 @@ -> ( [ Maybe (Expression (Analysis a)) ], [ ABlocks a ], ABlocks a,- Maybe (Expression (Analysis a)) )-decomposeIf blocks@(BlStatement _ _ _ (StIfThen _ _ mTargetName _):rest) =+ Maybe (Expression (Analysis a)),+ Statement (Analysis a) )+decomposeIf blocks@(BlStatement _ _ _ (StIfThen _ _ mTargetName _):_) = decomposeIf' blocks where decomposeIf' (BlStatement _ _ mLabel st:rest) =@@ -129,17 +141,20 @@ StElsif _ _ _ condition -> go (Just condition) rest StElse{} -> go Nothing rest StEndif _ _ mName- | mName == mTargetName -> ([], [], rest, mLabel)+ | mName == mTargetName -> ([], [], rest, mLabel, st) | otherwise -> error $ "If statement name does not match that of " ++ "the corresponding end if statement." _ -> error "Block with non-if related statement. Should never occur."- go maybeCondition blocks =- let (nonConditionBlocks, rest') = collectNonConditionalBlocks blocks- (conditions, listOfBlocks, rest'', endLabel) = decomposeIf' rest'+ decomposeIf' _ = error "can't decompose block"+ go maybeCondition blocks' =+ let (nonConditionBlocks, rest') = collectNonConditionalBlocks blocks'+ (conditions, listOfBlocks, rest'', endLabel, endStmt) = decomposeIf' rest' in ( maybeCondition : conditions , nonConditionBlocks : listOfBlocks , rest''- , endLabel )+ , endLabel+ , endStmt )+decomposeIf _ = error "can't decompose block" -- This compiles the executable blocks under various if conditions. collectNonConditionalBlocks :: ABlocks a -> (ABlocks a, ABlocks a)@@ -151,86 +166,100 @@ -- conditional directives. The reason is that this block can be -- a branch target if it is labeled according to the specification, hence -- it is presence in the parse tree is meaningful.- b@(BlStatement _ _ _ StEndif{}):_ -> ([], blocks)+ BlStatement _ _ _ StEndif{}:_ -> ([], blocks) -- Catch all case for all non-if related blocks. b:bs -> let (bs', rest) = collectNonConditionalBlocks bs in (b : bs', rest) -- In this case the structured if block is malformed and the file ends -- prematurely. _ -> error "Premature file ending while parsing structured if block." +isIf :: Statement a -> Bool+isIf s = case s of+ StIfThen{} -> True+ StElsif{} -> True+ StElse{} -> True+ StEndif{} -> True+ _ -> False+ -------------------------------------------------------------------------------- -- Grouping new do statement blocks into do blocks in entire parse tree -------------------------------------------------------------------------------- groupDo :: Data a => Transform a ()-groupDo = genericGroup groupDo'+groupDo = genericGroup groupDo' isDo groupDo' :: ABlocks a -> ABlocks a groupDo' [ ] = [ ]-groupDo' blocks@(b:bs) = b' : bs'+groupDo' (b:bs) = b' : bs' where (b', bs') = case b of BlStatement a s label st -- Do While statement | StDoWhile _ _ mTarget Nothing condition <- st ->- let ( blocks, leftOverBlocks, endLabel ) =+ let ( blocks, leftOverBlocks, endLabel, stEnd ) = collectNonDoBlocks groupedBlocks mTarget- in ( BlDoWhile a (getTransSpan s blocks) label mTarget Nothing condition blocks endLabel+ in ( BlDoWhile a (getTransSpan s stEnd) label mTarget Nothing condition blocks endLabel , leftOverBlocks) -- Vanilla do statement | StDo _ _ mName Nothing doSpec <- st ->- let ( blocks, leftOverBlocks, endLabel ) =+ let ( blocks, leftOverBlocks, endLabel, stEnd ) = collectNonDoBlocks groupedBlocks mName- in ( BlDo a (getTransSpan s blocks) label mName Nothing doSpec blocks endLabel+ in ( BlDo a (getTransSpan s stEnd) label mName Nothing doSpec blocks endLabel , leftOverBlocks)- b | containsGroups b ->- ( applyGroupingToSubblocks groupDo' b, groupedBlocks )+ b'' | containsGroups b'' ->+ ( applyGroupingToSubblocks groupDo' b'', groupedBlocks ) _ -> ( b, groupedBlocks ) groupedBlocks = groupDo' bs -- Assume everything to the right is grouped. collectNonDoBlocks :: ABlocks a -> Maybe String -> ( ABlocks a , ABlocks a- , Maybe (Expression (Analysis a)) )+ , Maybe (Expression (Analysis a))+ , Statement (Analysis a) ) collectNonDoBlocks blocks mNameTarget = case blocks of- b@(BlStatement _ _ mLabel (StEnddo _ _ mName)):rest- | mName == mNameTarget -> ([ ], rest, mLabel)+ BlStatement _ _ mLabel st@(StEnddo _ _ mName):rest+ | mName == mNameTarget -> ([ ], rest, mLabel, st) | otherwise -> error "Do block name does not match that of the end statement." b:bs ->- let (bs', rest, mLabel) = collectNonDoBlocks bs mNameTarget- in (b : bs', rest, mLabel)+ let (bs', rest, mLabel, stEnd) = collectNonDoBlocks bs mNameTarget+ in (b : bs', rest, mLabel, stEnd) _ -> error "Premature file ending while parsing structured do block." +isDo :: Statement a -> Bool+isDo s = case s of+ StDo _ _ _ Nothing _ -> True+ StDoWhile _ _ _ Nothing _ -> True+ StEnddo{} -> True+ _ -> False+ -------------------------------------------------------------------------------- -- Grouping labeled do statement blocks into do blocks in entire parse tree -------------------------------------------------------------------------------- groupLabeledDo :: Data a => Transform a ()-groupLabeledDo = genericGroup groupLabeledDo'+groupLabeledDo = genericGroup groupLabeledDo' isLabeledDo groupLabeledDo' :: ABlocks a -> ABlocks a groupLabeledDo' [ ] = [ ]-groupLabeledDo' blos@(b:bs) = b' : bs'+groupLabeledDo' (b:bs) = b' : bs' where (b', bs') = case b of BlStatement a s label (StDo _ _ mn tl@Just{} doSpec) ->- let ( blocks, leftOverBlocks ) =+ let ( blocks, leftOverBlocks, lastLabel ) = collectNonLabeledDoBlocks tl groupedBlocks- lastLabel = getLastLabel $ last blocks in ( BlDo a (getTransSpan s blocks) label mn tl doSpec blocks lastLabel , leftOverBlocks ) BlStatement a s label (StDoWhile _ _ mn tl@Just{} cond) ->- let ( blocks, leftOverBlocks ) =+ let ( blocks, leftOverBlocks, lastLabel ) = collectNonLabeledDoBlocks tl groupedBlocks- lastLabel = getLastLabel $ last blocks in ( BlDoWhile a (getTransSpan s blocks) label mn tl cond blocks lastLabel , leftOverBlocks )- b | containsGroups b ->- ( applyGroupingToSubblocks groupLabeledDo' b, groupedBlocks )+ b'' | containsGroups b'' ->+ ( applyGroupingToSubblocks groupLabeledDo' b'', groupedBlocks ) _ -> (b, groupedBlocks) -- Assume everything to the right is grouped.@@ -238,18 +267,20 @@ collectNonLabeledDoBlocks :: Maybe (Expression (Analysis a)) -> ABlocks a- -> (ABlocks a, ABlocks a)+ -> (ABlocks a, ABlocks a, Maybe (Expression (Analysis a))) collectNonLabeledDoBlocks targetLabel blocks = case blocks of -- Didn't find a statement with matching label; don't group [] -> error "Malformed labeled DO group."- b:bs- | compLabel (getLastLabel b) targetLabel -> ([ b ], bs)- | otherwise ->- let (bs', rest) = collectNonLabeledDoBlocks targetLabel bs- in (b : bs', rest)+ | compLabel (getLastLabel b) targetLabel -> (b1, bs, getLastLabel b)+ | otherwise -> (b : bs', rest, ll)+ where (bs', rest, ll) = collectNonLabeledDoBlocks targetLabel bs+ b1 = case b of BlStatement _ _ _ StEnddo{} -> []+ BlStatement _ _ _ StContinue{} -> []+ _ -> [b] + compLabel :: Maybe (Expression a) -> Maybe (Expression a) -> Bool compLabel (Just (ExpValue _ _ (ValInteger l1))) (Just (ExpValue _ _ (ValInteger l2))) = strip l1 == strip l2@@ -258,12 +289,18 @@ strip :: String -> String strip = dropWhile (=='0') +isLabeledDo :: Statement a -> Bool+isLabeledDo s = case s of+ StDo _ _ _ Just{} _ -> True+ StDoWhile _ _ _ Just{} _ -> True+ _ -> False+ -------------------------------------------------------------------------------- -- Grouping case statements -------------------------------------------------------------------------------- groupCase :: Data a => Transform a ()-groupCase = genericGroup groupCase'+groupCase = genericGroup groupCase' isCase groupCase' :: ABlocks a -> ABlocks a groupCase' [] = []@@ -276,18 +313,18 @@ ( conds, blocks, leftOverBlocks, endLabel ) = decomposeCase blocksToDecomp mName in ( BlCase a (getTransSpan s blocks) label mName scrutinee conds blocks endLabel , leftOverBlocks)- b | containsGroups b -> -- Map to subblocks for groupable blocks- ( applyGroupingToSubblocks groupCase' b, groupedBlocks )+ b'' | containsGroups b'' -> -- Map to subblocks for groupable blocks+ ( applyGroupingToSubblocks groupCase' b'', groupedBlocks ) _ -> ( b , groupedBlocks ) groupedBlocks = groupCase' bs -- Assume everything to the right is grouped.- isComment b = case b of { BlComment{} -> True; _ -> False }+ isComment b'' = case b'' of { BlComment{} -> True; _ -> False } decomposeCase :: ABlocks a -> Maybe String -> ( [ Maybe (AList Index (Analysis a)) ] , [ ABlocks a ] , ABlocks a , Maybe (Expression (Analysis a)) )-decomposeCase blocks@(BlStatement _ _ mLabel st:rest) mTargetName =+decomposeCase (BlStatement _ _ mLabel st:rest) mTargetName = case st of StCase _ _ mName mCondition | Nothing <- mName -> go mCondition rest@@ -301,23 +338,31 @@ _ -> error "Block with non-case related statement. Must not occur." where go mCondition blocks =- let (nonCaseBlocks, rest) = collectNonCaseBlocks blocks- (conditions, listOfBlocks, rest', endLabel) = decomposeCase rest mTargetName+ let (nonCaseBlocks, rest') = collectNonCaseBlocks blocks+ (conditions, listOfBlocks, rest'', endLabel) = decomposeCase rest' mTargetName in ( mCondition : conditions , nonCaseBlocks : listOfBlocks- , rest', endLabel )+ , rest'', endLabel )+decomposeCase _ _ = error "can't decompose case" -- This compiles the executable blocks under various if conditions. collectNonCaseBlocks :: ABlocks a -> (ABlocks a, ABlocks a) collectNonCaseBlocks blocks = case blocks of- b@(BlStatement _ _ _ st):_+ BlStatement _ _ _ st:_ | StCase{} <- st -> ( [], blocks ) | StEndcase{} <- st -> ( [], blocks ) -- In this case case block is malformed and the file ends prematurely. b:bs -> let (bs', rest) = collectNonCaseBlocks bs in (b : bs', rest) _ -> error "Premature file ending while parsing select case block." +isCase :: Statement a -> Bool+isCase s = case s of+ StCase{} -> True+ StEndcase{} -> True+ StSelectCase{} -> True+ _ -> False+ -------------------------------------------------------------------------------- -- Helpers for grouping of structured blocks with more blocks inside. --------------------------------------------------------------------------------@@ -332,6 +377,7 @@ BlDoWhile{} -> True BlInterface{} -> False BlComment{} -> False+ BlForall{} -> True applyGroupingToSubblocks :: (ABlocks a -> ABlocks a) -> Block (Analysis a) -> Block (Analysis a) applyGroupingToSubblocks f b@@ -345,7 +391,9 @@ | BlInterface{} <- b = error "Interface blocks do not have groupable subblocks. Must not occur." | BlComment{} <- b =- error "Comment statements do not have subblocks. Must not occur."+ error "Comment statements do not have subblocks. Must not occur."+ | BlForall a s ml mn h blocks mel <- b =+ BlForall a s ml mn h (f blocks) mel --------------------------------------------------
src/Language/Fortran/Transformation/TransformMonad.hs view
@@ -3,12 +3,12 @@ , putProgramFile , modifyProgramFile , runTransform- , Transform(..) )+ , Transform) where import Prelude hiding (lookup)-import Control.Monad.State.Lazy+import Control.Monad.State.Lazy hiding (state) import Data.Data import Language.Fortran.Analysis
src/Language/Fortran/Util/FirstParameter.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleContexts #-}@@ -14,10 +13,10 @@ setFirstParameter :: e -> a -> a default getFirstParameter :: (Generic a, GFirstParameter (Rep a) e) => a -> e- getFirstParameter a = getFirstParameter' . from $ a+ getFirstParameter = getFirstParameter' . from default setFirstParameter :: (Generic a, GFirstParameter (Rep a) e) => e -> a -> a- setFirstParameter e a = to . setFirstParameter' e . from $ a+ setFirstParameter e = to . setFirstParameter' e . from class GFirstParameter f e where getFirstParameter' :: f a -> e@@ -25,7 +24,7 @@ instance {-# OVERLAPPING #-} GFirstParameter (K1 i e) e where getFirstParameter' (K1 a) = a- setFirstParameter' e (K1 a) = K1 e+ setFirstParameter' e (K1 _) = K1 e instance {-# OVERLAPPABLE #-} GFirstParameter (K1 i a) e where getFirstParameter' _ = undefined@@ -44,7 +43,7 @@ instance (GFirstParameter a e, GFirstParameter b e) => GFirstParameter (a :*: b) e where getFirstParameter' (a :*: _) = getFirstParameter' a- setFirstParameter' e (a :*: b) = (setFirstParameter' e a :*: b)+ setFirstParameter' e (a :*: b) = setFirstParameter' e a :*: b instance (GFirstParameter U1 String) where getFirstParameter' _ = ""
src/Language/Fortran/Util/ModFile.hs view
@@ -30,7 +30,7 @@ > let modFile1 = genModFile programFile > let modFile2 = alterModFileData (const (Just ...)) "mydata" modFile1-> let bytes = encodeModFile modFile1+> let bytes = encodeModFile modFile2 > ... > case decodeModFile bytes of > Left error -> print error@@ -46,8 +46,8 @@ ( modFileSuffix, ModFile, ModFiles, emptyModFile, emptyModFiles , lookupModFileData, getLabelsModFileData, alterModFileData -- , alterModFileDataF , genModFile, regenModFile, encodeModFile, decodeModFile- , DeclMap, DeclContext(..), extractModuleMap, extractDeclMap- , moduleFilename, combinedDeclMap, combinedModuleMap, combinedTypeEnv+ , StringMap, DeclMap, ParamVarMap, DeclContext(..), extractModuleMap, extractDeclMap+ , moduleFilename, combinedStringMap, combinedDeclMap, combinedModuleMap, combinedTypeEnv, combinedParamVarMap , genUniqNameToFilenameMap ) where @@ -55,9 +55,10 @@ import Data.Maybe import Data.Generics.Uniplate.Operations import qualified Data.Map.Strict as M-import Data.Binary+import Data.Binary (Binary, encode, decodeOrFail)+import Control.Monad.State import GHC.Generics (Generic)-import qualified Data.ByteString.Char8 as B+-- import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as LB import qualified Language.Fortran.Util.Position as P@@ -65,6 +66,8 @@ import qualified Language.Fortran.Analysis as FA import qualified Language.Fortran.Analysis.Renaming as FAR import qualified Language.Fortran.Analysis.Types as FAT+import qualified Language.Fortran.Analysis.DataFlow as FAD+import qualified Language.Fortran.Analysis.BBlocks as FAB -------------------------------------------------- @@ -84,13 +87,22 @@ -- unit where it was defined, and the corresponding SrcSpan. type DeclMap = M.Map F.Name (DeclContext, P.SrcSpan) +-- | A map of aliases => strings, in order to save space and share+-- structure for repeated strings.+type StringMap = M.Map String String++-- | A map of variables => their constant expression if known+type ParamVarMap = FAD.ParameterVarMap+ -- | The data stored in the "mod files"-data ModFile = ModFile { mfFilename :: String- , mfModuleMap :: FAR.ModuleMap- , mfDeclMap :: DeclMap- , mfTypeEnv :: FAT.TypeEnv- , mfOtherData :: M.Map String B.ByteString }- deriving (Ord, Eq, Show, Data, Typeable, Generic)+data ModFile = ModFile { mfFilename :: String+ , mfStringMap :: StringMap+ , mfModuleMap :: FAR.ModuleMap+ , mfDeclMap :: DeclMap+ , mfTypeEnv :: FAT.TypeEnv+ , mfParamVarMap :: ParamVarMap+ , mfOtherData :: M.Map String LB.ByteString }+ deriving (Eq, Ord, Show, Data, Typeable, Generic) instance Binary ModFile @@ -103,17 +115,17 @@ -- | Starting point. emptyModFile :: ModFile-emptyModFile = ModFile "" M.empty M.empty M.empty M.empty+emptyModFile = ModFile "" M.empty M.empty M.empty M.empty M.empty M.empty -- | Extracts the module map, declaration map and type analysis from -- an analysed and renamed ProgramFile, then inserts it into the -- ModFile. regenModFile :: forall a. Data a => F.ProgramFile (FA.Analysis a) -> ModFile -> ModFile-regenModFile pf mf = mf- { mfModuleMap = extractModuleMap pf- , mfDeclMap = extractDeclMap pf- , mfTypeEnv = FAT.extractTypeEnv pf- , mfFilename = F.pfGetFilename pf }+regenModFile pf mf = mf { mfModuleMap = extractModuleMap pf+ , mfDeclMap = extractDeclMap pf+ , mfTypeEnv = FAT.extractTypeEnv pf+ , mfParamVarMap = extractParamVarMap pf+ , mfFilename = F.pfGetFilename pf } -- | Generate a fresh ModFile from the module map, declaration map and -- type analysis of a given analysed and renamed ProgramFile.@@ -122,7 +134,7 @@ -- | Looks up the raw "other data" that may be stored in a ModFile by -- applications that make use of fortran-src.-lookupModFileData :: String -> ModFile -> Maybe B.ByteString+lookupModFileData :: String -> ModFile -> Maybe LB.ByteString lookupModFileData k = M.lookup k . mfOtherData -- | Get a list of the labels present in the "other data" of a@@ -134,7 +146,7 @@ -- be stored in a ModFile by applications that make use of -- fortran-src. See 'Data.Map.Strict.alter' for more information about -- the interface of this function.-alterModFileData :: (Maybe B.ByteString -> Maybe B.ByteString) -> String -> ModFile -> ModFile+alterModFileData :: (Maybe LB.ByteString -> Maybe LB.ByteString) -> String -> ModFile -> ModFile alterModFileData f k mf = mf { mfOtherData = M.alter f k . mfOtherData $ mf } -- For when stackage gets containers-0.5.8.1:@@ -142,14 +154,18 @@ -- alterModFileDataF f k mf = (\ od -> mf { mfOtherData = od }) <$> M.alterF f k (mfOtherData mf) -- | Convert ModFile to a strict ByteString for writing to file.-encodeModFile :: ModFile -> B.ByteString-encodeModFile = LB.toStrict . encode+encodeModFile :: ModFile -> LB.ByteString+encodeModFile mf = encode mf' { mfStringMap = sm }+ where+ (mf', sm) = extractStringMap (mf { mfStringMap = M.empty }) --- | Convert a strict ByteString to a ModFile, if possible-decodeModFile :: Binary a => B.ByteString -> Either String a-decodeModFile bs = case decodeOrFail (LB.fromStrict bs) of- Left (_, _, s) -> Left s- Right (_, _, mf) -> Right mf+-- | Convert a strict ByteString to a ModFile, if possible. Revert the+-- String aliases according to the StringMap.+decodeModFile :: LB.ByteString -> Either String ModFile+decodeModFile bs = case decodeOrFail bs of+ Left (_, _, s) -> Left s+ Right (_, _, mf) -> Right (revertStringMap sm mf { mfStringMap = M.empty }) { mfStringMap = sm }+ where sm = mfStringMap mf -- | Extract the combined module map from a set of ModFiles. Useful -- for parsing a Fortran file in a large context of other modules.@@ -167,6 +183,14 @@ combinedDeclMap :: ModFiles -> DeclMap combinedDeclMap = M.unions . map mfDeclMap +-- | Extract the combined string map of ModFiles. Mainly internal use.+combinedStringMap :: ModFiles -> StringMap+combinedStringMap = M.unions . map mfStringMap++-- | Extract the combined string map of ModFiles. Mainly internal use.+combinedParamVarMap :: ModFiles -> ParamVarMap+combinedParamVarMap = M.unions . map mfParamVarMap+ -- | Get the associated Fortran filename that was used to compile the -- ModFile. moduleFilename :: ModFile -> String@@ -189,10 +213,18 @@ -- | Extract all module maps (name -> environment) by collecting all -- of the stored module maps within the PUModule annotation. extractModuleMap :: forall a. Data a => F.ProgramFile (FA.Analysis a) -> FAR.ModuleMap-extractModuleMap pf = M.fromList [ (n, env) | pu@(F.PUModule {}) <- universeBi pf :: [F.ProgramUnit (FA.Analysis a)]- , let a = F.getAnnotation pu- , let n = F.getName pu- , env <- maybeToList (FA.moduleEnv a) ]+extractModuleMap pf+ -- in case there are no modules, store global program unit names under the name 'NamelessMain'+ | null mmap = M.singleton F.NamelessMain $ M.unions combinedEnv+ | otherwise = M.fromList mmap+ where+ mmap = [ (n, env) | pu@F.PUModule{} <- childrenBi pf :: [F.ProgramUnit (FA.Analysis a)]+ , let a = F.getAnnotation pu+ , let n = F.getName pu+ , env <- maybeToList (FA.moduleEnv a) ]+ combinedEnv = [ env | pu <- childrenBi pf :: [F.ProgramUnit (FA.Analysis a)]+ , let a = F.getAnnotation pu+ , env <- maybeToList (FA.moduleEnv a) ] -- | Extract map of declared variables with their associated program -- unit and source span.@@ -227,3 +259,41 @@ | otherwise -> error $ "nameAndBlocks: un-named function with no return value! " ++ show (FA.puName pu) ++ " at source-span " ++ show (P.getSpan pu) F.PUBlockData _ _ _ b -> (DCBlockData, Nothing, b) F.PUComment {} -> (DCBlockData, Nothing, []) -- no decls inside of comments, so ignore it++-- | Extract a string map from the given data, leaving behind aliased+-- values in place of strings in the returned version.+extractStringMap :: Data a => a -> (a, StringMap)+extractStringMap x = fmap (inv . fst) . flip runState (M.empty, 0) $ descendBiM f x+ where+ inv = M.fromList . map (\ (a,b) -> (b,a)) . M.toList+ f :: String -> State (StringMap, Int) String+ f s = do+ (m, n) <- get+ case M.lookup s m of+ Just s' -> return s'+ Nothing -> do+ let s' = '@':show n+ put (M.insert s s' m, n + 1)+ return s'++-- | Rewrite the data with the string map aliases replaced by the+-- actual values (implicitly sharing structure).+revertStringMap :: Data a => StringMap -> a -> a+revertStringMap sm = descendBi (\ s -> s `fromMaybe` M.lookup s sm)++-- | Extract a map of variables assigned to constant values.+extractParamVarMap :: forall a. Data a => F.ProgramFile (FA.Analysis a) -> ParamVarMap+extractParamVarMap pf = M.fromList cvm+ where+ pf' = FAD.analyseConstExps $ FAB.analyseBBlocks pf+ cvm = [ (FA.varName v, con)+ | F.PUModule _ _ _ bs _ <- universeBi pf' :: [F.ProgramUnit (FA.Analysis a)]+ , st@(F.StDeclaration _ _ (F.TypeSpec _ _ _ _) _ _) <- universeBi bs :: [F.Statement (FA.Analysis a)]+ , F.AttrParameter _ _ <- universeBi st :: [F.Attribute (FA.Analysis a)]+ , (F.DeclVariable _ _ v _ _) <- universeBi st :: [F.Declarator (FA.Analysis a)]+ , Just con <- [FA.constExp (F.getAnnotation v)] ] +++ [ (FA.varName v, con)+ | F.PUModule _ _ _ bs _ <- universeBi pf' :: [F.ProgramUnit (FA.Analysis a)]+ , st@F.StParameter {} <- universeBi bs :: [F.Statement (FA.Analysis a)]+ , (F.DeclVariable _ _ v _ _) <- universeBi st :: [F.Declarator (FA.Analysis a)]+ , Just con <- [FA.constExp (F.getAnnotation v)] ]
src/Language/Fortran/Util/Position.hs view
@@ -16,26 +16,40 @@ getPos :: a -> Position data Position = Position- { posAbsoluteOffset :: {-# UNPACK #-} !Int- , posColumn :: {-# UNPACK #-} !Int- , posLine :: {-# UNPACK #-} !Int+ { posAbsoluteOffset :: Int+ , posColumn :: Int+ , posLine :: Int+ , filePath :: String+ , posPragmaOffset :: Maybe (Int, String) -- ^ line-offset and filename as given by a pragma. } deriving (Eq, Ord, Data, Typeable, Generic) instance Binary Position instance Show Position where- show (Position _ c l) = show l ++ ':' : show c+ show (Position _ c l _ _) = show l ++ ':' : show c initPosition :: Position initPosition = Position { posAbsoluteOffset = 0 , posColumn = 1 , posLine = 1+ , filePath = ""+ , posPragmaOffset = Nothing } lineCol :: Position -> (Int, Int)-lineCol p = (fromIntegral $ posLine p, fromIntegral $ posColumn p)+lineCol p = (fromIntegral $ posLine p, fromIntegral $ posColumn p) +-- | (line, column) number taking into account any specified line pragmas.+apparentLineCol :: Position -> (Int, Int)+apparentLineCol (Position _ c l _ (Just (o, _))) = (l + o, c)+apparentLineCol (Position _ c l _ _) = (l, c)++-- | Path of file taking into account any specified line pragmas.+apparentFilePath :: Position -> String+apparentFilePath p | Just (_, f) <- posPragmaOffset p = f+ | otherwise = filePath p+ data SrcSpan = SrcSpan Position Position deriving (Eq, Ord, Typeable, Data, Generic) instance Binary SrcSpan@@ -49,12 +63,16 @@ -- Difference between the column of the upper and lower positions in a span columnDistance :: SrcSpan -> Int-columnDistance (SrcSpan (Position _ c1 _) (Position _ c2 _)) = c2 - c1+columnDistance (SrcSpan (Position _ c1 _ _ _) (Position _ c2 _ _ _)) = c2 - c1 -- Difference between the lines of the upper and lower positions in a span lineDistance :: SrcSpan -> Int-lineDistance (SrcSpan (Position _ _ l1) (Position _ _ l2)) = l2 - l1+lineDistance (SrcSpan (Position _ _ l1 _ _) (Position _ _ l2 _ _)) = l2 - l1 +-- List of lines that are spanned+spannedLines :: SrcSpan -> [Int]+spannedLines (SrcSpan (Position _ _ l1 _ _) (Position _ _ l2 _ _)) = [l1..l2]+ initSrcSpan :: SrcSpan initSrcSpan = SrcSpan initPosition initPosition @@ -67,7 +85,7 @@ setSpan :: SrcSpan -> a -> a default getSpan :: (SecondParameter a SrcSpan) => a -> SrcSpan- getSpan a = getSecondParameter a+ getSpan = getSecondParameter default setSpan :: (SecondParameter a SrcSpan) => SrcSpan -> a -> a- setSpan e a = setSecondParameter e a+ setSpan = setSecondParameter
src/Language/Fortran/Util/SecondParameter.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleContexts #-}@@ -14,10 +13,10 @@ setSecondParameter :: e -> a -> a default getSecondParameter :: (Generic a, GSecondParameter (Rep a) e) => a -> e- getSecondParameter a = getSecondParameter' . from $ a+ getSecondParameter = getSecondParameter' . from default setSecondParameter :: (Generic a, GSecondParameter (Rep a) e) => e -> a -> a- setSecondParameter e a = to . setSecondParameter' e . from $ a+ setSecondParameter e = to . setSecondParameter' e . from class GSecondParameter f e where getSecondParameter' :: f a -> e@@ -63,7 +62,7 @@ instance {-# OVERLAPPING #-} GSecondParameter' (K1 i e) e where getSecondParameter'' (K1 a) = a- setSecondParameter'' e (K1 a) = K1 e+ setSecondParameter'' e (K1 _) = K1 e instance {-# OVERLAPPABLE #-} GSecondParameter' (K1 i a) e where getSecondParameter'' _ = undefined
src/Main.hs view
@@ -1,35 +1,38 @@-{-# LANGUAGE FlexibleContexts, FlexibleInstances, ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts, FlexibleInstances, ScopedTypeVariables, OverloadedStrings #-}+{-# OPTIONS_GHC -Wno-orphans #-} module Main where import Prelude hiding (readFile) import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Lazy.Char8 as LB import Data.Text.Encoding (encodeUtf8, decodeUtf8With) import Data.Text.Encoding.Error (replace) import Text.PrettyPrint (render)-import Text.Read import System.Console.GetOpt-+import System.IO import System.Environment import System.Directory import System.FilePath import Text.PrettyPrint.GenericPretty (pp, pretty, Out)-import Data.List (isInfixOf, intercalate, (\\))+import Text.Read (readMaybe)+import Data.List (sortBy, intercalate, (\\), isSuffixOf)+import Data.Ord (comparing) import Data.Char (toLower)-import Data.Maybe (fromMaybe, maybeToList)+import Data.Maybe (listToMaybe, fromMaybe, maybeToList) import Data.Data-import Data.Binary import Data.Generics.Uniplate.Data -import Language.Fortran.ParserMonad (FortranVersion(..), fromRight)+import Language.Fortran.ParserMonad (selectFortranVersion, FortranVersion(..), fromRight) import qualified Language.Fortran.Lexer.FixedForm as FixedForm (collectFixedTokens, Token(..)) import qualified Language.Fortran.Lexer.FreeForm as FreeForm (collectFreeTokens, Token(..)) import Language.Fortran.Parser.Any import Language.Fortran.Util.ModFile+import Language.Fortran.Util.Position import Language.Fortran.PrettyPrint import Language.Fortran.Analysis@@ -38,13 +41,14 @@ import Language.Fortran.Analysis.BBlocks import Language.Fortran.Analysis.DataFlow import Language.Fortran.Analysis.Renaming-import Data.Graph.Inductive hiding (trc)+import Data.Graph.Inductive hiding (trc, mf, version) import qualified Data.IntMap as IM import qualified Data.Map as M import Control.Monad import Text.Printf +programName :: String programName = "fortran-src" main :: IO ()@@ -52,38 +56,32 @@ args <- getArgs (opts, parsedArgs) <- compileArgs args case (parsedArgs, action opts) of- ([path], DumpModFile) -> do- let path = head parsedArgs- contents <- B.readFile path- case decodeModFile contents of- Left msg -> putStrLn $ "Error: " ++ msg- Right mf -> putStrLn $ "Filename: " ++ moduleFilename mf ++- "\n\nModuleMap:\n" ++ showModuleMap (combinedModuleMap [mf]) ++- "\n\nTypeEnv:\n" ++ showTypes (combinedTypeEnv [mf]) ++- "\n\nDeclMap:\n" ++ showGenericMap (combinedDeclMap [mf]) ++- "\n\nOther Data Labels: " ++ show (getLabelsModFileData mf)- ([path], actionOpt) -> do- let path = head parsedArgs contents <- flexReadFile path let version = fromMaybe (deduceVersion path) (fortranVersion opts) let (Just parserF0) = lookup version parserWithModFilesVersions- let parserF = \m b s -> fromRight (parserF0 m b s)+ let parserF m b s = fromRight (parserF0 m b s) let outfmt = outputFormat opts mods <- decodeModFiles $ includeDirs opts let mmap = combinedModuleMap mods let tenv = combinedTypeEnv mods+ let pvm = combinedParamVarMap mods - let runInfer pf = analyseTypesWithEnv tenv . analyseRenamesWithModuleMap mmap . initAnalysis $ pf+ let runTypes = analyseAndCheckTypesWithEnv tenv . analyseRenamesWithModuleMap mmap . initAnalysis let runRenamer = stripAnalysis . rename . analyseRenamesWithModuleMap mmap . initAnalysis let runBBlocks pf = showBBlocks pf' ++ "\n\n" ++ showDataFlow pf'- where pf' = analyseBBlocks . analyseRenamesWithModuleMap mmap . initAnalysis $ pf+ where pf' = analyseParameterVars pvm . analyseBBlocks . analyseRenamesWithModuleMap mmap . initAnalysis $ pf let runSuperGraph pf | outfmt == DOT = superBBGrToDOT sgr | otherwise = superGraphDataFlow pf' sgr- where pf' = analyseBBlocks . analyseRenamesWithModuleMap mmap . initAnalysis $ pf+ where pf' = analyseParameterVars pvm . analyseBBlocks . analyseRenamesWithModuleMap mmap . initAnalysis $ pf bbm = genBBlockMap pf' sgr = genSuperBBGr bbm-+ let runCompile = encodeModFile . genModFile . fst . analyseTypesWithEnv tenv . analyseRenamesWithModuleMap mmap . initAnalysis+ let findBlockPU pf astBlockId = listToMaybe+ [ pu | pu <- universeBi pf :: [ProgramUnit (Analysis A0)]+ , bbgr <- maybeToList (bBlocks (getAnnotation pu))+ , b <- concatMap snd $ labNodes (bbgrGr bbgr)+ , insLabel (getAnnotation b) == Just astBlockId ] case actionOpt of Lex | version `elem` [ Fortran66, Fortran77, Fortran77Extended, Fortran77Legacy ] -> print $ FixedForm.collectFixedTokens version contents@@ -91,57 +89,127 @@ print $ FreeForm.collectFreeTokens version contents Lex -> ioError $ userError $ usageInfo programName options Parse -> pp $ parserF mods contents path- Typecheck -> printTypes . extractTypeEnv . fst . runInfer $ parserF mods contents path+ Typecheck -> let (pf, _, errs) = runTypes (parserF mods contents path) in+ printTypeErrors errs >> printTypes (extractTypeEnv pf) Rename -> pp . runRenamer $ parserF mods contents path BBlocks -> putStrLn . runBBlocks $ parserF mods contents path SuperGraph -> putStrLn . runSuperGraph $ parserF mods contents path Reprint -> putStrLn . render . flip (pprint version) (Just 0) $ parserF mods contents path-+ Compile -> do+ let bytes = runCompile $ parserF mods contents path+ let fspath = path <.> modFileSuffix+ LB.writeFile fspath bytes+ DumpModFile -> do+ let path' = if modFileSuffix `isSuffixOf` path then path else path <.> modFileSuffix+ contents' <- LB.readFile path'+ case decodeModFile contents' of+ Left msg -> putStrLn $ "Error: " ++ msg+ Right mf -> putStrLn $ "Filename: " ++ moduleFilename mf +++ "\n\nStringMap:\n" ++ showStringMap (combinedStringMap [mf]) +++ "\n\nModuleMap:\n" ++ showModuleMap (combinedModuleMap [mf]) +++ "\n\nDeclMap:\n" ++ showGenericMap (combinedDeclMap [mf]) +++ "\n\nTypeEnv:\n" ++ showTypes (combinedTypeEnv [mf]) +++ "\n\nParamVarMap:\n" ++ showGenericMap (combinedParamVarMap [mf]) +++ "\n\nOther Data Labels: " ++ show (getLabelsModFileData mf)+ ShowFlows isFrom isSuper astBlockId -> do+ let pf = analyseParameterVars pvm .+ analyseBBlocks .+ analyseRenamesWithModuleMap mmap .+ initAnalysis $ parserF mods contents path+ let bbm = genBBlockMap pf+ case (isSuper, findBlockPU pf astBlockId) of+ (False, Nothing) -> fail "Couldn't find given AST block ID number."+ (False, Just pu)+ | Just bbgr <- M.lookup (puName pu) bbm ->+ putStrLn $ showFlowsDOT pf bbgr astBlockId isFrom+ | otherwise -> do+ print $ M.keys bbm+ fail $ "Internal error: Program Unit " ++ show (puName pu) ++ " is lacking a basic block graph."+ (True, _) -> do+ let sgr = genSuperBBGr bbm+ putStrLn $ showFlowsDOT pf (superBBGrGraph sgr) astBlockId isFrom+ ShowBlocks mlinenum -> do+ let pf = analyseBBlocks .+ analyseRenamesWithModuleMap mmap .+ initAnalysis $ parserF mods contents path+ let f :: ([ASTBlockNode], Int) -> ([ASTBlockNode], Int) -> ([ASTBlockNode], Int)+ f (nodes1, len1) (nodes2, len2)+ | len1 < len2 = (nodes1, len1)+ | len2 < len1 = (nodes2, len2)+ | otherwise = (nodes1 ++ nodes2, len1)+ let lineMap :: IM.IntMap ([ASTBlockNode], Int) -- ([list of IDs], line-distance of span)+ lineMap = IM.fromListWith f [+ (l, ([i], lineDistance ss))+ | b <- universeBi pf :: [Block (Analysis A0)]+ , i <- maybeToList . insLabel $ getAnnotation b+ , let ss = getSpan b+ , l <- spannedLines ss+ ]+ case mlinenum of+ Just l -> putStrLn . unwords . map show $ fromMaybe [] (fst <$> IM.lookup l lineMap)+ Nothing -> do+ let lineBs = B.lines contents+ let maxLen = maximum (0:map B.length lineBs)+ forM_ (zip lineBs [1..]) $ \ (line, l) -> do+ let nodeIDs = fromMaybe [] (fst <$> IM.lookup l lineMap)+ let nodeStr = B.intercalate "," (map (B.pack . ('B':) . show) nodeIDs)+ let suffix | null nodeIDs = ""+ | otherwise = B.replicate (maxLen - B.length line + 1) ' ' <> "!" <> nodeStr+ B.putStrLn $ line <> suffix _ -> fail $ usageInfo programName options --- List files in dir+-- List files in dir recursively rGetDirContents :: String -> IO [String] rGetDirContents d = canonicalizePath d >>= \d' -> go [d'] d' where- go seen d = do- ds <- getDirectoryContents d+ go seen d'' = do+ ds <- getDirectoryContents d'' fmap concat . mapM f $ ds \\ [".", ".."] -- remove '.' and '..' entries where f x = do path <- canonicalizePath $ d ++ "/" ++ x g <- doesDirectoryExist path- if g && not (path `elem` seen) then do+ if g && notElem path seen then do x' <- go (path : seen) path return $ map (\ y -> x ++ "/" ++ y) x' else return [x] +-- List files in dir+getDirContents :: String -> IO [String]+getDirContents d = do+ d' <- canonicalizePath d+ map (d' </>) `fmap` listDirectory d'+ decodeModFiles :: [String] -> IO ModFiles decodeModFiles = foldM (\ modFiles d -> do -- Figure out the camfort mod files and parse them.- modFileNames <- filter isModFile `fmap` rGetDirContents d+ modFileNames <- filter isModFile `fmap` getDirContents d addedModFiles <- forM modFileNames $ \ modFileName -> do- eResult <- decodeFileOrFail (d </> modFileName)- case eResult of- Left (offset, msg) -> do- putStrLn $ modFileName ++ ": Error at offset " ++ show offset ++ ": " ++ msg+ contents <- LB.readFile (d </> modFileName)+ case decodeModFile contents of+ Left msg -> do+ hPutStrLn stderr $ modFileName ++ ": Error: " ++ msg return emptyModFile Right modFile -> do- putStrLn $ modFileName ++ ": successfully parsed precompiled file."+ hPutStrLn stderr $ modFileName ++ ": successfully parsed precompiled file." return modFile return $ addedModFiles ++ modFiles ) emptyModFiles +isModFile :: FilePath -> Bool isModFile = (== modFileSuffix) . takeExtension superGraphDataFlow :: forall a. (Out a, Data a) => ProgramFile (Analysis a) -> SuperBBGr (Analysis a) -> String-superGraphDataFlow pf sgr = showBBGr (nmap (map (fmap insLabel)) gr) ++ "\n\n" ++ replicate 50 '-' ++ "\n\n" +++superGraphDataFlow pf sgr = showBBGr (bbgrMap (nmap (map (fmap insLabel))) gr') ++ "\n\n" ++ replicate 50 '-' ++ "\n\n" ++ show entries ++ "\n\n" ++ replicate 50 '-' ++ "\n\n" ++- dfStr gr+ dfStr gr' where- gr = superBBGrGraph sgr+ gr' = superBBGrGraph sgr entries = superBBGrEntries sgr dfStr gr = (\ (l, x) -> '\n':l ++ ": " ++ x) =<< [ ("callMap", show cm)+ , ("entries", show (bbgrEntries gr))+ , ("exits", show (bbgrExits gr)) , ("postOrder", show (postOrder gr)) , ("revPostOrder", show (revPostOrder gr)) , ("revPreOrder", show (revPreOrder gr))@@ -151,22 +219,22 @@ , ("lva", show (IM.toList $ lva gr)) , ("rd", show (IM.toList rDefs)) , ("backEdges", show bedges)- , ("topsort", show (topsort gr))- , ("scc ", show (scc gr))- , ("loopNodes", show (loopNodes bedges gr))+ , ("topsort", show (topsort $ bbgrGr gr))+ , ("scc ", show (scc $ bbgrGr gr))+ , ("loopNodes", show (loopNodes bedges $ bbgrGr gr)) , ("duMap", show (genDUMap bm dm gr rDefs)) , ("udMap", show (genUDMap bm dm gr rDefs)) , ("flowsTo", show (edges flTo)) , ("varFlowsTo", show (genVarFlowsToMap dm flTo)) , ("ivMap", show (genInductionVarMap bedges gr))- , ("noPredNodes", show (noPredNodes gr)) , ("blockMap", unlines [ "AST-block " ++ show i ++ ":\n" ++ pretty b | (i, b) <- IM.toList bm ]) , ("derivedInd", unlines [ "Expression " ++ show i ++ " (IE: " ++ show ie ++ "):\n" ++ pretty e | e <- universeBi bm :: [Expression (Analysis a)] , i <- maybeToList (insLabel (getAnnotation e)) , let ie = IM.lookup i diMap ])+ , ("constExpMap", show (genConstExpMap pf)) ] where- bedges = genBackEdgeMap (dominators gr) gr+ bedges = genBackEdgeMap (dominators gr) $ bbgrGr gr flTo = genFlowsToGraph bm dm gr rDefs rDefs = rd gr diMap = genDerivedInductionMap bedges gr@@ -178,7 +246,8 @@ showGenericMap :: (Show a, Show b) => M.Map a b -> String showGenericMap = unlines . map (\ (k, v) -> show k ++ " : " ++ show v) . M.toList-+showStringMap :: StringMap -> String+showStringMap = showGenericMap showModuleMap :: ModuleMap -> String showModuleMap = concatMap (\ (n, m) -> show n ++ ":\n" ++ (unlines . map (" "++) . lines . showGenericMap $ m)) . M.toList showTypes :: TypeEnv -> String@@ -186,13 +255,20 @@ printf "%s\t\t%s %s\n" name (drop 4 $ maybe " -" show vt) (drop 2 $ maybe " " show ct) printTypes :: TypeEnv -> IO () printTypes = putStrLn . showTypes+showTypeErrors :: [TypeError] -> String+showTypeErrors errs = unlines [ show ss ++ ": " ++ msg | (msg, ss) <- sortBy (comparing snd) errs ]+printTypeErrors :: [TypeError] -> IO ()+printTypeErrors = putStrLn . showTypeErrors -data Action = Lex | Parse | Typecheck | Rename | BBlocks | SuperGraph | Reprint | DumpModFile deriving Eq+data Action+ = Lex | Parse | Typecheck | Rename | BBlocks | SuperGraph | Reprint | DumpModFile | Compile+ | ShowFlows Bool Bool Int | ShowBlocks (Maybe Int)+ deriving Eq instance Read Action where readsPrec _ value =- let options = [ ("lex", Lex) , ("parse", Parse) ] in- tryTypes options+ let options' = [ ("lex", Lex) , ("parse", Parse) ] in+ tryTypes options' where tryTypes [] = [] tryTypes ((attempt,result):xs) =@@ -206,13 +282,14 @@ , outputFormat :: OutputFormat , includeDirs :: [String] } +initOptions :: Options initOptions = Options Nothing Parse Default [] options :: [OptDescr (Options -> Options)] options =- [ Option ['v']+ [ Option ['v','F'] ["fortranVersion"]- (ReqArg (\v opts -> opts { fortranVersion = readMaybe v }) "VERSION")+ (ReqArg (\v opts -> opts { fortranVersion = selectFortranVersion v }) "VERSION") "Fortran version to use, format: Fortran[66/77/77Legacy/77Extended/90]" , Option ['a'] ["action"]@@ -250,6 +327,29 @@ ["include-dir"] (ReqArg (\ d opts -> opts { includeDirs = d:includeDirs opts }) "DIR") "directory to search for precompiled 'mod files'"+ , Option ['c']+ ["compile"]+ (NoArg $ \ opts -> opts { action = Compile })+ "compile an .fsmod file from the input"+ , Option []+ ["show-block-numbers"]+ (OptArg (\a opts -> opts { action = ShowBlocks (a >>= readMaybe) }+ ) "LINE-NUM")+ "Show the corresponding AST-block identifier number next to every line of code."+ , Option []+ ["show-flows-to"]+ (ReqArg (\a opts -> case a of s:num | toLower s == 's' -> opts { action = ShowFlows False True (read num) }+ b:num | toLower b == 'b' -> opts { action = ShowFlows False False (read num) }+ num -> opts { action = ShowFlows False False (read num) }+ ) "AST-BLOCK-ID")+ "dump a graph showing flows-to information from the given AST-block ID; prefix with 's' for supergraph"+ , Option []+ ["show-flows-from"]+ (ReqArg (\a opts -> case a of s:num | toLower s == 's' -> opts { action = ShowFlows True True (read num) }+ b:num | toLower b == 'b' -> opts { action = ShowFlows True False (read num) }+ num -> opts { action = ShowFlows True False (read num) }+ ) "AST-BLOCK-ID")+ "dump a graph showing flows-from information from the given AST-block ID; prefix with 's' for supergraph" ] compileArgs :: [ String ] -> IO (Options, [ String ])@@ -258,24 +358,7 @@ (o, n, []) -> return (foldl (flip id) initOptions o, n) (_, _, errors) -> ioError $ userError $ concat errors ++ usageInfo header options where- header = "Usage: forpar [OPTION...] <lex|parse> <file>"--instance Read FortranVersion where- readsPrec _ value = tryTypes options- where- value' = map toLower value- options = [ ("66" , Fortran66)- , ("77e", Fortran77Extended)- , ("77l", Fortran77Legacy)- , ("77" , Fortran77)- , ("90" , Fortran90)- , ("95" , Fortran95)- , ("03" , Fortran2003)- , ("08" , Fortran2008) ]- tryTypes [] = []- tryTypes ((attempt,result):xs)- | attempt `isInfixOf` value' = [(result, "")]- | otherwise = tryTypes xs+ header = "Usage: " ++ programName ++ " [OPTION...] <file>" instance {-# OVERLAPPING #-} Show [ FixedForm.Token ] where show = unlines . lines'
test/Language/Fortran/Analysis/BBlocksSpec.hs view
@@ -1,11 +1,9 @@ module Language.Fortran.Analysis.BBlocksSpec where import Test.Hspec-import TestUtil import Language.Fortran.Parser.Fortran77-import Language.Fortran.Lexer.FixedForm (initParseState)-import Language.Fortran.ParserMonad (FortranVersion(..), evalParse, fromParseResultUnsafe)+import Language.Fortran.ParserMonad (fromParseResultUnsafe) import Language.Fortran.AST import Language.Fortran.Analysis import Language.Fortran.Analysis.BBlocks@@ -13,7 +11,6 @@ import qualified Data.Map as M import qualified Data.IntSet as IS import Data.Graph.Inductive-import Data.Graph.Inductive.PatriciaTree (Gr) import Data.Maybe import qualified Data.ByteString.Char8 as B @@ -25,34 +22,27 @@ spec = describe "Basic Blocks" $ do describe "loop4" $ do- it "nodes and edges length" $ do- let pf = pParser programLoop4- let gr = fromJust . M.lookup (Named "loop4") $ genBBlockMap pf- let ns = nodes gr- let es = edges gr+ let pf = pParser programLoop4+ gr = fromJust . M.lookup (Named "loop4") $ genBBlockMap pf+ ns = nodes $ bbgrGr gr+ es = edges $ bbgrGr gr+ nodeSet = IS.fromList ns+ it "nodes and edges length" $ (length ns, length es) `shouldBe` (11, 12)- it "branching nodes" $ do- let pf = pParser programLoop4- let gr = fromJust . M.lookup (Named "loop4") $ genBBlockMap pf+ it "branching nodes" $ (IS.size (findSuccsBB gr [10]), IS.size (findSuccsBB gr [20])) `shouldBe` (2, 2) it "all reachable" $ do- let pf = pParser programLoop4- let gr = fromJust . M.lookup (Named "loop4") $ genBBlockMap pf- let reached = IS.fromList $ dfs [0] gr- let nodeSet = IS.fromList $ nodes gr+ let reached = IS.fromList . dfs [0] $ bbgrGr gr reached `shouldBe` nodeSet it "all terminate" $ do- let pf = pParser programLoop4- let gr = fromJust . M.lookup (Named "loop4") $ genBBlockMap pf- let reached = IS.fromList $ rdfs [-1] gr- let nodeSet = IS.fromList $ nodes gr+ let reached = IS.fromList . rdfs [-1] $ bbgrGr gr reached `shouldBe` nodeSet describe "if arith" $ do it "nodes and edges length" $ do let pf = pParser programArithIf let gr = fromJust . M.lookup (Named "arithif") $ genBBlockMap pf- let ns = nodes gr- let es = edges gr+ let ns = nodes $ bbgrGr gr+ let es = edges $ bbgrGr gr (length ns, length es) `shouldBe` (6, 7) it "branching nodes" $ do let pf = pParser programArithIf@@ -61,15 +51,83 @@ it "all reachable" $ do let pf = pParser programArithIf let gr = fromJust . M.lookup (Named "arithif") $ genBBlockMap pf- let reached = IS.fromList $ dfs [0] gr- let nodeSet = IS.fromList $ nodes gr+ let reached = IS.fromList . dfs [0] $ bbgrGr gr+ let nodeSet = IS.fromList . nodes $ bbgrGr gr reached `shouldBe` nodeSet it "all terminate" $ do let pf = pParser programArithIf let gr = fromJust . M.lookup (Named "arithif") $ genBBlockMap pf- let reached = IS.fromList $ rdfs [-1] gr- let nodeSet = IS.fromList $ nodes gr+ let reached = IS.fromList . rdfs [-1] $ bbgrGr gr+ let nodeSet = IS.fromList . nodes $ bbgrGr gr reached `shouldBe` nodeSet+ describe "gotos" $ do+ let pf = pParser programGotos+ gr = fromJust . M.lookup (Named "_gotos1") $ genBBlockMap pf+ ns = nodes $ bbgrGr gr+ es = edges $ bbgrGr gr+ nodeSet = IS.fromList ns+ it "nodes and edges length" $ do+ (length ns, length es) `shouldBe` (10, 12)+ it "branching nodes" $+ (IS.size (findSuccsBB gr [10]), IS.size (findSuccsBB gr [20])) `shouldBe` (3, 1)+ it "all reachable" $ do+ let reached = IS.fromList . dfs [0] $ bbgrGr gr+ reached `shouldBe` nodeSet+ it "all terminate" $ do+ let reached = IS.fromList . rdfs [-1] $ bbgrGr gr+ reached `shouldBe` nodeSet+ describe "READ" $ do+ let pf = pParser programRead+ gr = fromJust . M.lookup (Named "reading_time") $ genBBlockMap pf+ ns = nodes $ bbgrGr gr+ es = edges $ bbgrGr gr+ nodeSet = IS.fromList ns+ it "nodes and edges length" $ do+ (length ns, length es) `shouldBe` (10, 11)+ it "branching nodes" $ do+ let succs l = IS.size $ findSuccsBB gr [l]+ (succs 10, succs 20, succs 40, succs 60) `shouldBe` (3, 1, 1, 1)+ it "all reachable" $ do+ let reached = IS.fromList . dfs [0] $ bbgrGr gr+ reached `shouldBe` nodeSet+ it "all terminate" $ do+ let reached = IS.fromList . rdfs [-1] $ bbgrGr gr+ reached `shouldBe` nodeSet+ describe "Leading zero labels" $ do+ let pf = pParser programZeroLabels+ gr = fromJust . M.lookup (Named "zero_labels") $ genBBlockMap pf+ ns = nodes $ bbgrGr gr+ es = edges $ bbgrGr gr+ nodeSet = IS.fromList ns+ it "nodes and edges length" $ do+ (length ns, length es) `shouldBe` (13, 15)+ it "branching nodes" $ do+ let succs l = IS.size $ findSuccsBB gr [l]+ (succs 10, succs 20, succs 40, succs 60, succs 80) `shouldBe` (4, 1, 1, 1, 1)+ it "all reachable" $ do+ let reached = IS.fromList . dfs [0] $ bbgrGr gr+ reached `shouldBe` nodeSet+ it "all terminate" $ do+ let reached = IS.fromList . rdfs [-1] $ bbgrGr gr+ reached `shouldBe` nodeSet+ describe "nested calls" $ do+ let pf = pParser programNestedCalls+ gr = fromJust . M.lookup (Named "nestedcall") $ genBBlockMap pf+ ns = nodes $ bbgrGr gr+ es = edges $ bbgrGr gr+ nodeSet = IS.fromList ns+ it "nodes and edges length" $ do+ (length ns, length es) `shouldBe` (10, 9)+ -- it "branching nodes" $+ -- (IS.size (findSuccsBB gr [10]), IS.size (findSuccsBB gr [20])) `shouldBe` (3, 1)+ it "all reachable" $ do+ let reached = IS.fromList . dfs [0] $ bbgrGr gr+ reached `shouldBe` nodeSet+ it "all terminate" $ do+ let reached = IS.fromList . rdfs [-1] $ bbgrGr gr+ reached `shouldBe` nodeSet+ it "straight-line program" $ do+ [ length (suc (bbgrGr gr) n) | n <- ns, n /= -1 ] `shouldSatisfy` all (== 1) -------------------------------------------------- -- Label-finding helper functions to help write tests that are@@ -86,11 +144,12 @@ -- For each label in the list, find the successors of the -- corresponding basic block, return as an IntSet. findSuccsBB :: BBGr a -> [Int] -> IS.IntSet-findSuccsBB gr = IS.fromList . concatMap (suc gr) . mapMaybe (flip findLabeledBBlock gr . show)+findSuccsBB gr = IS.fromList . concatMap (suc $ bbgrGr gr) . mapMaybe (flip findLabeledBBlock gr . show) -------------------------------------------------- -- Test programs +programLoop4 :: String programLoop4 = unlines [ " program loop4" , " integer r, i, j"@@ -117,6 +176,7 @@ , " end" ] +programArithIf :: String programArithIf = unlines [ " program arithif" , " integer n"@@ -126,6 +186,58 @@ , " 20 write (*,*) 20" , " 30 write (*,*) 30" , " end"]++programGotos :: String+programGotos = unlines [+ " subroutine gotos(s)"+ , " integer s"+ , " character a"+ , " a = 'H'"+ , " 10 goto (30, 40) s"+ , " 20 goto 999"+ , " 30 continue"+ , " if (a .eq. 'G') then"+ , " print *, 'almost there'"+ , " endif"+ , " 40 continue"+ , "999 print *, 'all done'"+ , " end" ]++programRead :: String+programRead = unlines [+ " program reading_time"+ , " integer i"+ , " 10 read(*, *, END=30, ERR=50) i"+ , " 20 goto 70"+ , " 30 print *, 'end'"+ , " 40 goto 70"+ , " 50 print *, 'err'"+ , " 60 goto 70"+ , " 70 print *, 'done'"+ , " print *, i"+ , " end" ]++programZeroLabels :: String+programZeroLabels = unlines [+ " program zero_labels"+ , " integer i"+ , " 10 goto (30, 50, 70) i"+ , " 20 goto 999"+ , " 30 print *, '30'"+ , " 40 goto 900"+ , " 050 print *, '050'"+ , " 60 goto 900"+ , " 070 print *, '070'"+ , " 80 goto 0900"+ , " 0900 print *, '0900'"+ , " 999 continue"+ , " end" ]++programNestedCalls :: String+programNestedCalls = unlines [+ " program nestedcall"+ , " call foo(bar(baz(1)))"+ , " end" ] -- Local variables:
test/Language/Fortran/Analysis/DataFlowSpec.hs view
@@ -6,25 +6,26 @@ import Language.Fortran.Parser.Fortran77 import qualified Language.Fortran.Parser.Fortran90 as F90-import Language.Fortran.Lexer.FixedForm (initParseState)-import Language.Fortran.ParserMonad (FortranVersion(..), evalParse, fromParseResultUnsafe)+import Language.Fortran.ParserMonad (fromParseResultUnsafe) import Language.Fortran.AST import Language.Fortran.Analysis-import Language.Fortran.Analysis.Renaming hiding (extractNameMap, underRenaming)+import Language.Fortran.Analysis.Renaming import Language.Fortran.Analysis.BBlocks import Language.Fortran.Analysis.DataFlow import qualified Data.Map as M import qualified Data.Set as S import qualified Data.IntMap as IM import qualified Data.IntSet as IS-import Data.Graph.Inductive-import Data.Graph.Inductive.PatriciaTree (Gr)+import Data.Graph.Inductive hiding (version, lab') import Data.Maybe import Data.List import Data.Data import Data.Generics.Uniplate.Operations import qualified Data.ByteString.Char8 as B+import Control.Arrow ((&&&)) +{-# ANN module "HLint: ignore Reduce duplication" #-}+ data F77 = F77 data F90 = F90 @@ -42,53 +43,49 @@ withParse :: Data a => Parser t => t -> String -> (ProgramFile (Analysis A0) -> a) -> a withParse version source f = underRenaming (f . analyseBBlocks) (parser version source "<unknown>") +testGraph :: Parser t => t -> String -> String -> BBGr (Analysis A0) testGraph version f p = fromJust . M.lookup (Named f) . withParse version p $ genBBlockMap+testPfAndGraph :: Parser t => t -> String -> String -> (ProgramFile (Analysis A0), BBGr (Analysis A0)) testPfAndGraph version f p = fmap (fromJust . M.lookup (Named f)) . withParse version p $ \ pf -> (pf, genBBlockMap pf) +testGenDefMap :: Parser t => t -> String -> DefMap testGenDefMap version = flip (withParse version) (genDefMap . genBlockMap . analyseBBlocks . initAnalysis) +testBackEdges :: Parser t => t -> String -> String -> BackEdgeMap testBackEdges version f p = bedges where gr = testGraph version f p domMap = dominators gr- bedges = genBackEdgeMap domMap gr+ bedges = genBackEdgeMap domMap $ bbgrGr gr spec :: Spec spec = describe "Dataflow" $ do- ----------------------------------------------- let pf = pParser F77 programLoop4 describe "loop4" $ do+ let pf = pParser F77 programLoop4+ bm = genBlockMap pf+ dm = genDefMap bm it "genBackEdgeMap" $ do let gr = testGraph F77 "loop4" programLoop4 testBackEdges F77 "loop4" programLoop4 `shouldBe` IM.fromList [(findLabelBB gr 8, findLabelBB gr 10), (findLabelBB gr 7, findLabelBB gr 20)] + let gr = fromJust . M.lookup (Named "loop4") $ genBBlockMap pf it "loopNodes" $ do- let pf = pParser F77 programLoop4- let gr = fromJust . M.lookup (Named "loop4") $ genBBlockMap pf let domMap = dominators gr- let bedges = genBackEdgeMap domMap gr- S.fromList (loopNodes bedges gr) `shouldBe`+ bedges = genBackEdgeMap domMap $ bbgrGr gr+ S.fromList (loopNodes bedges $ bbgrGr gr) `shouldBe` S.fromList [findLabelsBB gr [5,6,7,20], IS.unions [findLabelsBB gr [4,5,6,7,8,10,20,30], findSuccsBB gr [20]]] it "genDefMap" $ testGenDefMap F77 programLoop4 `shouldBe` M.fromList [("i",findLabelsBl pf [3,30]),("j",findLabelsBl pf [4,6]),("r",findLabelsBl pf [2,5])] - it "reachingDefinitions" $ do- let pf = pParser F77 programLoop4- let gr = fromJust . M.lookup (Named "loop4") $ genBBlockMap pf- let bm = genBlockMap pf- let dm = genDefMap bm+ it "reachingDefinitions" $ IM.lookup (findLabelBB gr 5) (reachingDefinitions dm gr) `shouldBe` Just (findLabelsBl pf [2,3,4,5,6,30], findLabelsBl pf [3,4,5,6,30]) - it "flowsTo" $ do- let pf = pParser F77 programLoop4- let gr = fromJust . M.lookup (Named "loop4") $ genBBlockMap pf- let bm = genBlockMap pf- let dm = genDefMap bm+ it "flowsTo" $ (S.fromList . edges . genFlowsToGraph bm dm gr $ reachingDefinitions dm gr) `shouldBe` -- Find the flows of the assignment statements in the program. findLabelsBlEdges pf [(2,5),(2,40) -- r = 0@@ -100,33 +97,33 @@ ] ----------------------------------------------- let pf = pParser F90 programLoop4Alt- let sgr = genSuperBBGr (genBBlockMap pf)- let gr = superBBGrGraph sgr- let domMap = dominators gr- let bedges = genBackEdgeMap domMap gr- let bm = genBlockMap pf- let dm = genDefMap bm describe "loop4 alt (module)" $ do+ let pf = pParser F90 programLoop4Alt+ sgr = genSuperBBGr (genBBlockMap pf)+ bm = genBlockMap pf+ dm = genDefMap bm+ gr = superBBGrGraph sgr+ domMap = dominators gr+ bedges = genBackEdgeMap domMap $ bbgrGr gr it "genBackEdgeMap" $ do- let gr = testGraph F90 "loop4" programLoop4Alt+ let gr' = testGraph F90 "loop4" programLoop4Alt testBackEdges F90 "loop4" programLoop4Alt `shouldBe`- IM.fromList [(findLabelBB gr 22, findLabelBB gr 20), (findLabelBB gr 31, findLabelBB gr 10)]+ IM.fromList [(findLabelBB gr' 22, findLabelBB gr' 20), (findLabelBB gr' 31, findLabelBB gr' 10)] - it "loopNodes" $ do- S.fromList (loopNodes bedges gr) `shouldBe`+ it "loopNodes" $+ S.fromList (loopNodes bedges $ bbgrGr gr) `shouldBe` S.fromList [findLabelsBB gr [20,21,22], findLabelsBB gr [10,11,20,21,22,31,40]] it "genDefMap" $ testGenDefMap F90 programLoop4Alt `shouldBe` M.fromList [("i",findLabelsBl pf [2,31]),("j",findLabelsBl pf [11,22]),("r",findLabelsBl pf [1,21])] - it "reachingDefinitions" $ do+ it "reachingDefinitions" $ IM.lookup (findLabelBB gr 21) (reachingDefinitions dm gr) `shouldBe` Just (findLabelsBl pf [1,2,11,21,22,31], findLabelsBl pf [2,11,21,22,31]) - it "flowsTo" $ do+ it "flowsTo" $ (S.fromList . edges . genFlowsToGraph bm dm gr $ reachingDefinitions dm gr) `shouldBe` -- Find the flows of the assignment statements in the program. findLabelsBlEdges pf [(1,21),(1,41) -- r = 0@@ -140,29 +137,25 @@ ----------------------------------------------- describe "rd3" $ do+ let (pf, gr) = testPfAndGraph F77 "f" programRd3+ bm = genBlockMap pf+ dm = genDefMap bm it "genBackEdgeMap" $ do- let gr = testGraph F77 "f" programRd3- testBackEdges F77 "f" programRd3 `shouldBe` IM.singleton (findLabelBB gr 4) (findLabelBB gr 1)+ let gr' = testGraph F77 "f" programRd3+ testBackEdges F77 "f" programRd3 `shouldBe` IM.singleton (findLabelBB gr 4) (findLabelBB gr' 1) it "loopNodes" $ do- let (pf, gr) = testPfAndGraph F77 "f" programRd3 let domMap = dominators gr- let bedges = genBackEdgeMap domMap gr- S.fromList (loopNodes bedges gr) `shouldBe`+ bedges = genBackEdgeMap domMap $ bbgrGr gr+ S.fromList (loopNodes bedges $ bbgrGr gr) `shouldBe` S.fromList [findLabelsBB gr [1,2,3,4]] - it "reachingDefinitions" $ do- let (pf, gr) = testPfAndGraph F77 "f" programRd3- let bm = genBlockMap pf- let dm = genDefMap bm+ it "reachingDefinitions" $ IM.lookup (findLabelBB gr 5) (reachingDefinitions dm gr) `shouldBe` Just (IS.unions [findBBlockBl gr 0, findLabelsBl pf [1,2,3]] ,IS.unions [findBBlockBl gr 0, findLabelsBl pf [1,2,3,5]]) - it "flowsTo" $ do- let (pf, gr) = testPfAndGraph F77 "f" programRd3- let bm = genBlockMap pf- let dm = genDefMap bm+ it "flowsTo" $ (S.fromList . edges . genFlowsToGraph bm dm gr $ reachingDefinitions dm gr) `shouldSatisfy` -- Find the flows of the assignment statements in the program. S.isSubsetOf (findLabelsBlEdges pf [(1,2),(1,3) -- do 4 i = 2, 10@@ -170,55 +163,52 @@ ,(3,2),(3,5) -- a(i) = b(i) ]) - describe "rd4" $ do+ describe "rd4" $ it "ivMapByASTBlock" $ do- let (pf, gr) = testPfAndGraph F77 "f" programRd4- let domMap = dominators gr- let bedges = genBackEdgeMap domMap gr- let ivMap = genInductionVarMapByASTBlock bedges gr- (sort . map (\ x -> (head x, length x)) . group . sort . map S.size $ IM.elems ivMap) `shouldBe` [(1,3),(2,3)]+ let (_, gr) = testPfAndGraph F77 "f" programRd4+ domMap = dominators gr+ bedges = genBackEdgeMap domMap $ bbgrGr gr+ ivMap = genInductionVarMapByASTBlock bedges gr+ (sort . map (head &&& length) . group . sort . map S.size $ IM.elems ivMap) `shouldBe` [(1,3),(2,3)] describe "bug36" $ do let pf = pParser F90 programBug36- let sgr = genSuperBBGr (genBBlockMap pf)- let gr = superBBGrGraph sgr- let domMap = dominators gr- let bedges = genBackEdgeMap domMap gr- it "loopNodes" $ do- length (loopNodes bedges gr) `shouldBe` 2+ sgr = genSuperBBGr (genBBlockMap pf)+ gr = superBBGrGraph sgr+ domMap = dominators gr+ bedges = genBackEdgeMap domMap $ bbgrGr gr+ it "loopNodes" $+ length (loopNodes bedges $ bbgrGr gr) `shouldBe` 2 describe "funcflow1" $ do let pf = pParser F90 programFuncFlow1- let sgr = genSuperBBGr (genBBlockMap pf)- let gr = superBBGrGraph sgr- let bm = genBlockMap pf- let dm = genDefMap bm- let rDefs = reachingDefinitions dm gr- let flTo = genFlowsToGraph bm dm gr rDefs- let domMap = dominators gr- let bedges = genBackEdgeMap domMap gr- let diMap = genDerivedInductionMap bedges gr- it "flowsTo" $ do+ sgr = genSuperBBGr (genBBlockMap pf)+ gr = superBBGrGraph sgr+ bm = genBlockMap pf+ dm = genDefMap bm+ rDefs = reachingDefinitions dm gr+ flTo = genFlowsToGraph bm dm gr rDefs+ it "flowsTo" $ (S.fromList . edges . trc $ flTo) `shouldSatisfy` -- Find the flows of the assignment statements in the program. S.isSubsetOf (findLabelsBlEdges pf [(1,2),(1,3),(3,2)]) describe "funcflow2" $ do let pf = pParser F90 programFuncFlow2- let sgr = genSuperBBGr (genBBlockMap pf)- let gr = superBBGrGraph sgr- let bm = genBlockMap pf- let dm = genDefMap bm- let rDefs = reachingDefinitions dm gr- let flTo = genFlowsToGraph bm dm gr rDefs- let domMap = dominators gr- let bedges = genBackEdgeMap domMap gr- let diMap = genDerivedInductionMap bedges gr- let (iLabel, iName):_ = [ (fromJust (insLabel a), varName e)+ sgr = genSuperBBGr (genBBlockMap pf)+ gr = superBBGrGraph sgr+ bm = genBlockMap pf+ dm = genDefMap bm+ rDefs = reachingDefinitions dm gr+ flTo = genFlowsToGraph bm dm gr rDefs+ domMap = dominators gr+ bedges = genBackEdgeMap domMap $ bbgrGr gr+ diMap = genDerivedInductionMap bedges gr+ (iLabel, iName):_ = [ (fromJust (insLabel a), varName e) | e@(ExpValue a _ (ValVariable _)) <- rhsExprs pf, srcName e == "i" ]- let (jLabel, jName):_ = [ (fromJust (insLabel a), varName e)+ (jLabel, _):_ = [ (fromJust (insLabel a), varName e) | e@(ExpValue a _ (ValVariable _)) <- lhsExprs pf, srcName e == "j" ]- it "flowsTo" $ do+ it "flowsTo" $ (S.fromList . edges . trc $ flTo) `shouldSatisfy` -- Find the flows of the assignment statements in the program. S.isSubsetOf (findLabelsBlEdges pf [(1,2),(1,3),(3,2)])@@ -226,10 +216,44 @@ IM.lookup iLabel diMap `shouldBe` Just (IELinear iName 1 0) IM.lookup jLabel diMap `shouldBe` Just (IELinear iName 6 2) - describe "other" $ do- it "dominators on disconnected graph" $ do- dominators (nmap (const []) (mkUGraph [0,1,3,4,5,6,7,8,9] [(0,3) ,(3,1) ,(5,6) ,(6,7) ,(7,4) ,(7,8) ,(8,7) ,(8,9) ,(9,8)] :: Gr () ())) `shouldBe` IM.fromList [(0,IS.fromList [0]),(1,IS.fromList [0,1,3]),(3,IS.fromList [0,3]),(4,IS.fromList [4,5,6,7]),(5,IS.fromList [5]),(6,IS.fromList [5,6]),(7,IS.fromList [5,6,7]),(8,IS.fromList [5,6,7,8]),(9,IS.fromList [5,6,7,8,9])]+ describe "defUse1" $ do+ let pf = pParser F90 programDefUse1+ sgr = genSuperBBGr (genBBlockMap pf)+ gr = superBBGrGraph sgr+ bm = genBlockMap pf+ dm = genDefMap bm+ rDefs = reachingDefinitions dm gr+ flTo = genFlowsToGraph bm dm gr rDefs+ domMap = dominators gr+ bedges = genBackEdgeMap domMap $ bbgrGr gr+ it "backEdges" $+ bedges `shouldBe` IM.fromList [(findLabelBB gr 5, findLabelBB gr 4)]+ it "flowsTo" $+ (S.fromList . edges $ flTo) `shouldBe`+ -- Find the flows of the assignment statements in the program.+ findLabelsBlEdges pf [(1,2),(1,3),(1,5),(2,3),(3,4),(4,5),(5,5)] + describe "defUse2" $ do+ let pf = pParser F90 programDefUse2+ sgr = genSuperBBGr (genBBlockMap pf)+ gr = superBBGrGraph sgr+ bm = genBlockMap pf+ dm = genDefMap bm+ rDefs = reachingDefinitions dm gr+ flTo = genFlowsToGraph bm dm gr rDefs+ domMap = dominators gr+ bedges = genBackEdgeMap domMap $ bbgrGr gr+ it "backEdges" $+ bedges `shouldBe` IM.fromList [(findLabelBB gr 12, findLabelBB gr 11)]+ it "flowsTo" $ do+ (S.fromList . edges . tc $ flTo) `shouldSatisfy`+ -- Find the flows of the assignment statements in the program.+ S.isSubsetOf (findLabelsBlEdges pf [(1,2),(1,3),(1,12),(2,3),(3,11),(11,12),(12,12)])++ describe "other" $+ it "dominators on disconnected graph" $+ dominators (BBGr (nmap (const []) (mkUGraph [0,1,3,4,5,6,7,8,9] [(0,3) ,(3,1) ,(5,6) ,(6,7) ,(7,4) ,(7,8) ,(8,7) ,(8,9) ,(9,8)])) [0,5] [3,9]) `shouldBe` IM.fromList [(0,IS.fromList [0]),(1,IS.fromList [0,1,3]),(3,IS.fromList [0,3]),(4,IS.fromList [4,5,6,7]),(5,IS.fromList [5]),(6,IS.fromList [5,6]),(7,IS.fromList [5,6,7]),(8,IS.fromList [5,6,7,8]),(9,IS.fromList [5,6,7,8,9])]+ -------------------------------------------------- -- Label-finding helper functions to help write tests that are -- insensitive to minor changes to the AST.@@ -245,7 +269,7 @@ -- For each Fortran label in the list, find the successors of the -- corresponding basic block, return as an IntSet. findSuccsBB :: BBGr a -> [Int] -> IS.IntSet-findSuccsBB gr = IS.fromList . concatMap (suc gr) . mapMaybe (flip findLabeledBBlock gr . show)+findSuccsBB gr = IS.fromList . concatMap (suc $ bbgrGr gr) . mapMaybe (flip findLabeledBBlock gr . show) -- For each Fortran label in the list, find the AST-block label numbers ('insLabel') associated findLabelsBl :: forall a. Data a => ProgramFile (Analysis a) -> [Int] -> IS.IntSet@@ -268,11 +292,12 @@ -- Get the set of AST-block labels found in a given basic block findBBlockBl :: BBGr (Analysis a) -> Int -> IS.IntSet-findBBlockBl gr = IS.fromList . mapMaybe (insLabel . getAnnotation) . concat . maybeToList . lab gr+findBBlockBl gr = IS.fromList . mapMaybe (insLabel . getAnnotation) . concat . maybeToList . lab (bbgrGr gr) -------------------------------------------------- -- Test programs +programLoop4 :: String programLoop4 = unlines [ " program loop4" , " 1 integer r, i, j"@@ -295,6 +320,7 @@ , " end" ] +programLoop4Alt :: String programLoop4Alt = unlines [ " module loopMod" , " implicit none"@@ -325,6 +351,7 @@ , " end module" ] +programRd3 :: String programRd3 = unlines [ " function f(x)" , " integer i, a, b, x, f"@@ -333,7 +360,7 @@ , " 1 do 4 i = 2, 10" , " 2 b(i) = a(i-1) + x" , " 3 a(i) = b(i)"- , " 4 continue"+ , " 4 i=i" -- alt. to 'continue' since the latter gets eliminated now , " 5 f = a(10)" , " end" , " program rd3"@@ -345,6 +372,7 @@ , "" ] +programRd4 :: String programRd4 = unlines [ " function f(x)" , " integer i, j, a, b, x, f"@@ -353,9 +381,9 @@ , " do 10 i = 2, 10" , " do 20 j = 2, 10" , " b(i) = a(i-1) + x"- , " 20 continue"+ , " 20 j=j" -- alt. to 'continue' since the latter gets eliminated now , " a(i) = b(i)"- , " 10 continue"+ , " 10 i=i" -- alt. to 'continue' since the latter gets eliminated now , " f = a(10)" , " end" , " program rd3"@@ -368,6 +396,7 @@ ] -- do not use line numbers+programBug36 :: String programBug36 = unlines [ "program foo" , " implicit none"@@ -381,6 +410,7 @@ , "end program" ] +programFuncFlow1 :: String programFuncFlow1 = unlines [ " program main" , " integer :: i, j"@@ -394,6 +424,7 @@ , " end program main" ] +programFuncFlow2 :: String programFuncFlow2 = unlines [ " program main" , " integer :: i, j"@@ -406,6 +437,35 @@ , " 3 f = k + 1" , " end function f" , " end program main"+ ]++programDefUse1 :: String+programDefUse1 = unlines [+ "program defUse1"+ , "1 integer :: x = 1"+ , "2 integer :: y = x + 1"+ , "3 integer :: z = x * y"+ , "4 do y=1,z"+ , "5 x = x + y"+ , "6 end do"+ , "end program defUse1"+ ]++programDefUse2 :: String+programDefUse2 = unlines [+ "program defUse2"+ , "1 integer :: x = 1"+ , "2 integer :: y = x + 1"+ , "3 integer :: z = x * y"+ , "4 call s(x)"+ , "contains"+ , " subroutine s(a)"+ , "10 integer :: a"+ , "11 do y=1,z"+ , "12 a = a + y"+ , "13 end do"+ , "end subroutine s"+ , "end program defUse2" ] -- Local variables:
test/Language/Fortran/Analysis/RenamingSpec.hs view
@@ -3,32 +3,33 @@ import Test.Hspec import TestUtil -import Data.Map ((!), elems)+import Data.Map (elems)+--import Data.Data (Data) import qualified Data.Map as M-import Data.List import Language.Fortran.ParserMonad import Language.Fortran.AST-import Language.Fortran.Util.Position import qualified Language.Fortran.Parser.Fortran90 as F90 import Language.Fortran.Analysis-import Language.Fortran.Analysis.Renaming hiding (extractNameMap, underRenaming)+import Language.Fortran.Analysis.Renaming import Data.Generics.Uniplate.Data-import Data.Generics.Uniplate.Operations-import Data.Data import qualified Data.ByteString.Char8 as B -import Debug.Trace--testF90 pf = (resetSrcSpan . analyseRenames . initAnalysis) $ pf+--testF90 :: Data a => ProgramFile a -> ProgramFile (Analysis a)+--testF90 pf = (resetSrcSpan . analyseRenames . initAnalysis) $ pf+extractNameMap' :: ProgramFile () -> M.Map String String extractNameMap' = extractNameMap . analyseRenames . initAnalysis+unrename' :: ProgramFile () -> ProgramFile () unrename' = stripAnalysis . unrename . rename . analyseRenames . initAnalysis-renameAndStrip' x = stripAnalysis . rename . analyseRenames . initAnalysis $ x+--renameAndStrip' :: Data a => ProgramFile a -> ProgramFile a+--renameAndStrip' x = stripAnalysis . rename . analyseRenames . initAnalysis $ x -countUnrenamed e = length [ () | ExpValue (Analysis { uniqueName = Nothing }) _ (ValVariable {}) <- uniE_PF e ]+countUnrenamed :: ProgramFile (Analysis ()) -> Int+countUnrenamed e = length [ () | ExpValue Analysis { uniqueName = Nothing } _ ValVariable {} <- uniE_PF e ] where uniE_PF :: ProgramFile (Analysis ()) -> [Expression (Analysis ())] uniE_PF = universeBi +fortran90Parser :: String -> String -> ProgramFile A0 fortran90Parser src file = fromParseResultUnsafe $ F90.fortran90Parser (B.pack src) file spec :: Spec@@ -43,32 +44,34 @@ ( 1, 2, 2, 2 ) -- Test that every symbol that is supposed to be renamed is renamed.- it "complete ex1" $ do+ it "complete ex1" $ countUnrenamed (analyseRenames . initAnalysis $ ex1) `shouldBe` 0- it "complete ex2" $ do+ it "complete ex2" $ countUnrenamed (analyseRenames . initAnalysis $ ex2) `shouldBe` 0- it "complete ex3" $ do+ it "complete ex3" $ countUnrenamed (analyseRenames . initAnalysis $ ex3) `shouldBe` 0- it "complete ex4" $ do+ it "complete ex4" $ countUnrenamed (analyseRenames . initAnalysis $ ex4) `shouldBe` 0- it "complete ex5" $ do+ it "complete ex5" $ countUnrenamed (analyseRenames . initAnalysis $ ex5) `shouldBe` 0- it "complete ex6" $ do+ it "complete ex6" $ countUnrenamed (analyseRenames . initAnalysis $ ex6) `shouldBe` 0- it "complete ex8" $ do+ it "complete ex8" $ countUnrenamed (analyseRenames . initAnalysis $ ex8) `shouldBe` 0- it "complete ex9" $ do+ it "complete ex9" $ countUnrenamed (analyseRenames . initAnalysis $ ex9) `shouldBe` 0- it "complete ex10" $ do+ it "complete ex10" $ countUnrenamed (analyseRenames . initAnalysis $ ex10) `shouldBe` 0- it "complete ex11" $ do+ it "complete ex11" $ countUnrenamed (analyseRenames . initAnalysis $ ex11) `shouldBe` 0- it "complete ex12" $ do+ it "complete ex12" $ countUnrenamed (analyseRenames . initAnalysis $ ex12) `shouldBe` 0+ it "complete ex13" $+ countUnrenamed (analyseRenames . initAnalysis $ ex13Renames) `shouldBe` 0 - it "complete exScope1" $ do+ it "complete exScope1" $ countUnrenamed (analyseRenames . initAnalysis $ exScope1) `shouldBe` 0- it "complete exScope2" $ do+ it "complete exScope2" $ countUnrenamed (analyseRenames . initAnalysis $ exScope2) `shouldBe` 0 it "functions 1" $ do@@ -102,7 +105,7 @@ let entry = extractNameMap' exScope2 length (filter (=="x") (elems entry)) `shouldBe` 2 - describe "Ordering" $ do+ describe "Ordering" $ it "exScope3 testing out-of-order definitions" $ do let entry = extractNameMap' exScope3 length (filter (=="f1") (elems entry)) `shouldBe` 1@@ -110,13 +113,25 @@ length (filter (=="s1") (elems entry)) `shouldBe` 1 length (filter (=="s2") (elems entry)) `shouldBe` 1 + describe "Common blocks" $+ it "common1" $ do+ let entry = extractNameMap' common1+ length (filter (=="x") (elems entry)) `shouldBe` 2+ M.lookup "c_x_common" entry `shouldBe` Just "x"+ M.lookup "c_y_common" entry `shouldBe` Just "y"+ -------------------------------------------------- +ex1 :: ProgramFile () ex1 = ProgramFile mi77 [ ex1pu1 ]-ex1pu1 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) (None () u False) "f1" Nothing Nothing [] Nothing+ex1pu1 :: ProgramUnit ()+ex1pu1 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) emptyPrefixSuffix "f1" Nothing Nothing [] Nothing +ex2 :: ProgramFile () ex2 = ProgramFile mi77 [ ex2pu1 ]+ex2pu1 :: ProgramUnit () ex2pu1 = PUMain () u (Just "main") ex2pu1bs Nothing+ex2pu1bs :: [Block ()] ex2pu1bs = [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ DeclVariable () u (varGen "a") Nothing Nothing@@ -134,8 +149,11 @@ , BlStatement () u Nothing (StExpressionAssign () u (ExpSubscript () u (varGen "d") (AList () u [ ixSinGen 1 ])) (intGen 1)) ] +ex3 :: ProgramFile () ex3 = ProgramFile mi77 [ ex3pu1, ex3pu2 ]+ex3pu1 :: ProgramUnit () ex3pu1 = PUMain () u (Just "main") ex3pu1bs Nothing+ex3pu1bs :: [Block ()] ex3pu1bs = [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ DeclVariable () u (varGen "a") Nothing Nothing@@ -154,10 +172,14 @@ (ExpSubscript () u (varGen "c") (AList () u [ ixSinGen 1 ])) (intGen 1)) , BlStatement () u Nothing (StExpressionAssign () u (varGen "d") (ExpBinary () u Addition (varGen "d") (intGen 1))) ]-ex3pu2 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) (None () u False) "f1" (Just $ AList () u [ varGen "d", varGen "b"]) Nothing (ex3pu1bs ++ [ BlStatement () u Nothing (StExpressionAssign () u (varGen "f1") (varGen "d")) ]) Nothing+ex3pu2 :: ProgramUnit ()+ex3pu2 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) emptyPrefixSuffix "f1" (Just $ AList () u [ varGen "d", varGen "b"]) Nothing (ex3pu1bs ++ [ BlStatement () u Nothing (StExpressionAssign () u (varGen "f1") (varGen "d")) ]) Nothing +ex4 :: ProgramFile () ex4 = ProgramFile mi77 [ ex4pu1, ex4pu2 ]+ex4pu1 :: ProgramUnit () ex4pu1 = PUMain () u (Just "main") ex4pu1bs Nothing+ex4pu1bs :: [Block ()] ex4pu1bs = [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ DeclVariable () u (varGen "f1") Nothing Nothing@@ -166,25 +188,39 @@ (ExpValue () u (ValVariable "r")) (ExpFunctionCall () u (ExpValue () u (ValVariable "f1")) (Just $ AList () u [ Argument () u Nothing $ intGen 1 ]))) ]-ex4pu2 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) (None () u False) "f1" (Just $ AList () u [ varGen "x"]) Nothing [ BlStatement () u Nothing (StExpressionAssign () u (varGen "f1") (varGen "x")) ] Nothing+ex4pu2 :: ProgramUnit ()+ex4pu2 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) emptyPrefixSuffix "f1" (Just $ AList () u [ varGen "x"]) Nothing [ BlStatement () u Nothing (StExpressionAssign () u (varGen "f1") (varGen "x")) ] Nothing +ex5 :: ProgramFile () ex5 = ProgramFile mi77 [ ex5pu1, ex5pu2 ]+ex5pu1 :: ProgramUnit () ex5pu1 = PUMain () u (Just "main") ex5pu1bs Nothing+ex5pu1bs :: [a] ex5pu1bs = []+ex5pu2 :: ProgramUnit () ex5pu2 = PUModule () u "ex5mod" ex5pu2bs (Just [ex5pu2pu1])+ex5pu2bs :: [a] ex5pu2bs = []-ex5pu2pu1 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) (None () u False) "f1" (Just $ AList () u [ varGen "x"]) Nothing [ BlStatement () u Nothing (StExpressionAssign () u (varGen "f1") (varGen "x")) ] Nothing-+ex5pu2pu1 :: ProgramUnit ()+ex5pu2pu1 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) emptyPrefixSuffix "f1" (Just $ AList () u [ varGen "x"]) Nothing [ BlStatement () u Nothing (StExpressionAssign () u (varGen "f1") (varGen "x")) ] Nothing +ex6 :: ProgramFile () ex6 = ProgramFile mi77 [ ex6pu1, ex6pu2 ]+ex6pu1 :: ProgramUnit () ex6pu1 = PUMain () u (Just "main") ex6pu1bs Nothing+ex6pu1bs :: [a] ex6pu1bs = []+ex6pu2 :: ProgramUnit () ex6pu2 = PUModule () u "ex6mod" ex6pu2bs (Just [ex6pu2pu1])+ex6pu2bs :: [a] ex6pu2bs = []-ex6pu2pu1 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) (None () u False) "f1" (Just $ AList () u [ varGen "x"]) Nothing [ BlStatement () u Nothing (StExpressionAssign () u (varGen "f1") (ExpFunctionCall () u (ExpValue () u (ValVariable "f1")) (Just $ AList () u [Argument () u Nothing (varGen "x")]))) ] (Just [ex5pu2pu1])+ex6pu2pu1 :: ProgramUnit ()+ex6pu2pu1 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) emptyPrefixSuffix "f1" (Just $ AList () u [ varGen "x"]) Nothing [ BlStatement () u Nothing (StExpressionAssign () u (varGen "f1") (ExpFunctionCall () u (ExpValue () u (ValVariable "f1")) (Just $ AList () u [Argument () u Nothing (varGen "x")]))) ] (Just [ex5pu2pu1]) -parseF90 = resetSrcSpan . flip fortran90Parser "" . unlines+--parseF90 :: [String] -> ProgramFile A0+--parseF90 = resetSrcSpan . flip fortran90Parser "" . unlines +ex8 :: ProgramFile A0 ex8 = resetSrcSpan . flip fortran90Parser "" $ unlines [ "module m1" , " implicit none"@@ -219,6 +255,7 @@ , "end program main" ] +ex9 :: ProgramFile A0 ex9 = resetSrcSpan . flip fortran90Parser "" $ unlines [ "module m1" , " implicit none"@@ -234,20 +271,27 @@ , "end module m1" ] +ex10 :: ProgramFile () ex10 = ProgramFile mi77 [ ex10pu1 ]-ex10pu1 = PUSubroutine () u (None () u False) "s1" Nothing ex10pu1bs Nothing+ex10pu1 :: ProgramUnit ()+ex10pu1 = PUSubroutine () u emptyPrefixSuffix "s1" Nothing ex10pu1bs Nothing+ex10pu1bs :: [Block ()] ex10pu1bs = [ BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e1")) Nothing Nothing) , BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e2")) Nothing Nothing) , BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e3")) Nothing Nothing) ] +ex11 :: ProgramFile () ex11 = ProgramFile mi77 [ ex11pu1 ]-ex11pu1 = PUFunction () u (Just (TypeSpec () u TypeInteger Nothing)) (None () u False) "f1" Nothing (Just (varGen "r1")) ex11pu1bs Nothing+ex11pu1 :: ProgramUnit ()+ex11pu1 = PUFunction () u (Just (TypeSpec () u TypeInteger Nothing)) emptyPrefixSuffix "f1" Nothing (Just (varGen "r1")) ex11pu1bs Nothing+ex11pu1bs :: [Block ()] ex11pu1bs = [ BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e1")) Nothing Nothing) , BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e2")) Nothing Nothing) , BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e3")) Nothing (Just (varGen "r2"))) ] +ex12 :: ProgramFile A0 ex12 = resetSrcSpan . flip fortran90Parser "" $ unlines [ "module m1" , " implicit none"@@ -284,7 +328,45 @@ , "end program main" ] +ex13Renames :: ProgramFile A0+ex13Renames = resetSrcSpan . flip fortran90Parser "" $ unlines [+ "module m1"+ , " implicit none"+ , " integer :: z"+ , "contains"+ , " integer function foo ()"+ , " foo = 0"+ , " end function foo"+ , "end module m1"+ , ""+ , "module m2"+ , " implicit none"+ , "contains"+ , " integer function foo2 (x)"+ , " use m1, only: frob => foo"+ , " integer :: x"+ , " foo2 = frob () + x"+ , " end function foo2"+ , "end module m2"+ , ""+ , "module m3"+ , " implicit none"+ , "contains"+ , " integer function foo () result (r)"+ , " r = 1"+ , " end function foo"+ , "end module m3"+ , ""+ , "program main"+ , " use m1, only: z, baz => foo"+ , " use m3, only: bar => foo"+ , " integer :: x"+ , " x = bar () + baz () + z"+ , "end program main"+ ] ++exScope1 :: ProgramFile A0 exScope1 = resetSrcSpan . flip fortran90Parser "" $ unlines [ "program scope1" -- local variables cannot take on the name of subprogram, therefore@@ -300,6 +382,7 @@ , "" ] +exScope2 :: ProgramFile A0 exScope2 = resetSrcSpan . flip fortran90Parser "" $ unlines [ "module scope2" , " integer :: x"@@ -329,6 +412,7 @@ , "end program main" ] +exScope3 :: ProgramFile A0 exScope3 = resetSrcSpan . flip fortran90Parser "" $ unlines [ "module m1" , " implicit none"@@ -363,6 +447,23 @@ , " integer :: x, f2" , " f2 = x + 1" , "end function f2"+ ]++common1 :: ProgramFile A0+common1 = resetSrcSpan . flip fortran90Parser "" $ unlines [+ "program p1"+ , " implicit none"+ , " integer :: x, y"+ , " common /c/ x, y(10)"+ , "contains"+ , " subroutine s1 ()"+ , " call s2 (f1(x))"+ , " end subroutine s1"+ , " integer function f1(x)"+ , " integer :: x, f2"+ , " f1 = f2(x)"+ , " end function f1"+ , "end program p1" ] -- Local variables:
test/Language/Fortran/Analysis/TypesSpec.hs view
@@ -6,21 +6,27 @@ import Data.Map ((!)) import Data.Data+import Data.Generics.Uniplate.Data import Language.Fortran.AST import Language.Fortran.Analysis.Types-import Language.Fortran.Analysis.Renaming hiding (extractNameMap, underRenaming)+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 -import Debug.Trace- inferTable :: Data a => ProgramFile a -> TypeEnv inferTable = underRenaming (snd . analyseTypes) +typedProgramFile :: Data a => ProgramFile a -> ProgramFile (Analysis a)+typedProgramFile = fst . analyseTypes . analyseRenames . initAnalysis++fortran90Parser :: String -> String -> ProgramFile A0 fortran90Parser src file = fromParseResultUnsafe $ F90.fortran90Parser (B.pack src) file +uniExpr :: ProgramFile (Analysis A0) -> [Expression (Analysis A0)]+uniExpr = universeBi+ spec :: Spec spec = do describe "Global type inference" $ do@@ -42,58 +48,141 @@ describe "Local type inference" $ do 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)- mapping ! "c" `shouldBe` IDType (Just TypeCharacter) (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)+ [ () | ExpValue a _ (ValVariable "x") <- uniExpr pf+ , idType a == Just (IDType (Just TypeInteger) (Just CTVariable)) ]+ `shouldNotSatisfy` null+ [ () | ExpValue a _ (ValVariable "y") <- uniExpr pf+ , idType a == Just (IDType (Just TypeInteger) (Just $ CTArray [(Nothing, Just 10)])) ]+ `shouldNotSatisfy` null it "infers from dimension declarations" $ do let mapping = inferTable ex5- mapping ! "x" `shouldBe` IDType Nothing (Just CTArray)- mapping ! "y" `shouldBe` IDType Nothing (Just CTArray)+ mapping ! "x" `shouldBe` IDType Nothing (Just $ CTArray [(Nothing, Just 1)])+ mapping ! "y" `shouldBe` IDType Nothing (Just $ CTArray [(Nothing, Just 1)]) it "infers from function statements" $ do let mapping = inferTable ex6- mapping ! "a" `shouldBe` IDType (Just TypeInteger) (Just CTArray)- mapping ! "b" `shouldBe` IDType (Just TypeInteger) (Just CTArray)+ 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 ! "d" `shouldBe` IDType Nothing (Just CTFunction) describe "Intrinsics type analysis" $ do it "disambiguates intrinsics from functions and variables" $ do let mapping = inferTable intrinsics1- idCType (mapping ! "abs") `shouldBe` Just CTIntrinsic+ let pf = typedProgramFile intrinsics1+ [ () | ExpValue a _ (ValVariable "x") <- uniExpr pf+ , idType a == Just (IDType (Just TypeReal) (Just CTVariable)) ]+ `shouldSatisfy` ((== 5) . length)++ -- the following are true because dabs and cabs are defined as function and array in this program. idCType (mapping ! "dabs") `shouldBe` Just CTFunction- idCType (mapping ! "cabs") `shouldBe` Just CTArray+ [ a | ExpValue a _ (ValIntrinsic "dabs") <- uniExpr pf+ ] -- , idType a == Just (IDType (Just TypeReal) (Just CTVariable)) ]+ `shouldSatisfy` null + idCType (mapping ! "cabs") `shouldBe` Just (CTArray [(Nothing, Just 3)])+ [ a | ExpValue a _ (ValIntrinsic "cabs") <- uniExpr pf+ ] -- , idType a == Just (IDType (Just TypeReal) (Just CTVariable)) ]+ `shouldSatisfy` null++ -- 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) ]+ `shouldNotSatisfy` null++ it "intrinsics and numeric types" $ do+ let mapping = inferTable intrinsics2+ let pf = typedProgramFile intrinsics2+ idCType (mapping ! "abs") `shouldBe` Just CTIntrinsic+ idCType (mapping ! "cabs") `shouldBe` Just CTIntrinsic+ idCType (mapping ! "dabs") `shouldBe` Just CTIntrinsic+ [ ty | ExpFunctionCall a _ (ExpValue _ _ (ValIntrinsic "abs")) _ <- uniExpr pf+ , Just (IDType (Just ty) Nothing) <- [idType a] ]+ `shouldBe` [TypeDoublePrecision, TypeComplex]+ [ a | ExpFunctionCall a _ (ExpValue _ _ (ValIntrinsic "cabs")) _ <- uniExpr pf+ , idType a == Just (IDType (Just TypeComplex) Nothing) ]+ `shouldNotSatisfy` null+ [ a | ExpFunctionCall a _ (ExpValue _ _ (ValIntrinsic "dabs")) _ <- uniExpr pf+ , idType a == Just (IDType (Just 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) ]+ `shouldNotSatisfy` null+ [ a | ExpBinary a _ Addition (ExpValue _ _ (ValInteger "1")) _ <- uniExpr pf+ , idType a == Just (IDType (Just TypeComplex) Nothing) ]+ `shouldNotSatisfy` null+ [ a | ExpBinary a _ Addition (ExpValue _ _ (ValInteger "2")) _ <- uniExpr pf+ , idType a == Just (IDType (Just TypeDoublePrecision) 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)+ idCType (mapping ! "d") `shouldBe` Just (CTArray [(Nothing, Just 10)])+ idVType (mapping ! "e") `shouldBe` Just (TypeCharacter (Just (CharLenInt 10)) Nothing)+ idCType (mapping ! "e") `shouldBe` Just (CTArray [(Nothing, Just 20)])+ 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)]))) ]+ `shouldNotSatisfy` null++ex1 :: ProgramFile () ex1 = ProgramFile mi77 [ ex1pu1 ]-ex1pu1 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) (None () u False) "f1" Nothing Nothing [] Nothing+ex1pu1 :: ProgramUnit ()+ex1pu1 = PUFunction () u (Just $ TypeSpec () u TypeInteger Nothing) emptyPrefixSuffix "f1" Nothing Nothing [] Nothing +ex2 :: ProgramFile () ex2 = ProgramFile mi77 [ ex2pu1, ex1pu1 ]-ex2pu1 = PUSubroutine () u (None () u False) "s1" Nothing [] Nothing+ex2pu1 :: ProgramUnit ()+ex2pu1 = PUSubroutine () u emptyPrefixSuffix "s1" Nothing [] Nothing +ex3 :: ProgramFile () ex3 = ProgramFile mi77 [ ex3pu1 ]-ex3pu1 = PUSubroutine () u (None () u False) "s1" Nothing ex3pu1bs Nothing+ex3pu1 :: ProgramUnit ()+ex3pu1 = PUSubroutine () u emptyPrefixSuffix "s1" Nothing ex3pu1bs Nothing+ex3pu1bs :: [Block ()] ex3pu1bs = [ BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e1")) Nothing Nothing) , BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e2")) Nothing Nothing) , BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e3")) Nothing Nothing) ] +ex4 :: ProgramFile () ex4 = ProgramFile mi77 [ ex4pu1 ]+ex4pu1 :: ProgramUnit () ex4pu1 = PUMain () u Nothing ex4pu1bs Nothing+ex4pu1bs :: [Block ()] ex4pu1bs = [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ 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+ , BlStatement () u Nothing (StDeclaration () u (TypeSpec () u (TypeCharacter Nothing Nothing) 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 ])) ] +ex5 :: ProgramFile () ex5 = ProgramFile mi77 [ ex5pu1 ]+ex5pu1 :: ProgramUnit () ex5pu1 = PUBlockData () u (Just "bd") ex5pu1bs+ex5pu1bs :: [Block ()] ex5pu1bs = [ BlStatement () u Nothing (StDimension () u (AList () u [ DeclArray () u (varGen "x") (AList () u [ DimensionDeclarator () u Nothing (Just $ intGen 1) ]) Nothing Nothing@@ -109,8 +198,11 @@ - d(x) = 1 - end -}+ex6 :: ProgramFile () ex6 = ProgramFile mi77 [ ex6pu1 ]+ex6pu1 :: ProgramUnit () ex6pu1 = PUMain () u (Just "main") ex6pu1bs Nothing+ex6pu1bs :: [Block ()] ex6pu1bs = [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ DeclVariable () u (varGen "a") Nothing Nothing@@ -127,14 +219,17 @@ , BlStatement () u Nothing (StExpressionAssign () u (ExpSubscript () u (varGen "d") (fromList () [ ixSinGen 1 ])) (intGen 1)) ] +ex11 :: ProgramFile () ex11 = ProgramFile mi77 [ ex11pu1 ]-ex11pu1 = PUFunction () u (Just (TypeSpec () u TypeInteger Nothing)) (None () u False) "f1" Nothing (Just (varGen "r1")) ex11pu1bs Nothing+ex11pu1 :: ProgramUnit ()+ex11pu1 = PUFunction () u (Just (TypeSpec () u TypeInteger Nothing)) emptyPrefixSuffix "f1" Nothing (Just (varGen "r1")) ex11pu1bs Nothing+ex11pu1bs :: [Block ()] ex11pu1bs = [ BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e1")) Nothing Nothing) , BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e2")) Nothing Nothing) , BlStatement () u Nothing (StEntry () u (ExpValue () u (ValVariable "e3")) Nothing (Just (varGen "r2"))) ] -+intrinsics1 :: ProgramFile A0 intrinsics1 = resetSrcSpan . flip fortran90Parser "" $ unlines [ "module intrinsics" , "contains"@@ -152,6 +247,56 @@ , " dabs = a" , " end function dabs" , "end module intrinsics"+ ]++intrinsics2 :: ProgramFile A0+intrinsics2 = resetSrcSpan . flip fortran90Parser "" $ unlines [+ "module intrinsics"+ , "contains"+ , " subroutine main()"+ , " double precision :: u"+ , " complex :: c"+ , " real :: x"+ , " integer :: y = 1"+ , " u = dabs(y + x)"+ , " c = cabs(y + x)"+ , " u = abs(y + x * u)"+ , " c = abs(y + x * c)"+ , " print *, x"+ , " end subroutine main"+ , "end module intrinsics"+ ]++numerics1 :: ProgramFile A0+numerics1 = resetSrcSpan . flip fortran90Parser "" $ unlines [+ "module numerics1"+ , "contains"+ , " subroutine main()"+ , " double precision :: u"+ , " complex :: c"+ , " real :: x"+ , " integer :: y = 1"+ , " print *, 1 + (-u * c + abs(y + x))"+ , " print *, 2 + f(y)"+ , " end subroutine main"+ , " double precision function f(a)"+ , " integer :: a"+ , " f = a"+ , " end function f"+ , "end module numerics1"+ ]+++teststrings1 :: ProgramFile A0+teststrings1 = resetSrcSpan . flip fortran90Parser "" $ unlines [+ "program teststrings"+ , " character(5,1) :: a"+ , " character :: b*10"+ , " character(kind=1,len=3) :: c"+ , " integer, parameter :: k = 8"+ , " character(k), dimension(10) :: d"+ , " character :: e(20)*10"+ , "end program teststrings" ] -- Local variables:
test/Language/Fortran/AnalysisSpec.hs view
@@ -4,14 +4,9 @@ import TestUtil import Language.Fortran.Parser.Fortran77-import Language.Fortran.Lexer.FixedForm (initParseState)-import Language.Fortran.ParserMonad (FortranVersion(..), evalParse, fromParseResultUnsafe)+import Language.Fortran.ParserMonad (fromParseResultUnsafe) import Language.Fortran.AST import Language.Fortran.Analysis-import Data.Graph.Inductive-import Data.Graph.Inductive.PatriciaTree (Gr)-import Data.List-import Data.Maybe import qualified Data.ByteString.Char8 as B pParser :: String -> ProgramFile (Analysis ())@@ -21,12 +16,13 @@ spec :: Spec spec =- describe "Analysis" $ do- describe "anal1" $ do+ describe "Analysis" $+ describe "anal1" $ it "lhsExprs" $ do let pf = stripAnalysis $ pParser programAnal1 lhsExprs pf `shouldMatchList'` programAnal1LhsExprs +programAnal1LhsExprs :: [Expression ()] programAnal1LhsExprs = [ ExpSubscript () u (ExpValue () u (ValVariable "a")) (AList () u [ ixSinGen 1 ]) , ExpSubscript () u (ExpValue () u (ValVariable "a"))@@ -38,6 +34,7 @@ , ExpSubscript () u (ExpValue () u (ValVariable "a")) (AList () u [ ixSinGen 6 ]) , ExpSubscript () u (ExpValue () u (ValVariable "a")) (AList () u [ ixSinGen 5 ]) ] +programAnal1 :: String programAnal1 = unlines $ map (replicate 6 ' '++) [ "program anal1" , "integer a, f"
test/Language/Fortran/Lexer/FixedFormSpec.hs view
@@ -7,9 +7,6 @@ import Test.Hspec.QuickCheck import TestUtil -import Control.Monad.State.Lazy-import Control.Exception- import Data.List (isPrefixOf) import qualified Data.ByteString.Char8 as B @@ -28,15 +25,16 @@ dropUntil2 [] = Nothing dropUntil2 [_] = Nothing dropUntil2 [a,_] = Just a- dropUntil2 (x:xs) = dropUntil2 xs+ dropUntil2 (_:xs) = dropUntil2 xs collectToLexSafe :: FortranVersion -> String -> Maybe Token collectToLexSafe version srcInput = dropUntil2 $ collectFixedTokensSafe version (B.pack srcInput) where dropUntil2 (Just [a,_]) = Just a- dropUntil2 (Just (x:xs)) = dropUntil2 $ Just xs+ dropUntil2 (Just (_:xs)) = dropUntil2 $ Just xs dropUntil2 _ = Nothing +collectFixedTokens' :: FortranVersion -> String -> [Token] collectFixedTokens' v = collectFixedTokens v . B.pack spec :: Spec@@ -150,7 +148,7 @@ `shouldBe` resetSrcSpan [TType u "integer", TId u "if", TEOF u] describe "Fortran 77 Legacy" $ do- it "lexes inline comments" $ do+ it "lexes inline comments" $ resetSrcSpan (collectFixedTokens' Fortran77Legacy " integer foo ! bar") `shouldBe` resetSrcSpan [TType u "integer", TId u "foo", TEOF u] @@ -159,27 +157,27 @@ , "C hello" , " + bar" ]- resetSrcSpan (collectFixedTokens' Fortran77Legacy src)- `shouldBe` resetSrcSpan [TType u "integer", TId u "foo", TComma u, TId u "bar", TNewline u, TEOF u]+ in resetSrcSpan (collectFixedTokens' Fortran77Legacy src)+ `shouldBe` resetSrcSpan [TType u "integer", TId u "foo", TComma u, TId u "bar", TNewline u, TEOF u] let src = unlines [ " integer foo, ! hello" , " + bar" ]- resetSrcSpan (collectFixedTokens' Fortran77Legacy src)- `shouldBe` resetSrcSpan [TType u "integer", TId u "foo", TComma u, TId u "bar", TNewline u, TEOF u]+ in resetSrcSpan (collectFixedTokens' Fortran77Legacy src)+ `shouldBe` resetSrcSpan [TType u "integer", TId u "foo", TComma u, TId u "bar", TNewline u, TEOF u] let src = unlines [ " integer foo," , "" , " + bar" ]- resetSrcSpan (collectFixedTokens' Fortran77Legacy src)- `shouldBe` resetSrcSpan [TType u "integer", TId u "foo", TComma u, TId u "bar", TNewline u, TEOF u]+ in resetSrcSpan (collectFixedTokens' Fortran77Legacy src)+ `shouldBe` resetSrcSpan [TType u "integer", TId u "foo", TComma u, TId u "bar", TNewline u, TEOF u] let src = unlines [ " integer foo," , " " -- the space is intentional , " + bar" ]- resetSrcSpan (collectFixedTokens' Fortran77Legacy src)- `shouldBe` resetSrcSpan [TType u "integer", TId u "foo", TComma u, TId u "bar", TNewline u, TEOF u]+ in resetSrcSpan (collectFixedTokens' Fortran77Legacy src)+ `shouldBe` resetSrcSpan [TType u "integer", TId u "foo", TComma u, TId u "bar", TNewline u, TEOF u] - it "lexes the older TYPE statement" $ do+ it "lexes the older TYPE statement" $ resetSrcSpan (collectFixedTokens' Fortran77Legacy " type *, 'hello'") `shouldBe` resetSrcSpan [TTypePrint u, TStar u, TComma u, TString u "hello", TEOF u] @@ -199,11 +197,11 @@ resetSrcSpan (collectFixedTokens' Fortran77Legacy " character s*(*)") `shouldBe` resetSrcSpan [TType u "character", TId u "s", TStar u, TLeftPar u, TStar u, TRightPar u, TEOF u] - it "lexes strings case-sensitively" $ do+ it "lexes strings case-sensitively" $ resetSrcSpan (collectFixedTokens' Fortran77Legacy " c = 'Hello'") `shouldBe` resetSrcSpan [TId u "c", TOpAssign u, TString u "Hello", TEOF u] - it "lexes strings delimited by '\"'" $ do+ it "lexes strings delimited by '\"'" $ resetSrcSpan (collectFixedTokens' Fortran77Legacy " c = \"hello\"") `shouldBe` resetSrcSpan [TId u "c", TOpAssign u, TString u "hello", TEOF u] @@ -214,25 +212,25 @@ resetSrcSpan (collectFixedTokens' Fortran77Legacy " x = 7hshort\n") `shouldBe` resetSrcSpan [TId u "x", TOpAssign u, THollerith u "short ", TNewline u, TEOF u] - it "lexes BOZ constants" $ do+ it "lexes BOZ constants" $ resetSrcSpan (collectFixedTokens' Fortran77Legacy " integer i, j, k / b'0101', o'0755', z'ab01' /") `shouldBe` resetSrcSpan [ TType u "integer", TId u "i", TComma u, TId u "j", TComma u, TId u"k" , TSlash u, TBozInt u "b'0101'", TComma u, TBozInt u "o'0755'", TComma u, TBozInt u "z'ab01'", TSlash u , TEOF u ] - it "lexes non-standard identifiers" $ do+ it "lexes non-standard identifiers" $ resetSrcSpan (collectFixedTokens' Fortran77Legacy " integer _this_is_a_long_identifier$") `shouldBe` resetSrcSpan [TType u "integer", TId u "_this_is_a_long_identifier$", TEOF u] - it "lexes ';' as a line-terminator" $ do+ it "lexes ';' as a line-terminator" $ resetSrcSpan (collectFixedTokens' Fortran77Legacy " integer i; integer j") `shouldBe` resetSrcSpan [TType u "integer", TId u "i", TNewline u, TType u "integer", TId u "j", TEOF u] - it "lexes subscripts in assignments" $ do+ it "lexes subscripts in assignments" $ resetSrcSpan (collectFixedTokens' Fortran77Legacy " x(0,0) = 0") `shouldBe` resetSrcSpan [TId u "x", TLeftPar u, TInt u "0", TComma u, TInt u "0", TRightPar u, TOpAssign u, TInt u "0", TEOF u] - it "lexes labeled DO WHILE blocks" $ do+ it "lexes labeled DO WHILE blocks" $ resetSrcSpan (collectFixedTokens' Fortran77Legacy " do 10 while (.true.)") `shouldBe` resetSrcSpan [TDo u, TInt u "10", TWhile u, TLeftPar u, TBool u ".true.", TRightPar u, TEOF u] @@ -257,6 +255,7 @@ , TEndStructure u, TNewline u , TEOF u ] +example1 :: String example1 = unlines [ " intEGerix", "1 iX= 42",@@ -264,6 +263,7 @@ " 10 wrITe (*,*), ix", " EnD" ] +continuationExample :: String continuationExample = unlines [ " inte", " .ger i",@@ -272,6 +272,7 @@ " .2", " end"] +example1Expectation :: [Token] example1Expectation = [ TType u "integer", TId u "ix", TNewline u, TLabel u "1", TId u "ix", TOpAssign u, TInt u "42", TNewline u,
test/Language/Fortran/Lexer/FreeFormSpec.hs view
@@ -3,17 +3,19 @@ import Test.Hspec import TestUtil -import Data.Maybe (fromJust)- import Language.Fortran.ParserMonad (FortranVersion(..)) import Language.Fortran.Lexer.FreeForm (collectFreeTokens, Token(..))+import Language.Fortran.Util.Position (SrcSpan) import qualified Data.ByteString.Char8 as B -import Debug.Trace- collectF90 :: String -> [ Token ] collectF90 = collectFreeTokens Fortran90 . B.pack +collectF03 :: String -> [ Token ]+collectF03 = collectFreeTokens Fortran2003 . B.pack+++pseudoAssign :: (SrcSpan -> Token) -> [Token] pseudoAssign token = fmap ($u) [ flip TId "i", TOpAssign, token, TEOF ] spec :: Spec@@ -136,6 +138,25 @@ , TDimension, TLeftPar, flip TIntegerLiteral "2" , TRightPar, TComma, TAllocatable, TDoubleColon , flip TId "y", TEOF ]++ it "try to trick lexer into parsing variables as attributes (1)" $+ shouldBe' (collectF90 "integer save, dimension(10), target") $+ fmap ($u) [ TInteger, flip TId "save", TComma+ , flip TId "dimension", TLeftPar, flip TIntegerLiteral "10", TRightPar, TComma+ , flip TId "target", TEOF ]++ it "try to trick lexer into parsing variables as attributes (2)" $+ shouldBe' (collectF90 "type(foo) save, dimension(10), target") $+ fmap ($u) [ TType, TLeftPar, flip TId "foo", TRightPar, flip TId "save", TComma+ , flip TId "dimension", TLeftPar, flip TIntegerLiteral "10", TRightPar, TComma+ , flip TId "target", TEOF ]++ it "try to trick lexer into parsing variables as attributes (3)" $+ shouldBe' (collectF90 "allocate(type(foo) :: errmsg(stat, source), source=x)") $+ fmap ($u) [ TAllocate, TLeftPar, TType, TLeftPar, flip TId "foo", TRightPar, TDoubleColon+ , flip TId "errmsg", TLeftPar, flip TId "stat", TComma, flip TId "source", TRightPar+ , TComma, TSource, TOpAssign, flip TId "x", TRightPar, TEOF ]+ describe "Character" $ do it "lexes single quote literal" $ shouldBe' (collectF90 "character c = 'heL\"Lo ''daRLing'") $@@ -261,3 +282,87 @@ it "Empty comment" $ shouldBe' (collectF90 "!\n") $ ($u) <$> [ flip TComment "", TNewline , TEOF ]++ describe "Subscripting" $ do+ it "Strings nested in arrays" $+ shouldBe' (collectF90 "a(1)(2:3) = 'we'") $+ ($u) <$> [ flip TId "a", TLeftPar, flip TIntegerLiteral "1", TRightPar+ , TLeftPar, flip TIntegerLiteral "2", TColon, flip TIntegerLiteral "3", TRightPar+ , TOpAssign, flip TString "we", TEOF ]++ describe "Fortran95" $ do+ it "lexes value attribute" $ do+ shouldBe' (collectF03 "value :: a, b") $+ fmap ($u) [ TValue, TDoubleColon, flip TId "a", TComma, flip TId "b", TEOF ]+ shouldBe' (collectF03 "integer, value :: a, b") $+ fmap ($u) [ TInteger, TComma, TValue, TDoubleColon, flip TId "a", TComma, flip TId "b", TEOF ]++ it "lexes volatile attribute" $ do+ shouldBe' (collectF03 "volatile :: a, b") $+ fmap ($u) [ TVolatile, TDoubleColon, flip TId "a", TComma, flip TId "b", TEOF ]+ shouldBe' (collectF03 "integer, volatile :: a, b") $+ fmap ($u) [ TInteger, TComma, TVolatile, TDoubleColon, flip TId "a", TComma, flip TId "b", TEOF ]++ describe "Fortran2003" $ do+ it "lexes procedures" $+ shouldBe' (collectF03 "PROCEDURE(a), SAVE :: b => c()") $+ ($u) <$> [ TProcedure, TLeftPar, flip TId "a", TRightPar+ , TComma, TSave, TDoubleColon+ , flip TId "b", TArrow, flip TId "c", TLeftPar, TRightPar, TEOF ]++ it "lexes procedures with bind" $+ shouldBe' (collectF03 "PROCEDURE(a), BIND(C, NAME=\"d\") :: b => c()") $+ ($u) <$> [ TProcedure, TLeftPar, flip TId "a", TRightPar+ , TComma, TBind, TLeftPar, TC, TComma, TName, TOpAssign, flip TString "d", TRightPar, TDoubleColon+ , flip TId "b", TArrow, flip TId "c", TLeftPar, TRightPar, TEOF ]++ it "lexes functions with bind" $+ shouldBe' (collectF03 "FUNCTION f(a) RESULT(x) BIND(C, NAME=\"d\")") $+ ($u) <$> [ TFunction, flip TId "f", TLeftPar, flip TId "a", TRightPar+ , TResult, TLeftPar, flip TId "x", TRightPar+ , TBind, TLeftPar, TC, TComma, TName, TOpAssign, flip TString "d", TRightPar, TEOF ]++ it "lexes subroutines with bind" $+ shouldBe' (collectF03 "SUBROUTINE s(a) BIND(C, NAME=\"d\")") $+ ($u) <$> [ TSubroutine, flip TId "s", TLeftPar, flip TId "a", TRightPar+ , TBind, TLeftPar, TC, TComma, TName, TOpAssign, flip TString "d", TRightPar, TEOF ]++ it "lexes class decl (name)" $+ shouldBe' (collectF03 "procedure (class(c))") $+ fmap ($u) [ TProcedure, TLeftPar+ , TClass, TLeftPar, flip TId "c", TRightPar, TRightPar, TEOF ]++ it "lexes class decl (*)" $+ shouldBe' (collectF03 "procedure (class(*))") $+ fmap ($u) [ TProcedure, TLeftPar+ , TClass, TLeftPar, TStar, TRightPar, TRightPar, TEOF ]++ it "lexes import statements" $+ shouldBe' (collectF03 "import :: a, b") $+ fmap ($u) [ TImport, TDoubleColon, flip TId "a", TComma, flip TId "b", TEOF ]++ it "lexes asynchronous attribute" $ do+ shouldBe' (collectF03 "asynchronous :: a, b") $+ fmap ($u) [ TAsynchronous, TDoubleColon, flip TId "a", TComma, flip TId "b", TEOF ]+ shouldBe' (collectF03 "integer, asynchronous :: a, b") $+ fmap ($u) [ TInteger, TComma, TAsynchronous, TDoubleColon, flip TId "a", TComma, flip TId "b", TEOF ]++ it "lexes enums" $ do+ shouldBe' (collectF03 "enum, bind(c)") $ fmap ($u) [ TEnum, TComma, TBind, TLeftPar, TC, TRightPar, TEOF ]+ shouldBe' (collectF03 "enumerator :: a = 1, b") $+ fmap ($u) [ TEnumerator, TDoubleColon, flip TId "a", TOpAssign, flip TIntegerLiteral "1"+ , TComma, flip TId "b", TEOF ]+ shouldBe' (collectF03 "end enum") $ fmap ($u) [ TEndEnum, TEOF ]++ it "lexes flush" $ do+ shouldBe' (collectF03 "flush(unit=1)") $+ fmap ($u) [ TFlush, TLeftPar, TUnit, TOpAssign, flip TIntegerLiteral "1", TRightPar, TEOF ]+ shouldBe' (collectF03 "flush(unit=1,iomsg=x,iostat=y,err=z)") $+ fmap ($u) [ TFlush, TLeftPar, TUnit, TOpAssign, flip TIntegerLiteral "1", TComma+ , TIOMsg, TOpAssign, flip TId "x", TComma+ , TIOStat, TOpAssign, flip TId "y", TComma+ , TErr, TOpAssign, flip TId "z", TRightPar, TEOF ]++ it "lexes protected" $ do+ shouldBe' (collectF03 "real, protected, public :: x") $+ fmap ($u) [ TReal, TComma, TProtected, TComma, TPublic, TDoubleColon, flip TId "x", TEOF ]
test/Language/Fortran/Parser/Fortran2003Spec.hs view
@@ -1,9 +1,156 @@ module Language.Fortran.Parser.Fortran2003Spec where ++import Prelude hiding (GT, EQ, exp, pred)++import TestUtil import Test.Hspec +import Language.Fortran.AST+import Language.Fortran.ParserMonad+import Language.Fortran.Lexer.FreeForm+import Language.Fortran.Parser.Fortran2003+import qualified Data.ByteString.Char8 as B++eParser :: String -> Expression ()+eParser sourceCode =+ case evalParse statementParser parseState of+ (StExpressionAssign _ _ _ e) -> e+ _ -> error "unhandled evalParse"+ where+ paddedSourceCode = B.pack $ " a = " ++ sourceCode+ parseState = initParseState paddedSourceCode Fortran2003 "<unknown>"++sParser :: String -> Statement ()+sParser sourceCode =+ evalParse statementParser $ initParseState (B.pack sourceCode) Fortran2003 "<unknown>"++fParser :: String -> ProgramUnit ()+fParser sourceCode =+ evalParse functionParser $ initParseState (B.pack sourceCode) Fortran2003 "<unknown>"+ spec :: Spec-spec = +spec = describe "Fortran 2003 Parser" $ do- it "TODO" $ do- pending+ describe "Modules" $ do+ it "parses use statement, intrinsic module" $ do+ let renames = fromList ()+ [ UseRename () u (varGen "sprod") (varGen "prod")+ , UseRename () u (varGen "a") (varGen "b") ]+ let st = StUse () u (varGen "mod") (Just ModIntrinsic) Permissive (Just renames)+ sParser "use, intrinsic :: mod, sprod => prod, a => b" `shouldBe'` st++ it "parses use statement, non_intrinsic module" $ do+ let renames = fromList ()+ [ UseRename () u (varGen "sprod") (varGen "prod")+ , UseRename () u (varGen "a") (varGen "b") ]+ let st = StUse () u (varGen "mod") (Just ModNonIntrinsic) Exclusive (Just renames)+ sParser "use, non_intrinsic :: mod, only: sprod => prod, a => b" `shouldBe'` st++ it "parses use statement, unspecified nature of module" $ do+ let renames = fromList ()+ [ UseRename () u (varGen "sprod") (varGen "prod")+ , UseRename () u (varGen "a") (varGen "b") ]+ let st = StUse () u (varGen "mod") Nothing Permissive (Just renames)+ sParser "use :: mod, sprod => prod, a => b" `shouldBe'` st++ it "parses procedure (interface-name, attribute, proc-decl)" $ do+ let call = ExpFunctionCall () u (varGen "c") Nothing+ let st = StProcedure () u (Just (ProcInterfaceName () u (varGen "a")))+ (Just (AttrSave () u))+ (AList () u [ProcDecl () u (varGen "b") (Just call)])+ sParser "PROCEDURE(a), SAVE :: b => c()" `shouldBe'` st++ it "parses procedure (class-star, bind-name, proc-decls)" $ do+ let call = ExpFunctionCall () u (varGen "c") Nothing+ let clas = TypeSpec () u ClassStar Nothing+ let st = StProcedure () u (Just (ProcInterfaceType () u clas))+ (Just (AttrSuffix () u (SfxBind () u (Just (ExpValue () u (ValString "e"))))))+ (AList () u [ProcDecl () u (varGen "b") (Just call)+ ,ProcDecl () u (varGen "d") (Just call)])+ sParser "PROCEDURE(CLASS(*)), BIND(C, NAME=\"e\") :: b => c(), d => c()" `shouldBe'` st++ it "parses procedure (class-custom, bind, proc-decls)" $ do+ let call = ExpFunctionCall () u (varGen "c") Nothing+ let clas = TypeSpec () u (ClassCustom "e") Nothing+ let st = StProcedure () u (Just (ProcInterfaceType () u clas))+ (Just (AttrSuffix () u (SfxBind () u Nothing)))+ (AList () u [ProcDecl () u (varGen "b") (Just call)+ ,ProcDecl () u (varGen "d") (Just call)])+ sParser "PROCEDURE(CLASS(e)), BIND(C) :: b => c(), d => c()" `shouldBe'` st++ it "import statements" $ do+ let st = StImport () u (AList () u [varGen "a", varGen "b"])+ sParser "import a, b" `shouldBe'` st+ sParser "import :: a, b" `shouldBe'` st++ it "parses function with bind" $ do+ let puFunction = PUFunction () u+ fType = Nothing+ fPre = emptyPrefixes+ fSuf = fromList' () [SfxBind () u (Just $ ExpValue () u (ValString "f"))]+ fName = "f"+ fArgs = Nothing+ fRes = Nothing+ fBody = []+ fSub = Nothing+ fStr = init $ unlines ["function f() bind(c,name=\"f\")"+ , "end function f" ]+ let expected = puFunction fType (fPre, fSuf) fName fArgs fRes fBody fSub+ fParser fStr `shouldBe'` expected++ it "parses asynchronous decl" $ do+ let decls = [DeclVariable () u (varGen "a") Nothing Nothing, DeclVariable () u (varGen "b") Nothing Nothing]+ let st = StAsynchronous () u (AList () u decls)+ sParser "asynchronous a, b" `shouldBe'` st+ sParser "asynchronous :: a, b" `shouldBe'` st++ it "parses asynchronous attribute" $ do+ let decls = [DeclVariable () u (varGen "a") Nothing Nothing, DeclVariable () u (varGen "b") Nothing Nothing]+ let ty = TypeSpec () u TypeInteger Nothing+ let attrs = [AttrAsynchronous () u]+ let st = StDeclaration () u ty (Just (AList () u attrs)) (AList () u decls)+ sParser "integer, asynchronous :: a, b" `shouldBe'` st++ it "parses enumerators" $ do+ let decls = [ DeclVariable () u (varGen "a") Nothing (Just (intGen 1))+ , DeclVariable () u (varGen "b") Nothing Nothing ]+ let st = StEnumerator () u (AList () u decls)+ sParser "enum, bind(c)" `shouldBe'` StEnum () u+ sParser "enumerator :: a = 1, b" `shouldBe'` st+ sParser "end enum" `shouldBe'` StEndEnum () u++ 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 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 st = StAllocate () u (Just ty) (AList () u [varGen "s"]) Nothing+ sParser "allocate(character(len=3,kind=foo) :: s)" `shouldBe'` st++ it "parses protected" $ do+ let ty = TypeSpec () u TypeReal Nothing+ let decls = AList () u [DeclVariable () u (varGen "x") Nothing Nothing]+ let st1 = StDeclaration () u ty (Just (AList () u [AttrProtected () u, AttrPublic () u])) decls+ let st2 = StProtected () u (Just (AList () u [varGen "x"]))+ sParser "real, protected, public :: x" `shouldBe'` st1+ sParser "protected x" `shouldBe'` st2++ describe "labelled where" $ do+ it "parses where construct statement" $+ sParser "foo: where (.true.)" `shouldBe'` StWhereConstruct () u (Just "foo") valTrue++ it "parses elsewhere statement" $+ sParser "elsewhere ab101" `shouldBe'` StElsewhere () u (Just "ab101") Nothing++ it "parses elsewhere statement" $ do+ let exp = ExpBinary () u GT (varGen "a") (varGen "b")+ sParser "elsewhere (a > b) A123" `shouldBe'` StElsewhere () u (Just "a123") (Just exp)++ it "parses endwhere statement" $+ sParser "endwhere foo1" `shouldBe'` StEndWhere () u (Just "foo1")
test/Language/Fortran/Parser/Fortran2008Spec.hs view
@@ -3,7 +3,6 @@ import Test.Hspec spec :: Spec-spec = - describe "Fortran 2008 Parser" $ do- it "TODO" $ do- pending+spec =+ describe "Fortran 2008 Parser" $+ it "TODO" pending
test/Language/Fortran/Parser/Fortran66Spec.hs view
@@ -3,7 +3,6 @@ import Test.Hspec import TestUtil -import Control.Monad.State.Lazy import Prelude hiding (LT) import Language.Fortran.Parser.Fortran66@@ -12,12 +11,11 @@ import Language.Fortran.AST import qualified Data.ByteString.Char8 as B -import Data.Typeable- eParser :: String -> Expression () eParser sourceCode = case evalParse statementParser parseState of (StExpressionAssign _ _ _ e) -> e+ _ -> error "unhandled evalParse" where paddedSourceCode = B.pack $ " a = " ++ sourceCode parseState = initParseState paddedSourceCode Fortran66 "<unknown>"
+ test/Language/Fortran/Parser/Fortran77/IncludeSpec.hs view
@@ -0,0 +1,53 @@+module Language.Fortran.Parser.Fortran77.IncludeSpec where++import Test.Hspec+import TestUtil++import Language.Fortran.Parser.Fortran77+import qualified Data.ByteString.Char8 as B+import Language.Fortran.ParserMonad+import Language.Fortran.Lexer.FixedForm+import Language.Fortran.AST+import Language.Fortran.Util.Position++iParser :: [String] -> String -> IO (ParseResult AlexInput Token (ProgramFile A0))+iParser incs src = legacy77ParserWithIncludes incs (B.pack src) "<unknown>"++makeSrcR :: (Int, Int, Int, String) -> (Int, Int, Int, String) -> SrcSpan+makeSrcR (i1, i2, i3, s) (j1, j2, j3, s') = SrcSpan (Position i1 i2 i3 s Nothing) (Position j1 j2 j3 s' Nothing)++spec :: SpecWith ()+spec =+ describe "Include Test" $ do+ let source = unlines [" program bar",+ " include 'foo.f'",+ " end"+ ]+ incs = ["./test/Language/Fortran/Parser"]+ name = "bar"+ pf = ProgramFile mi77 [pu]+ puSpan = makeSrcR (6,7,1,"<unknown>") (48,9,3,"<unknown>")+ st1Span = makeSrcR (24,7,2,"<unknown>") (38,21,2,"<unknown>")+ expSpan = makeSrcR (32,15,2,"<unknown>") (38,21,2,"<unknown>")++ -- the expansion returns the span in the included file+ -- it should return the span at the inclusion+ st2Span = makeSrcR (6,7,1,"foo.f") (14,15,1,"foo.f")+ declSpan = makeSrcR (6,7,1,"foo.f") (14,15,1,"foo.f")+ typeSpan = makeSrcR (6,7,1,"foo.f") (12,13,1,"foo.f")+ blockSpan = makeSrcR (14,15,1,"foo.f") (14,15,1,"foo.f")+ varGen' str = ExpValue () blockSpan $ ValVariable str++ pu = PUMain () puSpan (Just name) blocks Nothing+ blocks = [bl1]+ decl = DeclVariable () blockSpan (varGen' "a") Nothing Nothing+ typeSpec = TypeSpec () typeSpan TypeInteger Nothing+ st2 = StDeclaration () st2Span typeSpec Nothing (AList () blockSpan [decl])+ bl1 = BlStatement () st1Span Nothing st1+ st1 = StInclude () st1Span ex (Just [bl2])+ ex = ExpValue () expSpan (ValString "foo.f")+ bl2 = BlStatement () declSpan Nothing st2+ it "includes some files and expands them" $ do+ ps <- iParser incs source+ let pr = fromParseResultUnsafe ps+ pr `shouldBe` pf
+ test/Language/Fortran/Parser/Fortran77/ParserSpec.hs view
@@ -0,0 +1,312 @@+module Language.Fortran.Parser.Fortran77.ParserSpec where++import Test.Hspec+import TestUtil++import Prelude hiding (exp)+import Language.Fortran.Parser.Fortran77+import Language.Fortran.Lexer.FixedForm (initParseState)+import Language.Fortran.ParserMonad (FortranVersion(..), evalParse, fromParseResultUnsafe)+import Language.Fortran.AST+import qualified Data.ByteString.Char8 as B++{-# ANN module "HLint: ignore Reduce duplication" #-}++eParser :: String -> Expression ()+eParser sourceCode =+ case evalParse statementParser parseState of+ (StExpressionAssign _ _ _ e) -> e+ _ -> error "unhandled evalParse"+ where+ paddedSourceCode = B.pack $ " a = " ++ sourceCode+ parseState = initParseState paddedSourceCode Fortran77 "<unknown>"++sParser :: String -> Statement ()+sParser sourceCode =+ evalParse statementParser $ initParseState (B.pack sourceCode) Fortran77 "<unknown>"++slParser :: String -> Statement ()+slParser sourceCode =+ evalParse statementParser $ initParseState (B.pack sourceCode) Fortran77Legacy "<unknown>"++iParser :: String -> [Block ()]+iParser sourceCode =+ fromParseResultUnsafe $ includeParser Fortran77Legacy (B.pack sourceCode) "<unknown>"++pParser :: String -> ProgramFile ()+pParser source = fromParseResultUnsafe $ fortran77Parser (B.pack source) "<unknown>"++spec :: Spec+spec =+ describe "Fortran 77 Parser" $ do+ describe "IO" $ do+ it "parses 'print *, 9000" $ do+ let expectedSt = StPrint () u starVal $ Just (AList () u [ intGen 9000 ])+ sParser " print *, 9000" `shouldBe'` expectedSt++ it "parses 'write (UNIT=6, FORMAT=*)" $ do+ let cp1 = ControlPair () u (Just "unit") (intGen 6)+ cp2 = ControlPair () u (Just "format") starVal+ expectedSt = StWrite () u (AList () u [cp1, cp2]) Nothing+ sParser " write (UNIT=6, FORMAT=*)" `shouldBe'` expectedSt++ it "parses 'endfile i" $+ sParser " endfile i" `shouldBe'` StEndfile2 () u (varGen "i")++ it "parses 'read *, (x, y(i), i = 1, 10, 2)'" $ do+ let stAssign = StExpressionAssign () u (varGen "i") (intGen 1)+ doSpec = DoSpecification () u stAssign (intGen 10) (Just $ intGen 2)+ impliedDoVars = AList () u [ varGen "x", ExpSubscript () u (varGen "y") (AList () u [ IxSingle () u Nothing $ varGen "i" ])]+ impliedDo = ExpImpliedDo () u impliedDoVars doSpec+ iolist = AList () u [ impliedDo ]+ expectedSt = StRead2 () u starVal (Just iolist)+ sParser " read *, (x, y(i), i = 1, 10, 2)" `shouldBe'` expectedSt++ it "parses '(x, y(i), i = 1, 10, 2)'" $ do+ let stAssign = StExpressionAssign () u (varGen "i") (intGen 1)+ doSpec = DoSpecification () u stAssign (intGen 10) (Just $ intGen 2)+ impliedDoVars = AList () u [ varGen "x", ExpSubscript () u (varGen "y") (AList () u [ IxSingle () u Nothing $ varGen "i" ])]+ impliedDo = ExpImpliedDo () u impliedDoVars doSpec+ eParser "(x, y(i), i = 1, 10, 2)" `shouldBe'` impliedDo++ it "parses main program unit" $ do+ let decl = DeclVariable () u (varGen "x") Nothing Nothing+ st = StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ decl ])+ bl = BlStatement () u Nothing st+ pu = ProgramFile mi77 [ PUMain () u (Just "hello") [ bl ] Nothing ]+ pParser exampleProgram1 `shouldBe'` pu++ it "parses block data unit" $ do+ let decl = DeclVariable () u (varGen "x") Nothing Nothing+ st = StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ decl ])+ bl = BlStatement () u Nothing st+ pu = ProgramFile mi77 [ PUBlockData () u (Just "hello") [ bl ] ]+ pParser exampleProgram2 `shouldBe'` pu++ it "parses 'intrinsic cosh, sin'" $ do+ let fun1 = ExpValue () u (ValVariable "cosh")+ fun2 = ExpValue () u (ValVariable "sin")+ st = StIntrinsic () u (AList () u [ fun1, fun2 ])+ sParser " intrinsic cosh, sin" `shouldBe'` st++ it "parses 'intrinsic real" $ do+ let fun = ExpValue () u (ValVariable "real")+ st = StIntrinsic () u (AList () u [ fun ])+ sParser " intrinsic real" `shouldBe'` st++ describe "CHARACTER" $ do+ it "parses character literal assignment" $ do+ let rhs = ExpValue () u (ValString "hello 'baby")+ st = StExpressionAssign () u (varGen "xyz") rhs+ sParser " xyz = 'hello ''baby'" `shouldBe'` st++ it "string concatenation" $ do+ let str1 = ExpValue () u (ValString "hello ")+ str2 = ExpValue () u (ValString "world")+ exp = ExpBinary () u Concatenation str1 str2+ eParser "'hello ' // 'world'" `shouldBe'` exp++ describe "Subscript like" $ do+ it "parses vanilla subscript" $ do+ let exp = ExpSubscript () u (varGen "a") (AList () u [ IxSingle () u Nothing $ varGen "x", IxSingle () u Nothing $ intGen 2, IxSingle () u Nothing $ intGen 3 ])+ eParser "a(x, 2, 3)" `shouldBe'` exp++ it "parses array declarator" $ do+ let dimDecls = [ DimensionDeclarator () u (Just $ intGen 1) (Just $ intGen 2)+ , DimensionDeclarator () u Nothing (Just $ intGen 15)+ , DimensionDeclarator () u (Just $ varGen "x") (Just starVal) ]+ decl = DeclArray () u (varGen "a") (AList () u dimDecls) Nothing Nothing+ st = StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ decl ])+ sParser " integer a(1:2, 15, x:*)" `shouldBe'` st++ it "parses character substring" $ do+ let indicies = [ ixSinGen 1, ixSinGen 2, ixSinGen 3 ]+ subExp = ExpSubscript () u (varGen "a") (AList () u indicies)+ range = IxRange () u Nothing (Just $ intGen 10) Nothing+ exp = ExpSubscript () u subExp (AList () u [ range ])+ eParser "a(1, 2, 3)(:10)" `shouldBe'` exp++ it "parses simpler substring" $ do+ let exp = ExpSubscript () u (varGen "a") (AList () u [ ixRanGen 5 10 ])+ eParser "a(5:10)" `shouldBe'` exp++ it "parses simpler substring" $ do+ let range = IxRange () u (Just $ intGen 5) Nothing Nothing+ exp = ExpSubscript () u (varGen "a") (AList () u [ range ])+ eParser "a(5:)" `shouldBe'` exp++ describe "GOTO" $ do+ it "parses computed GOTO with integer expression" $ do+ let exp = ExpBinary () u Multiplication (intGen 42) (intGen 24)+ st = StGotoComputed () u (AList () u [labelGen 10, labelGen 20, labelGen 30]) exp+ sParser " GOTO (10, 20, 30), 42 * 24" `shouldBe'` st++ let gotoSt = StGotoAssigned () u (varGen "v") (Just (AList () u [labelGen 10, labelGen 20, labelGen 30]))+ it "parses assigned GOTO with comma" $+ sParser " GOTO v, (10, 20, 30)" `shouldBe'` gotoSt++ it "parses assigned GOTO without comma" $+ sParser " GOTO v (10, 20, 30)" `shouldBe'` gotoSt++ describe "IMPLICIT" $ do+ it "parses 'implicit none'" $ do+ let st = resetSrcSpan $ StImplicit () u Nothing+ sParser " implicit none" `shouldBe'` st++ 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+ 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++ it "parses 'parameter (pi = 3.14, b = 'X' // 'O', d = k) '" $ do+ let sts = [ DeclVariable () u (varGen "pi") Nothing (Just $ realGen (3.14::Double))+ , let e = ExpBinary () u Concatenation (strGen "X") (strGen "O")+ in DeclVariable () u (varGen "b") Nothing (Just e)+ , DeclVariable () u (varGen "d") Nothing (Just $ varGen "k") ]+ st = StParameter () u (AList () u sts)+ sParser " parameter (pi = 3.14, b = 'X' // 'O', d = k)" `shouldBe'` st++ it "parses 'pause 'hello world''" $ do+ let st = StPause () u $ Just $ strGen "hello world"+ sParser " pause 'hello world'" `shouldBe'` st++ describe "SAVE" $ do+ it "parses 'save /cb/, var, /key/'" $ do+ let saveArgs = [ varGen "cb", varGen "var", varGen "key" ]+ st = StSave () u (Just $ AList () u saveArgs)+ sParser " save /cb/, var, /key/" `shouldBe'` st++ it "parses 'save'" $+ sParser " save" `shouldBe'` StSave () u Nothing++ it "parses '.true. .eqv. f(42) .neqv. x'" $ do+ let arg2 = ExpSubscript () u (varGen "f") $ AList () u [ ixSinGen 42 ]+ arg3 = varGen "x"+ subexp = ExpBinary () u Equivalent valTrue arg2+ exp = ExpBinary () u NotEquivalent subexp arg3+ eParser ".true. .eqv. f(42) .neqv. x" `shouldBe'` exp++ it "parses 'entry me (a,b,*)'" $ do+ let func = ExpValue () u (ValVariable "me")+ args = [ varGen "a", varGen "b", starVal ]+ st = StEntry () u func (Just $ AList () u args) Nothing+ sParser " entry me (a,b,*)" `shouldBe'` st++ it "parses 'character a*8'" $ do+ let decl = DeclVariable () u (varGen "a") (Just $ intGen 8) Nothing+ typeSpec = TypeSpec () u (TypeCharacter Nothing Nothing) Nothing+ st = StDeclaration () u typeSpec Nothing (AList () u [ decl ])+ sParser " character a*8" `shouldBe'` st++ it "parses included files" $ do+ let decl = DeclVariable () u (varGen "a") Nothing Nothing+ typeSpec = TypeSpec () u TypeInteger Nothing+ st = StDeclaration () u typeSpec Nothing (AList () u [ decl ])+ bl = BlStatement () u Nothing st+ iParser " integer a" `shouldBe'` [bl]++ describe "Legacy Extensions" $ do+ it "parses structure/union/map blocks" $ do+ let src = init+ $ unlines [ " structure /foo/"+ , " union"+ , " map"+ , " integer i"+ , " end map"+ , " map"+ , " real r"+ , " end map"+ , " end union"+ , " end structure"]+ ds = [ UnionMap () u $ AList () u+ [StructFields () u (TypeSpec () u TypeInteger Nothing) Nothing $+ AList () u [DeclVariable () u (varGen "i") Nothing Nothing]]+ , UnionMap () u $ AList () u+ [StructFields () u (TypeSpec () u TypeReal Nothing) Nothing $+ AList () u [DeclVariable () u (varGen "r") Nothing Nothing]]+ ]+ st = StStructure () u (Just "foo") $ AList () u [StructUnion () u $ AList () u ds]+ resetSrcSpan (slParser src) `shouldBe` st++ it "parses character declarations with unspecfied lengths" $ do+ let src = " character s*(*)"+ st = StDeclaration () u (TypeSpec () u (TypeCharacter Nothing Nothing) Nothing) Nothing $+ AList () u [DeclVariable () u+ (ExpValue () u (ValVariable "s"))+ (Just (ExpValue () u ValStar))+ Nothing]+ resetSrcSpan (slParser src) `shouldBe` st++ it "parses array initializers" $ do+ let src = " integer xs(3) / 1, 2, 3 /"+ inits = [ExpValue () u (ValInteger "1"), ExpValue () u (ValInteger "2"), ExpValue () u (ValInteger "3")]+ st = StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing $+ AList () u [DeclArray () u+ (ExpValue () u (ValVariable "xs"))+ (AList () u [DimensionDeclarator () u Nothing (Just (ExpValue () u (ValInteger "3")))])+ Nothing+ (Just (ExpInitialisation () u $ AList () u inits))]+ resetSrcSpan (slParser src) `shouldBe` st++ 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 $+ AList () u [DeclArray () u+ (ExpValue () u (ValVariable "xs"))+ (AList () u [DimensionDeclarator () u Nothing (Just (ExpValue () u (ValInteger "2")))])+ (Just (ExpValue () u (ValInteger "5")))+ (Just (ExpInitialisation () u $ AList () u inits1))]+ resetSrcSpan (slParser src1) `shouldBe` st1++ 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 $+ AList () u [DeclArray () u+ (ExpValue () u (ValVariable "xs"))+ (AList () u [DimensionDeclarator () u Nothing (Just (ExpValue () u (ValInteger "2")))])+ (Just (ExpValue () u (ValInteger "5")))+ (Just (ExpInitialisation () u $ AList () u inits2))]+ resetSrcSpan (slParser src2) `shouldBe` st2++ it "parses subscripts in assignments" $ do+ let mkIdx i = IxSingle () u Nothing (ExpValue () u (ValInteger i))++ src = " x(0,1) = 0"+ tgt = ExpSubscript () u (ExpValue () u (ValVariable "x")) (AList () u [mkIdx "0", mkIdx "1"])+ st = StExpressionAssign () u tgt (ExpValue () u (ValInteger "0"))+ resetSrcSpan (slParser src) `shouldBe` st++ let src1 = " x(0).foo = 0"+ tgt1 = ExpDataRef () u (ExpSubscript () u (ExpValue () u (ValVariable "x")) (AList () u [mkIdx "0"])) (ExpValue () u (ValVariable "foo"))+ st1 = StExpressionAssign () u tgt1 (ExpValue () u (ValInteger "0"))+ resetSrcSpan (slParser src1) `shouldBe` st1++ let src2 = " x.foo = 0"+ tgt2 = ExpDataRef () u (ExpValue () u (ValVariable "x")) (ExpValue () u (ValVariable "foo"))+ st2 = StExpressionAssign () u tgt2 (ExpValue () u (ValInteger "0"))+ resetSrcSpan (slParser src2) `shouldBe` st2++ let src3 = " x.foo(0) = 0"+ tgt3 = ExpSubscript () u (ExpDataRef () u (ExpValue () u (ValVariable "x")) (ExpValue () u (ValVariable "foo"))) (AList () u [mkIdx "0"])+ st3 = StExpressionAssign () u tgt3 (ExpValue () u (ValInteger "0"))+ resetSrcSpan (slParser src3) `shouldBe` st3++exampleProgram1 :: String+exampleProgram1 = unlines+ [ " program hello"+ , " integer x"+ , " end" ]++exampleProgram2 :: String+exampleProgram2 = unlines+ [ " block data hello"+ , " integer x"+ , " end" ]++-- Local variables:+-- mode: haskell+-- haskell-program-name: "cabal repl test-suite:spec"+-- End:
− test/Language/Fortran/Parser/Fortran77Spec.hs
@@ -1,306 +0,0 @@-module Language.Fortran.Parser.Fortran77Spec where--import Test.Hspec-import TestUtil--import Language.Fortran.Parser.Fortran77-import Language.Fortran.Lexer.FixedForm (initParseState)-import Language.Fortran.ParserMonad (FortranVersion(..), evalParse, fromParseResultUnsafe)-import Language.Fortran.AST-import qualified Data.ByteString.Char8 as B--eParser :: String -> Expression ()-eParser sourceCode =- case evalParse statementParser parseState of- (StExpressionAssign _ _ _ e) -> e- where- paddedSourceCode = B.pack $ " a = " ++ sourceCode- parseState = initParseState paddedSourceCode Fortran77 "<unknown>"--sParser :: String -> Statement ()-sParser sourceCode =- evalParse statementParser $ initParseState (B.pack sourceCode) Fortran77 "<unknown>"--slParser :: String -> Statement ()-slParser sourceCode =- evalParse statementParser $ initParseState (B.pack sourceCode) Fortran77Legacy "<unknown>"--iParser :: String -> [Block ()]-iParser sourceCode =- fromParseResultUnsafe $ includeParser Fortran77Legacy (B.pack sourceCode) "<unknown>"--pParser :: String -> ProgramFile ()-pParser source = fromParseResultUnsafe $ fortran77Parser (B.pack source) "<unknown>"--spec :: Spec-spec =- describe "Fortran 77 Parser" $ do- describe "IO" $ do- it "parses 'print *, 9000" $ do- let expectedSt = StPrint () u starVal $ Just (AList () u [ intGen 9000 ])- sParser " print *, 9000" `shouldBe'` expectedSt-- it "parses 'write (UNIT=6, FORMAT=*)" $ do- let cp1 = ControlPair () u (Just "unit") (intGen 6)- let cp2 = ControlPair () u (Just "format") starVal- let expectedSt = StWrite () u (AList () u [cp1, cp2]) Nothing- sParser " write (UNIT=6, FORMAT=*)" `shouldBe'` expectedSt-- it "parses 'endfile i" $- sParser " endfile i" `shouldBe'` StEndfile2 () u (varGen "i")-- it "parses 'read *, (x, y(i), i = 1, 10, 2)'" $ do- let stAssign = StExpressionAssign () u (varGen "i") (intGen 1)- let doSpec = DoSpecification () u stAssign (intGen 10) (Just $ intGen 2)- let impliedDoVars = AList () u [ varGen "x", ExpSubscript () u (varGen "y") (AList () u [ IxSingle () u Nothing $ varGen "i" ])]- let impliedDo = ExpImpliedDo () u impliedDoVars doSpec- let iolist = AList () u [ impliedDo ]- let expectedSt = StRead2 () u starVal (Just iolist)- sParser " read *, (x, y(i), i = 1, 10, 2)" `shouldBe'` expectedSt-- it "parses '(x, y(i), i = 1, 10, 2)'" $ do- let stAssign = StExpressionAssign () u (varGen "i") (intGen 1)- let doSpec = DoSpecification () u stAssign (intGen 10) (Just $ intGen 2)- let impliedDoVars = AList () u [ varGen "x", ExpSubscript () u (varGen "y") (AList () u [ IxSingle () u Nothing $ varGen "i" ])]- let impliedDo = ExpImpliedDo () u impliedDoVars doSpec- eParser "(x, y(i), i = 1, 10, 2)" `shouldBe'` impliedDo-- it "parses main program unit" $ do- let decl = DeclVariable () u (varGen "x") Nothing Nothing- let st = StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ decl ])- let bl = BlStatement () u Nothing st- let pu = ProgramFile mi77 [ PUMain () u (Just "hello") [ bl ] Nothing ]- pParser exampleProgram1 `shouldBe'` pu-- it "parses block data unit" $ do- let decl = DeclVariable () u (varGen "x") Nothing Nothing- let st = StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ decl ])- let bl = BlStatement () u Nothing st- let pu = ProgramFile mi77 [ PUBlockData () u (Just "hello") [ bl ] ]- pParser exampleProgram2 `shouldBe'` pu-- it "parses 'intrinsic cosh, sin'" $ do- let fun1 = ExpValue () u (ValVariable "cosh")- let fun2 = ExpValue () u (ValVariable "sin")- let st = StIntrinsic () u (AList () u [ fun1, fun2 ])- sParser " intrinsic cosh, sin" `shouldBe'` st-- it "parses 'intrinsic real" $ do- let fun = ExpValue () u (ValVariable "real")- let st = StIntrinsic () u (AList () u [ fun ])- sParser " intrinsic real" `shouldBe'` st-- describe "CHARACTER" $ do- it "parses character literal assignment" $ do- let rhs = ExpValue () u (ValString "hello 'baby")- let st = StExpressionAssign () u (varGen "xyz") rhs- sParser " xyz = 'hello ''baby'" `shouldBe'` st-- it "string concatenation" $ do- let str1 = ExpValue () u (ValString "hello ")- let str2 = ExpValue () u (ValString "world")- let exp = ExpBinary () u Concatenation str1 str2- eParser "'hello ' // 'world'" `shouldBe'` exp-- describe "Subscript like" $ do- it "parses vanilla subscript" $ do- let exp = ExpSubscript () u (varGen "a") (AList () u [ IxSingle () u Nothing $ varGen "x", IxSingle () u Nothing $ intGen 2, IxSingle () u Nothing $ intGen 3 ])- eParser "a(x, 2, 3)" `shouldBe'` exp-- it "parses array declarator" $ do- let dimDecls = [ DimensionDeclarator () u (Just $ intGen 1) (Just $ intGen 2)- , DimensionDeclarator () u Nothing (Just $ intGen 15)- , DimensionDeclarator () u (Just $ varGen "x") (Just $ starVal) ]- let decl = DeclArray () u (varGen "a") (AList () u dimDecls) Nothing Nothing- let st = StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ decl ])- sParser " integer a(1:2, 15, x:*)" `shouldBe'` st-- it "parses character substring" $ do- let indicies = [ ixSinGen 1, ixSinGen 2, ixSinGen 3 ]- let subExp = ExpSubscript () u (varGen "a") (AList () u indicies)- let range = IxRange () u Nothing (Just $ intGen 10) Nothing- let exp = ExpSubscript () u subExp (AList () u [ range ])- eParser "a(1, 2, 3)(:10)" `shouldBe'` exp-- it "parses simpler substring" $ do- let exp = ExpSubscript () u (varGen "a") (AList () u [ ixRanGen 5 10 ])- eParser "a(5:10)" `shouldBe'` exp-- it "parses simpler substring" $ do- let range = IxRange () u (Just $ intGen 5) Nothing Nothing- let exp = ExpSubscript () u (varGen "a") (AList () u [ range ])- eParser "a(5:)" `shouldBe'` exp-- describe "GOTO" $ do- it "parses computed GOTO with integer expression" $ do- let exp = ExpBinary () u Multiplication (intGen 42) (intGen 24)- let st = StGotoComputed () u (AList () u [labelGen 10, labelGen 20, labelGen 30]) exp- sParser " GOTO (10, 20, 30), 42 * 24" `shouldBe'` st-- let gotoSt = StGotoAssigned () u (varGen "v") (Just (AList () u [labelGen 10, labelGen 20, labelGen 30]))- it "parses assigned GOTO with comma" $- sParser " GOTO v, (10, 20, 30)" `shouldBe'` gotoSt-- it "parses assigned GOTO without comma" $- sParser " GOTO v (10, 20, 30)" `shouldBe'` gotoSt-- describe "IMPLICIT" $ do- it "parses 'implicit none'" $ do- let st = resetSrcSpan $ StImplicit () u Nothing- sParser " implicit none" `shouldBe'` st-- it "parses 'implicit character*30 (a, b, c), integer (a-z, l)" $ do- let impEls = [ImpCharacter () u "a", ImpCharacter () u "b", ImpCharacter () u "c"]- let selector = Selector () u (Just $ intGen 30) Nothing- let imp1 = ImpList () u (TypeSpec () u TypeCharacter (Just selector)) $ AList () u impEls- let imp2 = ImpList () u (TypeSpec () u TypeInteger Nothing) $ AList () u [ImpRange () u "a" "z", ImpCharacter () u "l"]- let st = StImplicit () u $ Just $ AList () u [imp1, imp2]- sParser " implicit character*30 (a, b, c), integer (a-z, l)" `shouldBe'` st-- it "parses 'parameter (pi = 3.14, b = 'X' // 'O', d = k) '" $ do- let sts = [ DeclVariable () u (varGen "pi") Nothing (Just $ realGen 3.14)- , let e = ExpBinary () u Concatenation (strGen "X") (strGen "O")- in DeclVariable () u (varGen "b") Nothing (Just e)- , DeclVariable () u (varGen "d") Nothing (Just $ varGen "k") ]- let st = StParameter () u (AList () u sts)- sParser " parameter (pi = 3.14, b = 'X' // 'O', d = k)" `shouldBe'` st-- it "parses 'pause 'hello world''" $ do- let st = StPause () u $ Just $ strGen "hello world"- sParser " pause 'hello world'" `shouldBe'` st-- describe "SAVE" $ do- it "parses 'save /cb/, var, /key/'" $ do- let saveArgs = [ varGen "cb", varGen "var", varGen "key" ]- let st = StSave () u (Just $ AList () u saveArgs)- sParser " save /cb/, var, /key/" `shouldBe'` st-- it "parses 'save'" $- sParser " save" `shouldBe'` StSave () u Nothing-- it "parses '.true. .eqv. f(42) .neqv. x'" $ do- let arg2 = ExpSubscript () u (varGen "f") $ AList () u [ ixSinGen 42 ]- let arg3 = varGen "x"- let subexp = ExpBinary () u Equivalent valTrue arg2- let exp = ExpBinary () u NotEquivalent subexp arg3- eParser ".true. .eqv. f(42) .neqv. x" `shouldBe'` exp-- it "parses 'entry me (a,b,*)'" $ do- let func = ExpValue () u (ValVariable "me")- let args = [ varGen "a", varGen "b", starVal ]- let st = StEntry () u func (Just $ AList () u args) Nothing- sParser " entry me (a,b,*)" `shouldBe'` st-- it "parses 'character a*8'" $ do- let decl = DeclVariable () u (varGen "a") (Just $ intGen 8) Nothing- let typeSpec = TypeSpec () u TypeCharacter Nothing- let st = StDeclaration () u typeSpec Nothing (AList () u [ decl ])- sParser " character a*8" `shouldBe'` st-- it "parses included files" $ do- let decl = DeclVariable () u (varGen "a") Nothing Nothing- let typeSpec = TypeSpec () u TypeInteger Nothing- let st = StDeclaration () u typeSpec Nothing (AList () u [ decl ])- let bl = BlStatement () u Nothing st- iParser " integer a" `shouldBe'` [bl]-- describe "Legacy Extensions" $ do- it "parses structure/union/map blocks" $ do- let src = init- $ unlines [ " structure /foo/"- , " union"- , " map"- , " integer i"- , " end map"- , " map"- , " real r"- , " end map"- , " end union"- , " end structure"]- let ds = [ UnionMap () u $ AList () u- [StructFields () u (TypeSpec () u TypeInteger Nothing) Nothing $- AList () u [DeclVariable () u (varGen "i") Nothing Nothing]]- , UnionMap () u $ AList () u- [StructFields () u (TypeSpec () u TypeReal Nothing) Nothing $- AList () u [DeclVariable () u (varGen "r") Nothing Nothing]]- ]- let st = StStructure () u (Just "foo") $ AList () u [StructUnion () u $ AList () u ds]- resetSrcSpan (slParser src) `shouldBe` st-- it "parses character declarations with unspecfied lengths" $ do- let src = " character s*(*)"- let st = StDeclaration () u (TypeSpec () u TypeCharacter Nothing) Nothing $- AList () u [DeclVariable () u- (ExpValue () u (ValVariable "s"))- (Just (ExpValue () u ValStar))- Nothing]- resetSrcSpan (slParser src) `shouldBe` st-- it "parses array initializers" $ do- let src = " integer xs(3) / 1, 2, 3 /"- let inits = [ExpValue () u (ValInteger "1"), ExpValue () u (ValInteger "2"), ExpValue () u (ValInteger "3")]- let st = StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing $- AList () u [DeclArray () u- (ExpValue () u (ValVariable "xs"))- (AList () u [DimensionDeclarator () u Nothing (Just (ExpValue () u (ValInteger "3")))])- Nothing- (Just (ExpInitialisation () u $ AList () u inits))]- resetSrcSpan (slParser src) `shouldBe` st-- let src = " character xs(2)*5 / 'hello', 'world' /"- let inits = [ExpValue () u (ValString "hello"), ExpValue () u (ValString "world")]- let st = 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")))])- (Just (ExpValue () u (ValInteger "5")))- (Just (ExpInitialisation () u $ AList () u inits))]- resetSrcSpan (slParser src) `shouldBe` st-- let src = " character xs*5(2) / 'hello', 'world' /"- let inits = [ExpValue () u (ValString "hello"), ExpValue () u (ValString "world")]- let st = 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")))])- (Just (ExpValue () u (ValInteger "5")))- (Just (ExpInitialisation () u $ AList () u inits))]- resetSrcSpan (slParser src) `shouldBe` st-- it "parses subscripts in assignments" $ do- let mkIdx i = IxSingle () u Nothing (ExpValue () u (ValInteger i))-- let src = " x(0,1) = 0"- let tgt = ExpSubscript () u (ExpValue () u (ValVariable "x")) (AList () u [mkIdx "0", mkIdx "1"])- let st = StExpressionAssign () u tgt (ExpValue () u (ValInteger "0"))- resetSrcSpan (slParser src) `shouldBe` st-- let src = " x(0).foo = 0"- let tgt = ExpDataRef () u (ExpSubscript () u (ExpValue () u (ValVariable "x")) (AList () u [mkIdx "0"])) (ExpValue () u (ValVariable "foo"))- let st = StExpressionAssign () u tgt (ExpValue () u (ValInteger "0"))- resetSrcSpan (slParser src) `shouldBe` st-- let src = " x.foo = 0"- let tgt = ExpDataRef () u (ExpValue () u (ValVariable "x")) (ExpValue () u (ValVariable "foo"))- let st = StExpressionAssign () u tgt (ExpValue () u (ValInteger "0"))- resetSrcSpan (slParser src) `shouldBe` st-- let src = " x.foo(0) = 0"- let tgt = ExpSubscript () u (ExpDataRef () u (ExpValue () u (ValVariable "x")) (ExpValue () u (ValVariable "foo"))) (AList () u [mkIdx "0"])- let st = StExpressionAssign () u tgt (ExpValue () u (ValInteger "0"))- resetSrcSpan (slParser src) `shouldBe` st--exampleProgram1 = unlines- [ " program hello"- , " integer x"- , " end" ]--exampleProgram2 = unlines- [ " block data hello"- , " integer x"- , " end" ]---- Local variables:--- mode: haskell--- haskell-program-name: "cabal repl test-suite:spec"--- End:
test/Language/Fortran/Parser/Fortran90Spec.hs view
@@ -1,6 +1,6 @@ module Language.Fortran.Parser.Fortran90Spec (spec) where -import Prelude hiding (GT)+import Prelude hiding (GT, exp, pred) import TestUtil import Test.Hspec@@ -9,13 +9,16 @@ import Language.Fortran.ParserMonad import Language.Fortran.Lexer.FreeForm import Language.Fortran.Parser.Fortran90-import qualified Data.List as List+--import qualified Data.List as List import qualified Data.ByteString.Char8 as B +{-# ANN module "HLint: ignore Reduce duplication" #-}+ eParser :: String -> Expression () eParser sourceCode = case evalParse statementParser parseState of (StExpressionAssign _ _ _ e) -> e+ _ -> error "unhandled evalParse" where paddedSourceCode = B.pack $ " a = " ++ sourceCode parseState = initParseState paddedSourceCode Fortran90 "<unknown>"@@ -37,8 +40,8 @@ - Given a list of values, find every combination of those values: - combination [1,2] = [[], [1], [2], [1,2], [2,1]] -}-combination :: [a] -> [[a]]-combination = foldr ((++) . List.permutations) [] . List.subsequences+--combination :: [a] -> [[a]]+--combination = foldr ((++) . List.permutations) [] . List.subsequences spec :: Spec spec =@@ -46,87 +49,89 @@ describe "Function" $ do let puFunction = PUFunction () u let fType = Nothing- let fOpt = None () u False- let fName = "f"- let fArgs = Nothing- let fRes = Nothing- let fBody = []- let fSub = Nothing+ fPre = emptyPrefixes+ fPreR = Just $ AList () u [PfxRecursive () u]+ fSuf = emptySuffixes+ fPreSuf = (fPre, fSuf)+ fName = "f"+ fArgs = Nothing+ fRes = Nothing+ fBody = []+ fSub = Nothing describe "End" $ do it "parses simple functions ending with \"end function [function name]\"" $ do- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub+ let expected = puFunction fType fPreSuf fName fArgs fRes fBody fSub let fStr = init $ unlines ["function f()" , "end function f" ] fParser fStr `shouldBe'` expected it "parses simple functions ending with \"end\"" $ do- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub+ let expected = puFunction fType fPreSuf fName fArgs fRes fBody fSub let fStr = init $ unlines ["function f()" , "end" ] fParser fStr `shouldBe'` expected it "parses simple functions ending with \"end function\"" $ do- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub+ let expected = puFunction fType fPreSuf fName fArgs fRes fBody fSub let fStr = init $ unlines ["function f()" , "end function" ] fParser fStr `shouldBe'` expected it "parses functions with return type specs" $ do- let fType = Just $ TypeSpec () u TypeInteger Nothing- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub+ let fType' = Just $ TypeSpec () u TypeInteger Nothing+ let expected = puFunction fType' fPreSuf fName fArgs fRes fBody fSub let fStr = init $ unlines ["integer function f()" , "end function f" ] fParser fStr `shouldBe'` expected - it "parses recursive functions" $ do- let fOpt = None () u True- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- let fStr = init $ unlines ["recursive function f()", "end"]- fParser fStr `shouldBe'` expected+ it "parses recursive functions" $+ let expected = puFunction fType (fPreR, fSuf) fName fArgs fRes fBody fSub+ fStr = init $ unlines ["recursive function f()", "end"]+ in fParser fStr `shouldBe'` expected - it "parses functions with a list of arguments" $ do- let fArgs = Just $ AList () u [ varGen "x", varGen "y", varGen "z" ] - let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- let fStr = init $ unlines ["function f(x, y, z)"+ it "parses functions with a list of arguments" $+ let fArgs' = Just $ AList () u [ varGen "x", varGen "y", varGen "z" ]+ expected = puFunction fType fPreSuf fName fArgs' fRes fBody fSub+ fStr = init $ unlines ["function f(x, y, z)" , "end function f" ]- fParser fStr `shouldBe'` expected+ in fParser fStr `shouldBe'` expected - it "parses functions with a result variable" $ do- let fRes = Just $ varGen "i"- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- let fStr = init $ unlines ["function f() result(i)"+ it "parses functions with a result variable" $+ let fRes' = Just $ varGen "i"+ expected = puFunction fType fPreSuf fName fArgs fRes' fBody fSub+ fStr = init $ unlines ["function f() result(i)" , "end function f" ]- fParser fStr `shouldBe'` expected+ in fParser fStr `shouldBe'` expected - it "parses functions with function bodies" $ do+ it "parses functions with function bodies" $ let decrementRHS = ExpBinary () u Subtraction (varGen "i") (intGen 1)- let f1 = StPrint () u starVal (Just $ AList () u [ varGen "i" ]) - let f2 = StExpressionAssign () u (varGen "i") decrementRHS- let fBody = [ BlStatement () u Nothing f1 , BlStatement () u Nothing f2 ]- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- let fStr = init $ unlines ["function f()"- , " print *, i" - , " i = (i - 1)" + f1 = StPrint () u starVal (Just $ AList () u [ varGen "i" ])+ f2 = StExpressionAssign () u (varGen "i") decrementRHS+ fBody' = [ BlStatement () u Nothing f1 , BlStatement () u Nothing f2 ]+ expected = puFunction fType fPreSuf fName fArgs fRes fBody' fSub+ fStr = init $ unlines ["function f()"+ , " print *, i"+ , " i = (i - 1)" , "end function f" ]- fParser fStr `shouldBe'` expected+ in fParser fStr `shouldBe'` expected - it "parses complex functions" $ do- let fType = Just $ TypeSpec () u TypeInteger Nothing- let fArgs = Just $ AList () u [ varGen "x", varGen "y", varGen "z" ] - let fRes = Just $ varGen "i" - let decrementRHS = ExpBinary () u Subtraction (varGen "i") (intGen 1)- let f1 = StPrint () u starVal (Just $ AList () u [ varGen "i" ]) - let f2 = StExpressionAssign () u (varGen "i") decrementRHS- let fBody = [ BlStatement () u Nothing f1 , BlStatement () u Nothing f2 ]- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- let fStr = init $ unlines [ "integer function f(x, y, z) result(i)" - , " print *, i" - , " i = (i - 1)" - , "end function f" ] - fParser fStr `shouldBe'` expected+ it "parses complex functions" $+ let fType' = Just $ TypeSpec () u TypeInteger Nothing+ fArgs' = Just $ AList () u [ varGen "x", varGen "y", varGen "z" ]+ fRes' = Just $ varGen "i"+ decrementRHS = ExpBinary () u Subtraction (varGen "i") (intGen 1)+ f1 = StPrint () u starVal (Just $ AList () u [ varGen "i" ])+ f2 = StExpressionAssign () u (varGen "i") decrementRHS+ fBody' = [ BlStatement () u Nothing f1 , BlStatement () u Nothing f2 ]+ expected = puFunction fType' fPreSuf fName fArgs' fRes' fBody' fSub+ fStr = init $ unlines [ "integer function f(x, y, z) result(i)"+ , " print *, i"+ , " i = (i - 1)"+ , "end function f" ]+ in fParser fStr `shouldBe'` expected describe "Expression" $ do it "parses logial literals with kind" $ do@@ -179,7 +184,7 @@ let stPause = StPause () u Nothing let stStr = "PAUSE" sParser stStr `shouldBe'` stPause- + it "parses pause statements with expression" $ do let stPause = StPause () u (Just (strGen "MESSAGE")) let stStr = "PAUSE \"MESSAGE\""@@ -210,14 +215,14 @@ let stStr = "logical x, y" sParser stStr `shouldBe'` expected - it "parses declaration with initialisation" $ do+ it "parses declaration with initialisation" $ let typeSpec = TypeSpec () u TypeComplex Nothing- let init = ExpValue () u (ValComplex (intGen 24) (realGen 42.0))- let declarators = AList () u- [ DeclVariable () u (varGen "x") Nothing (Just init) ]- let expected = StDeclaration () u typeSpec Nothing declarators- let stStr = "complex :: x = (24, 42.0)"- sParser stStr `shouldBe'` expected+ init' = ExpValue () u (ValComplex (intGen 24) (realGen (42.0::Double)))+ declarators = AList () u+ [ DeclVariable () u (varGen "x") Nothing (Just init') ]+ expected = StDeclaration () u typeSpec Nothing declarators+ stStr = "complex :: x = (24, 42.0)"+ in sParser stStr `shouldBe'` expected it "parses declaration of custom type" $ do let typeSpec = TypeSpec () u (TypeCustom "meinetype") Nothing@@ -280,7 +285,7 @@ sParser "implicit none" `shouldBe'` st it "parses implicit with single" $ do- let typeSpec = TypeSpec () u TypeCharacter Nothing+ let typeSpec = TypeSpec () u (TypeCharacter Nothing Nothing) Nothing let impEls = [ ImpCharacter () u "k" ] let impLists = [ ImpList () u typeSpec (fromList () impEls) ] let st = StImplicit () u (Just $ fromList () impLists)@@ -294,7 +299,7 @@ sParser "implicit logical (x-z)" `shouldBe'` st it "parses implicit statement" $ do- let typeSpec1 = TypeSpec () u TypeCharacter Nothing+ let typeSpec1 = TypeSpec () u (TypeCharacter Nothing Nothing) Nothing let typeSpec2 = TypeSpec () u TypeInteger Nothing let impEls1 = [ ImpCharacter () u "s", ImpCharacter () u "a" ] let impEls2 = [ ImpRange () u "x" "z" ]@@ -379,21 +384,24 @@ describe "Dynamic allocation" $ do it "parses allocate statement" $ do- let controlPair = ControlPair () u (Just "stat") (varGen "a")+ let opt = AOStat () u (varGen "a") let allocs = fromList () [ varGen "x" , ExpDataRef () u (varGen "st") (varGen "part") ]- let s = StAllocate () u allocs (Just controlPair)+ let s = StAllocate () u Nothing allocs (Just (AList () u [opt])) sParser "allocate (x, st % part, STAT = a)" `shouldBe'` s it "parses deallocate statement" $ do+ let opt = AOStat () u (varGen "a") let allocs = fromList () [ let indicies = fromList () [ IxSingle () u Nothing (intGen 20) ] in ExpSubscript () u (varGen "smt") indicies ] let s = StDeallocate () u allocs Nothing+ let s' = StDeallocate () u allocs (Just (AList () u [opt])) sParser "deallocate (smt ( 20 ))" `shouldBe'` s+ sParser "deallocate (smt ( 20 ), stat=a)" `shouldBe'` s' it "parses nullify statement" $ do let s = StNullify () u (fromList () [ varGen "x" ])@@ -414,13 +422,17 @@ describe "Where block" $ do it "parses where construct statement" $- sParser "where (.true.)" `shouldBe'` StWhereConstruct () u valTrue+ sParser "where (.true.)" `shouldBe'` StWhereConstruct () u Nothing valTrue it "parses elsewhere statement" $- sParser "elsewhere" `shouldBe'` StElsewhere () u+ sParser "elsewhere" `shouldBe'` StElsewhere () u Nothing Nothing + it "parses elsewhere statement" $ do+ let exp = ExpBinary () u GT (varGen "a") (varGen "b")+ sParser "elsewhere (a > b)" `shouldBe'` StElsewhere () u Nothing (Just exp)+ it "parses endwhere statement" $- sParser "endwhere" `shouldBe'` StEndWhere () u+ sParser "endwhere" `shouldBe'` StEndWhere () u Nothing describe "If" $ do it "parses if-then statement" $@@ -530,9 +542,18 @@ let st = StWrite () u ciList (Just outList) sParser "write (10, FORMAT = x) (i, j, i = 1, 42, 2)" `shouldBe'` st - it "parses use statement" $ do+ it "parses use statement with renames" $ do let renames = fromList () [ UseRename () u (varGen "sprod") (varGen "prod") , UseRename () u (varGen "a") (varGen "b") ]- let st = StUse () u (varGen "stats_lib") Permissive (Just renames)+ let st = StUse () u (varGen "stats_lib") Nothing Permissive (Just renames) sParser "use stats_lib, sprod => prod, a => b" `shouldBe'` st++ it "parses use statement with only list" $ do+ let onlys = fromList ()+ [ UseID () u (varGen "a")+ , UseRename () u (varGen "b") (varGen "c")+ , UseID () u (ExpValue () u (ValOperator "+"))+ , UseID () u (ExpValue () u ValAssignment) ]+ let st = StUse () u (varGen "stats_lib") Nothing Exclusive (Just onlys)+ sParser "use stats_lib, only: a, b => c, operator(+), assignment(=)" `shouldBe'` st
test/Language/Fortran/Parser/Fortran95Spec.hs view
@@ -1,6 +1,6 @@ module Language.Fortran.Parser.Fortran95Spec (spec) where -import Prelude hiding (GT, EQ, NE)+import Prelude hiding (GT, EQ, exp, pred) import TestUtil import Test.Hspec@@ -14,10 +14,13 @@ import Data.Foldable(forM_) import qualified Data.ByteString.Char8 as B +{-# ANN module "HLint: ignore Reduce duplication" #-}+ eParser :: String -> Expression () eParser sourceCode = case evalParse statementParser parseState of (StExpressionAssign _ _ _ e) -> e+ _ -> error "unhandled evalParse" where paddedSourceCode = B.pack $ " a = " ++ sourceCode parseState = initParseState paddedSourceCode Fortran95 "<unknown>"@@ -47,99 +50,104 @@ describe "Fortran 95 Parser" $ do describe "Function" $ do let puFunction = PUFunction () u- let fType = Nothing- let fOpt = None () u False- let fName = "f"- let fArgs = Nothing- let fRes = Nothing- let fBody = []- let fSub = Nothing+ fType = Nothing+ fSuf = emptySuffixes+ fPreSuf = emptyPrefixSuffix+ fName = "f"+ fArgs = Nothing+ fRes = Nothing+ fBody = []+ fSub = Nothing describe "End" $ do it "parses simple functions ending with \"end function [function name]\"" $ do- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- let fStr = init $ unlines ["function f()"+ let expected = puFunction fType fPreSuf fName fArgs fRes fBody fSub+ fStr = init $ unlines ["function f()" , "end function f" ] fParser fStr `shouldBe'` expected it "parses simple functions ending with \"end\"" $ do- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- let fStr = init $ unlines ["function f()"+ let expected = puFunction fType fPreSuf fName fArgs fRes fBody fSub+ fStr = init $ unlines ["function f()" , "end" ] fParser fStr `shouldBe'` expected it "parses simple functions ending with \"end function\"" $ do- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- let fStr = init $ unlines ["function f()"+ let expected = puFunction fType fPreSuf fName fArgs fRes fBody fSub+ fStr = init $ unlines ["function f()" , "end function" ] fParser fStr `shouldBe'` expected it "parses functions with return type specs" $ do- let fType = Just $ TypeSpec () u TypeInteger Nothing- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- let fStr = init $ unlines ["integer function f()"+ let fType' = Just $ TypeSpec () u TypeInteger Nothing+ expected = puFunction fType' fPreSuf fName fArgs fRes fBody fSub+ fStr = init $ unlines ["integer function f()" , "end function f" ] fParser fStr `shouldBe'` expected describe "parses function options (recursive, pure, elemental)" $ do let options_list = map unzip $ combination- [ ("recursive ", None () u True)- , ("pure ", Pure () u False)- , ("elemental ", Elemental () u) ]+ [ ("recursive ", PfxRecursive () u)+ , ("pure ", PfxPure () u)+ , ("elemental ", PfxElemental () u) ] forM_ options_list (\(strs, opts) -> do- let str = foldr (++) "" strs- let fStr = str ++ (init $ unlines ["function f()", "end"])- let opt = buildPUFunctionOpts opts- let expected = puFunction fType - case opt of- Left _ -> it ("Shouldn't parse: " ++ show fStr ++ ": " ++ show opt) $ evaluate (fParser fStr) `shouldThrow` anyIOException- Right fOpt ->- it ("Should parse: " ++ show fStr ++ ": " ++ show opt) $ do- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- fParser fStr `shouldBe'` expected+ let isElem (PfxElemental {}) = True; isElem _ = False+ isRec (PfxRecursive {}) = True; isRec _ = False+ str = concat strs+ fStr = str ++ init (unlines ["function f()", "end"])+ pfx = fromList' () opts+ --let expected = puFunction fType+ if any isElem opts && any isRec opts+ then+ it ("Shouldn't parse: " ++ show fStr ++ ": " ++ show opts) $+ evaluate (fParser fStr) `shouldThrow` anyIOException+ else+ it ("Should parse: " ++ show fStr ++ ": " ++ show opts) $ do+ let expected' = puFunction fType (pfx, fSuf) fName fArgs fRes fBody fSub+ fParser fStr `shouldBe'` expected' ) it "parses functions with a list of arguments" $ do- let fArgs = Just $ AList () u [ varGen "x", varGen "y", varGen "z" ] - let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- let fStr = init $ unlines ["function f(x, y, z)"+ let fArgs' = Just $ AList () u [ varGen "x", varGen "y", varGen "z" ]+ expected = puFunction fType fPreSuf fName fArgs' fRes fBody fSub+ fStr = init $ unlines ["function f(x, y, z)" , "end function f" ] fParser fStr `shouldBe'` expected it "parses functions with a result variable" $ do- let fRes = Just $ varGen "i"- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- let fStr = init $ unlines ["function f() result(i)"+ let fRes' = Just $ varGen "i"+ expected = puFunction fType fPreSuf fName fArgs fRes' fBody fSub+ fStr = init $ unlines ["function f() result(i)" , "end function f" ] fParser fStr `shouldBe'` expected it "parses functions with function bodies" $ do let decrementRHS = ExpBinary () u Subtraction (varGen "i") (intGen 1)- let f1 = StPrint () u starVal (Just $ AList () u [ varGen "i" ]) - let f2 = StExpressionAssign () u (varGen "i") decrementRHS- let fBody = [ BlStatement () u Nothing f1 , BlStatement () u Nothing f2 ]- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- let fStr = init $ unlines ["function f()"- , " print *, i" - , " i = (i - 1)" + f1 = StPrint () u starVal (Just $ AList () u [ varGen "i" ])+ f2 = StExpressionAssign () u (varGen "i") decrementRHS+ fBody' = [ BlStatement () u Nothing f1 , BlStatement () u Nothing f2 ]+ expected = puFunction fType fPreSuf fName fArgs fRes fBody' fSub+ fStr = init $ unlines ["function f()"+ , " print *, i"+ , " i = (i - 1)" , "end function f" ] fParser fStr `shouldBe'` expected it "parses complex functions" $ do- let fType = Just $ TypeSpec () u TypeInteger Nothing- let fArgs = Just $ AList () u [ varGen "x", varGen "y", varGen "z" ] - let fRes = Just $ varGen "i" - let decrementRHS = ExpBinary () u Subtraction (varGen "i") (intGen 1)- let f1 = StPrint () u starVal (Just $ AList () u [ varGen "i" ]) - let f2 = StExpressionAssign () u (varGen "i") decrementRHS- let fBody = [ BlStatement () u Nothing f1 , BlStatement () u Nothing f2 ]- let expected = puFunction fType fOpt fName fArgs fRes fBody fSub- let fStr = init $ unlines [ "integer function f(x, y, z) result(i)" - , " print *, i" - , " i = (i - 1)" - , "end function f" ] + let fType' = Just $ TypeSpec () u TypeInteger Nothing+ fArgs' = Just $ AList () u [ varGen "x", varGen "y", varGen "z" ]+ fRes' = Just $ varGen "i"+ decrementRHS = ExpBinary () u Subtraction (varGen "i") (intGen 1)+ f1 = StPrint () u starVal (Just $ AList () u [ varGen "i" ])+ f2 = StExpressionAssign () u (varGen "i") decrementRHS+ fBody' = [ BlStatement () u Nothing f1 , BlStatement () u Nothing f2 ]+ expected = puFunction fType' fPreSuf fName fArgs' fRes' fBody' fSub+ fStr = init $ unlines [ "integer function f(x, y, z) result(i)"+ , " print *, i"+ , " i = (i - 1)"+ , "end function f" ] fParser fStr `shouldBe'` expected describe "Expression" $ do@@ -153,7 +161,7 @@ describe "Custom operator" $ do let unOp = UnCustom ".inverse."- let unExp = ExpUnary () u unOp $ intGen 42+ unExp = ExpUnary () u unOp $ intGen 42 it "parses unary custom operator" $ eParser ".inverse. 42" `shouldBe'` unExp@@ -169,24 +177,24 @@ it "parses data ref" $ do let range = fromList () [ IxSingle () u Nothing $ intGen 10 ]- let sub = ExpSubscript () u (varGen "y") range- let innerRefExp = ExpDataRef () u (varGen "x") sub- let exp = ExpDataRef () u innerRefExp (varGen "z")+ sub = ExpSubscript () u (varGen "y") range+ innerRefExp = ExpDataRef () u (varGen "x") sub+ exp = ExpDataRef () u innerRefExp (varGen "z") eParser "x % y(10) % z" `shouldBe'` exp it "parses section subscript" $ do let range = [ IxSingle () u Nothing $ intGen 10 , IxRange () u Nothing (Just $ intGen 1) (Just $ intGen 2) , IxSingle () u Nothing $ varGen "y" ]- let exp = ExpSubscript () u (varGen "x") (fromList () range)+ exp = ExpSubscript () u (varGen "x") (fromList () range) eParser "x (10, : 1 : 2, y)" `shouldBe'` exp describe "Statement" $ do it "data ref assignment" $ do let indicies = AList () u [ IxSingle () u Nothing (intGen 1) ]- let subs = ExpSubscript () u (varGen "x") indicies- let lhs = ExpDataRef () u subs (varGen "y")- let st = StExpressionAssign () u lhs (intGen 1)+ subs = ExpSubscript () u (varGen "x") indicies+ lhs = ExpDataRef () u subs (varGen "y")+ st = StExpressionAssign () u lhs (intGen 1) sParser "x(1) % y = 1" `shouldBe'` st it "doesn't parse assign statements" $ do@@ -196,75 +204,75 @@ it "doesn't parse pause statements" $ do let stStr = "PAUSE" evaluate (sParser stStr) `shouldThrow` anyIOException- + it "doesn't parse pause statements with expression" $ do let stStr = "PAUSE \"MESSAGE\"" evaluate (sParser stStr) `shouldThrow` anyIOException it "parses declaration with attributes" $ do let typeSpec = TypeSpec () u TypeReal Nothing- let attrs = AList () u [ AttrExternal () u+ attrs = AList () u [ AttrExternal () u , AttrIntent () u Out , AttrDimension () u $ AList () u [ DimensionDeclarator () u (Just $ intGen 3) (Just $ intGen 10) ] ]- let declarators = AList () u+ declarators = AList () u [ DeclVariable () u (varGen "x") Nothing Nothing , DeclVariable () u (varGen "y") Nothing Nothing ]- let expected = StDeclaration () u typeSpec (Just attrs) declarators- let stStr = "real, external, intent (out), dimension (3:10) :: x, y"+ expected = StDeclaration () u typeSpec (Just attrs) declarators+ stStr = "real, external, intent (out), dimension (3:10) :: x, y" sParser stStr `shouldBe'` expected it "parses declaration with old syntax" $ do let typeSpec = TypeSpec () u TypeLogical Nothing- let declarators = AList () u+ declarators = AList () u [ DeclVariable () u (varGen "x") Nothing Nothing , DeclVariable () u (varGen "y") Nothing Nothing ]- let expected = StDeclaration () u typeSpec Nothing declarators- let stStr = "logical x, y"+ expected = StDeclaration () u typeSpec Nothing declarators+ stStr = "logical x, y" sParser stStr `shouldBe'` expected it "parses declaration with initialisation" $ do let typeSpec = TypeSpec () u TypeComplex Nothing- let init = ExpValue () u (ValComplex (intGen 24) (realGen 42.0))- let declarators = AList () u- [ DeclVariable () u (varGen "x") Nothing (Just init) ]- let expected = StDeclaration () u typeSpec Nothing declarators- let stStr = "complex :: x = (24, 42.0)"+ init' = ExpValue () u (ValComplex (intGen 24) (realGen (42.0::Double)))+ declarators = AList () u+ [ DeclVariable () u (varGen "x") Nothing (Just init') ]+ expected = StDeclaration () u typeSpec Nothing declarators+ stStr = "complex :: x = (24, 42.0)" sParser stStr `shouldBe'` expected it "parses declaration of custom type" $ do let typeSpec = TypeSpec () u (TypeCustom "meinetype") Nothing- let declarators = AList () u+ declarators = AList () u [ DeclVariable () u (varGen "x") Nothing Nothing ]- let expected = StDeclaration () u typeSpec Nothing declarators- let stStr = "type (MeineType) :: x"+ expected = StDeclaration () u typeSpec Nothing declarators+ stStr = "type (MeineType) :: x" sParser stStr `shouldBe'` expected it "parses declaration type with kind selector" $ do let selector = Selector () u Nothing (Just $ varGen "hello")- let typeSpec = TypeSpec () u TypeInteger (Just selector)- let declarators = AList () u+ typeSpec = TypeSpec () u TypeInteger (Just selector)+ declarators = AList () u [ DeclVariable () u (varGen "x") Nothing Nothing ]- let expected = StDeclaration () u typeSpec Nothing declarators- let stStr = "integer (hello) :: x"+ expected = StDeclaration () u typeSpec Nothing declarators+ stStr = "integer (hello) :: x" sParser stStr `shouldBe'` expected it "parses intent statement" $ do let stStr = "intent (inout) :: a"- let expected = StIntent () u InOut (fromList () [ varGen "a" ])+ expected = StIntent () u InOut (fromList () [ varGen "a" ]) sParser stStr `shouldBe'` expected it "parses optional statement" $ do let stStr = "optional x"- let expected = StOptional () u (fromList () [ varGen "x" ])+ expected = StOptional () u (fromList () [ varGen "x" ]) sParser stStr `shouldBe'` expected it "parses public statement" $ do let stStr = "public :: x"- let expected = StPublic () u (Just $ fromList () [ varGen "x" ])+ expected = StPublic () u (Just $ fromList () [ varGen "x" ]) sParser stStr `shouldBe'` expected it "parses public assignment" $ do@@ -280,47 +288,47 @@ it "parses save statement" $ do let list = [ varGen "hello", varGen "bye" ]- let expected = StSave () u (Just $ fromList () list)- let stStr = "save /hello/, bye"+ expected = StSave () u (Just $ fromList () list)+ stStr = "save /hello/, bye" sParser stStr `shouldBe'` expected it "parses parameter statement" $ do let ass1 = DeclVariable () u (varGen "x") Nothing (Just $ intGen 10)- let ass2 = DeclVariable () u (varGen "y") Nothing (Just $ intGen 20)- let expected = StParameter () u (fromList () [ ass1, ass2 ])+ ass2 = DeclVariable () u (varGen "y") Nothing (Just $ intGen 20)+ expected = StParameter () u (fromList () [ ass1, ass2 ]) sParser "parameter (x = 10, y = 20)" `shouldBe'` expected describe "FORALL blocks" $ do let stride = Just $ ExpBinary () u NE (varGen "i") (intGen 2)- let tripletSpecList = [("i", intGen 1, varGen "n", stride)]+ tripletSpecList = [("i", intGen 1, varGen "n", stride)] it "parses basic FORALL blocks" $ do let stStr = "FORALL (I=1:N, I /= 2)"- let expected = StForall () u Nothing (ForallHeader tripletSpecList Nothing) + expected = StForall () u Nothing (ForallHeader tripletSpecList Nothing) sParser stStr `shouldBe'` expected describe "FORALL statements" $ do let stride = Just $ ExpBinary () u NE (varGen "i") (intGen 2)- let tripletSpecList = [("i", intGen 1, varGen "n", stride)]- let varI = IxSingle () u Nothing (varGen "i")- let expSub1 = ExpSubscript () u (varGen "a") (AList () u [varI, varI])- let expSub2 = ExpSubscript () u (varGen "x") (AList () u [varI])- let eAssign = StExpressionAssign () u expSub1 expSub2+ tripletSpecList = [("i", intGen 1, varGen "n", stride)]+ --let varI = IxSingle () u Nothing (varGen "i")+ --let expSub1 = ExpSubscript () u (varGen "a") (AList () u [varI, varI])+ --let expSub2 = ExpSubscript () u (varGen "x") (AList () u [varI])+ --let eAssign = StExpressionAssign () u expSub1 expSub2 it "parses basic FORALL statements" $ do let stStr = "FORALL (I=1:N, I /= 2)" -- A(I,I) = X(I)"- let expected = StForall () u Nothing (ForallHeader tripletSpecList Nothing)-- eAssign+ expected = StForall () u Nothing (ForallHeader tripletSpecList Nothing)-- eAssign sParser stStr `shouldBe'` expected describe "ENDFORALL statements" $ do it "parses FORALL end statements" $ do let stStr = "ENDFORALL"- let expected = StEndForall () u Nothing+ expected = StEndForall () u Nothing sParser stStr `shouldBe'` expected it "parses FORALL end statements with label" $ do let stStr = "ENDFORALL A"- let expected = StEndForall () u $ Just "a"+ expected = StEndForall () u $ Just "a" sParser stStr `shouldBe'` expected describe "Implicit" $ do@@ -329,46 +337,46 @@ sParser "implicit none" `shouldBe'` st it "parses implicit with single" $ do- 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)+ let typeSpec = TypeSpec () u (TypeCharacter Nothing Nothing) Nothing+ impEls = [ ImpCharacter () u "k" ]+ impLists = [ ImpList () u typeSpec (fromList () impEls) ]+ st = StImplicit () u (Just $ fromList () impLists) sParser "implicit character (k)" `shouldBe'` st it "parses implicit with range" $ do let typeSpec = TypeSpec () u TypeLogical Nothing- let impEls = [ ImpRange () u "x" "z" ]- let impLists = [ ImpList () u typeSpec (fromList () impEls) ]- let st = StImplicit () u (Just $ fromList () impLists)+ impEls = [ ImpRange () u "x" "z" ]+ impLists = [ ImpList () u typeSpec (fromList () impEls) ]+ st = StImplicit () u (Just $ fromList () impLists) sParser "implicit logical (x-z)" `shouldBe'` st it "parses implicit statement" $ do- 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" ]- let impLists = [ ImpList () u typeSpec1 (fromList () impEls1)+ let typeSpec1 = TypeSpec () u (TypeCharacter Nothing Nothing) Nothing+ typeSpec2 = TypeSpec () u TypeInteger Nothing+ impEls1 = [ ImpCharacter () u "s", ImpCharacter () u "a" ]+ impEls2 = [ ImpRange () u "x" "z" ]+ impLists = [ ImpList () u typeSpec1 (fromList () impEls1) , ImpList () u typeSpec2 (fromList () impEls2) ]- let st = StImplicit () u (Just $ fromList () impLists)+ st = StImplicit () u (Just $ fromList () impLists) sParser "implicit character (s, a), integer (x-z)" `shouldBe'` st describe "Data" $ do it "parses vanilla" $ do let nlist = fromList () [ varGen "x", varGen "y" ]- let vlist = fromList () [ intGen 1, intGen 2 ]- let list = [ DataGroup () u nlist vlist ]- let expected = StData () u (fromList () list)- let stStr = "data x,y/1,2/"+ vlist = fromList () [ intGen 1, intGen 2 ]+ list = [ DataGroup () u nlist vlist ]+ expected = StData () u (fromList () list)+ stStr = "data x,y/1,2/" sParser stStr `shouldBe'` expected describe "Delimeter" $ do let [ nlist1, vlist1 ] = map (fromList () . return) [ varGen "x", intGen 1 ]- let [ nlist2, vlist2 ] =+ [ nlist2, vlist2 ] = map (fromList () . return) [ varGen "y", intGen 2 ]- let list = [ DataGroup () u nlist1 vlist1+ list = [ DataGroup () u nlist1 vlist1 , DataGroup () u nlist2 vlist2 ]- let expected = StData () u (fromList () list)+ expected = StData () u (fromList () list) it "parses comma delimited init groups" $ sParser "data x/1/, y/2/" `shouldBe'` expected@@ -379,9 +387,9 @@ describe "Namelist" $ do let groupNames = [ ExpValue () u (ValVariable "something") , ExpValue () u (ValVariable "other") ]- let itemss = [ fromList () [ varGen "a", varGen "b", varGen "c" ]+ itemss = [ fromList () [ varGen "a", varGen "b", varGen "c" ] , fromList () [ varGen "y" ] ]- let st = StNamelist () u $+ st = StNamelist () u $ fromList () [ Namelist () u (head groupNames) (head itemss) , Namelist () u (last groupNames) (last itemss) ] @@ -394,9 +402,9 @@ describe "Common" $ do let commonNames = [ ExpValue () u (ValVariable "something") , ExpValue () u (ValVariable "other") ]- let itemss = [ fromList () [ varGen "a", varGen "b", varGen "c" ]+ itemss = [ fromList () [ varGen "a", varGen "b", varGen "c" ] , fromList () [ varGen "y" ] ]- let st = StCommon () u $ fromList ()+ st = StCommon () u $ fromList () [ CommonGroup () u Nothing (fromList () [ varGen "q" ]) , CommonGroup () u (Just $ head commonNames) (head itemss) , CommonGroup () u (Just $ last commonNames) (last itemss) ]@@ -423,17 +431,17 @@ in ExpSubscript () u (varGen "d") indicies ] ]- let st = StEquivalence () u eqALists+ st = StEquivalence () u eqALists sParser "equivalence (a(1), x), (y, z, d(1:42))" `shouldBe'` st describe "Dynamic allocation" $ do it "parses allocate statement" $ do- let controlPair = ControlPair () u (Just "stat") (varGen "a")- let allocs = fromList ()+ let opt = AOStat () u (varGen "a")+ allocs = fromList () [ varGen "x" , ExpDataRef () u (varGen "st") (varGen "part") ]- let s = StAllocate () u allocs (Just controlPair)+ s = StAllocate () u Nothing allocs (Just (AList () u [opt])) sParser "allocate (x, st % part, STAT = a)" `shouldBe'` s it "parses deallocate statement" $ do@@ -441,7 +449,7 @@ [ let indicies = fromList () [ IxSingle () u Nothing (intGen 20) ] in ExpSubscript () u (varGen "smt") indicies ]- let s = StDeallocate () u allocs Nothing+ s = StDeallocate () u allocs Nothing sParser "deallocate (smt ( 20 ))" `shouldBe'` s it "parses nullify statement" $ do@@ -450,26 +458,30 @@ it "parses pointer assignment" $ do let src = ExpDataRef () u (varGen "x") (varGen "y")- let st = StPointerAssign () u src (varGen "exp")+ st = StPointerAssign () u src (varGen "exp") sParser "x % y => exp" `shouldBe'` st describe "Where" $ do it "parses where statement" $ do let exp = ExpBinary () u Subtraction (varGen "temp") (varGen "r_temp")- let pred = ExpBinary () u GT (varGen "temp") (intGen 100)- let assignment = StExpressionAssign () u (varGen "temp") exp- let st = StWhere () u pred assignment+ pred = ExpBinary () u GT (varGen "temp") (intGen 100)+ assignment = StExpressionAssign () u (varGen "temp") exp+ st = StWhere () u pred assignment sParser "where (temp > 100) temp = temp - r_temp"`shouldBe'` st describe "Where block" $ do it "parses where construct statement" $- sParser "where (.true.)" `shouldBe'` StWhereConstruct () u valTrue+ sParser "where (.true.)" `shouldBe'` StWhereConstruct () u Nothing valTrue it "parses elsewhere statement" $- sParser "elsewhere" `shouldBe'` StElsewhere () u+ sParser "elsewhere" `shouldBe'` StElsewhere () u Nothing Nothing + it "parses elsewhere statement" $ do+ let exp = ExpBinary () u GT (varGen "a") (varGen "b")+ sParser "elsewhere (a > b)" `shouldBe'` StElsewhere () u Nothing (Just exp)+ it "parses endwhere statement" $- sParser "endwhere" `shouldBe'` StEndWhere () u+ sParser "endwhere" `shouldBe'` StEndWhere () u Nothing describe "If" $ do it "parses if-then statement" $@@ -490,7 +502,7 @@ it "parses logical if statement" $ do let assignment = StExpressionAssign () u (varGen "a") (varGen "b")- let stIf = StIfLogical () u valTrue assignment+ stIf = StIfLogical () u valTrue assignment sParser "if (.true.) a = b" `shouldBe'` stIf it "parses arithmetic if statement" $ do@@ -522,14 +534,14 @@ describe "Do" $ do it "parses do statement with label" $ do let assign = StExpressionAssign () u (varGen "i") (intGen 0)- let doSpec = DoSpecification () u assign (intGen 42) Nothing- let st = StDo () u Nothing (Just $ intGen 24) (Just doSpec)+ doSpec = DoSpecification () u assign (intGen 42) Nothing+ st = StDo () u Nothing (Just $ intGen 24) (Just doSpec) sParser "do 24, i = 0, 42" `shouldBe'` st it "parses do statement without label" $ do let assign = StExpressionAssign () u (varGen "i") (intGen 0)- let doSpec = DoSpecification () u assign (intGen 42) Nothing- let st = StDo () u Nothing Nothing (Just doSpec)+ doSpec = DoSpecification () u assign (intGen 42) Nothing+ st = StDo () u Nothing Nothing (Just doSpec) sParser "do i = 0, 42" `shouldBe'` st it "parses infinite do" $ do@@ -551,13 +563,13 @@ it "parses computed goto" $ do let list = fromList () [ intGen 10, intGen 20, intGen 30 ]- let st = StGotoComputed () u list (intGen 20)+ st = StGotoComputed () u list (intGen 20) sParser "goto (10, 20, 30) 20" `shouldBe'` st - it "doesn't parse assigned goto" $ do+ it "doesn't parse assigned goto" $ evaluate (sParser "goto i, (10, 20, 30)") `shouldThrow` anyIOException - it "doesn't parse label assignment" $ do+ it "doesn't parse label assignment" $ evaluate (sParser "assign 20 to l") `shouldThrow` anyIOException describe "IO" $ do@@ -567,18 +579,44 @@ it "parses write with implied do" $ do let cp1 = ControlPair () u Nothing (intGen 10)- let cp2 = ControlPair () u (Just "format") (varGen "x")- let ciList = fromList () [ cp1, cp2 ]- let assign = StExpressionAssign () u (varGen "i") (intGen 1)- let doSpec = DoSpecification () u assign (intGen 42) (Just $ intGen 2)- let alist = fromList () [ varGen "i", varGen "j" ]- let outList = fromList () [ ExpImpliedDo () u alist doSpec ]- let st = StWrite () u ciList (Just outList)+ cp2 = ControlPair () u (Just "format") (varGen "x")+ ciList = fromList () [ cp1, cp2 ]+ assign = StExpressionAssign () u (varGen "i") (intGen 1)+ doSpec = DoSpecification () u assign (intGen 42) (Just $ intGen 2)+ alist = fromList () [ varGen "i", varGen "j" ]+ outList = fromList () [ ExpImpliedDo () u alist doSpec ]+ st = StWrite () u ciList (Just outList) sParser "write (10, FORMAT = x) (i, j, i = 1, 42, 2)" `shouldBe'` st it "parses use statement" $ do let renames = fromList () [ UseRename () u (varGen "sprod") (varGen "prod") , UseRename () u (varGen "a") (varGen "b") ]- let st = StUse () u (varGen "stats_lib") Permissive (Just renames)+ let st = StUse () u (varGen "stats_lib") Nothing Permissive (Just renames) sParser "use stats_lib, sprod => prod, a => b" `shouldBe'` st++ it "parses value decl" $ do+ let decls = [DeclVariable () u (varGen "a") Nothing Nothing, DeclVariable () u (varGen "b") Nothing Nothing]+ let st = StValue () u (AList () u decls)+ sParser "value a, b" `shouldBe'` st+ sParser "value :: a, b" `shouldBe'` st++ it "parses value attribute" $ do+ let decls = [DeclVariable () u (varGen "a") Nothing Nothing, DeclVariable () u (varGen "b") Nothing Nothing]+ let ty = TypeSpec () u TypeInteger Nothing+ let attrs = [AttrValue () u]+ let st = StDeclaration () u ty (Just (AList () u attrs)) (AList () u decls)+ sParser "integer, value :: a, b" `shouldBe'` st++ it "parses volatile decl" $ do+ let decls = [DeclVariable () u (varGen "a") Nothing Nothing, DeclVariable () u (varGen "b") Nothing Nothing]+ let st = StVolatile () u (AList () u decls)+ sParser "volatile a, b" `shouldBe'` st+ sParser "volatile :: a, b" `shouldBe'` st++ it "parses volatile attribute" $ do+ let decls = [DeclVariable () u (varGen "a") Nothing Nothing, DeclVariable () u (varGen "b") Nothing Nothing]+ let ty = TypeSpec () u TypeInteger Nothing+ let attrs = [AttrVolatile () u]+ let st = StDeclaration () u ty (Just (AList () u attrs)) (AList () u decls)+ sParser "integer, volatile :: a, b" `shouldBe'` st
test/Language/Fortran/Parser/UtilsSpec.hs view
@@ -1,24 +1,23 @@ module Language.Fortran.Parser.UtilsSpec where import Test.Hspec-import TestUtil import Language.Fortran.Parser.Utils spec :: Spec spec = describe "Fortran Parser Utils" $ do- describe "readReal" $ do+ describe "readReal" $ it "tests" $ do- readReal "+12" `shouldBe` Just (12)+ readReal "+12" `shouldBe` Just 12 readReal "-1.2" `shouldBe` Just (-1.2)- readReal "1.2d3" `shouldBe` Just (1200)- readReal "1.e2" `shouldBe` Just (100)- readReal "1.e-2" `shouldBe` Just (0.01)- readReal ".12" `shouldBe` Just (0.12)+ readReal "1.2d3" `shouldBe` Just 1200+ readReal "1.e2" `shouldBe` Just 100+ readReal "1.e-2" `shouldBe` Just 0.01+ readReal ".12" `shouldBe` Just 0.12 readReal "-.12" `shouldBe` Just (-0.12)- readReal "1_f" `shouldBe` Just (1)- describe "readInteger" $ do+ readReal "1_f" `shouldBe` Just 1+ describe "readInteger" $ it "tests" $ do readInteger "b'101'" `shouldBe` Just 5 readInteger "o'22'" `shouldBe` Just 18
test/Language/Fortran/ParserMonadSpec.hs view
@@ -1,13 +1,12 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# OPTIONS_GHC -Wno-orphans #-} module Language.Fortran.ParserMonadSpec where import Test.Hspec import Language.Fortran.ParserMonad-import Control.Monad.State.Lazy- import Language.Fortran.Util.Position vanillaParseState :: ParseState String@@ -28,7 +27,7 @@ data SomeInput = SomeInput { p :: Position } initPos :: Position-initPos = Position 5 1 2+initPos = Position 5 1 2 "" Nothing initSomeInput :: SomeInput initSomeInput = SomeInput { p = initPos }@@ -52,16 +51,16 @@ spec = describe "ParserMonad" $ do describe "Parse" $ do- it "should give out correct version" $ do+ it "should give out correct version" $ evalParse getVersion vanillaParseState `shouldBe` Fortran66 - it "satisfies read after write equals to what is written" $ do+ it "satisfies read after write equals to what is written" $ let ai = evalParse (putAlex "l'enfer" >> getAlex) vanillaParseState in ai `shouldBe` "l'enfer" describe "Obtaining locations" $ do- it "getPosition returns correct location" $ do- let _expPosition = Position 6 2 3+ it "getPosition returns correct location" $+ let _expPosition = Position 6 2 3 "some.f" Nothing _exampleM = do _ai <- getAlex putAlex $ _ai { p = _expPosition }@@ -69,8 +68,8 @@ _loc = evalParse _exampleM vanillaSomeInput in _loc `shouldBe` _expPosition - it "getSrcSpan return correct location span" $ do- let _loc2 = Position 6 2 3+ it "getSrcSpan return correct location span" $+ let _loc2 = Position 6 2 3 "some.f" Nothing _exampleM = do _ai <- getAlex _loc1 <- getPosition@@ -81,13 +80,13 @@ _span `shouldBe` _expectation describe "Lex" $ do- it "reads the state correctly" $ do+ it "reads the state correctly" $ evalParse getAlex vanillaParseState `shouldBe` "" - it "overrides the state correctly" $ do+ it "overrides the state correctly" $ let ai = evalParse (putAlex "c'est" >> getAlex) vanillaParseState in ai `shouldBe` "c'est" - it "mixes operations correctly" $ do- let ai = evalParse (putAlex "hello" >> getAlex >>= \s -> (putAlex $ take 4 s) >> getAlex) vanillaParseState in+ it "mixes operations correctly" $+ let ai = evalParse (putAlex "hello" >> getAlex >>= \s -> putAlex (take 4 s) >> getAlex) vanillaParseState in ai `shouldBe` "hell"
test/Language/Fortran/PrettyPrintSpec.hs view
@@ -4,27 +4,20 @@ module Language.Fortran.PrettyPrintSpec where +import Prelude hiding (mod) import qualified Data.ByteString.Char8 as B import Data.Text.Encoding (encodeUtf8, decodeUtf8With) import Data.Text.Encoding.Error (replace) import Data.Data-import Data.Foldable import Data.Generics.Uniplate.Operations import Data.Maybe (catMaybes)---import Data.DeriveTH -import Control.Monad (void)- import Language.Fortran.AST as LFA import Language.Fortran.ParserMonad import Language.Fortran.PrettyPrint-import Language.Fortran.Parser.Any-import Language.Fortran.Util.Position-import Language.Fortran.Util.SecondParameter import System.FilePath-import System.Directory import Text.PrettyPrint import Text.PrettyPrint.GenericPretty @@ -102,11 +95,17 @@ let ed = FIHollerith () u (ValHollerith "hello darling") pprint Fortran77 ed Nothing `shouldBe` "13hhello darling" + describe "Flush statement" $+ it "prints flush statement" $ do+ let f = StFlush () u (AList () u [ FSUnit () u (intGen 1), FSIOStat () u (varGen "x")+ , FSIOMsg () u (varGen "y"), FSErr () u (varGen "z") ])+ pprint Fortran2003 f Nothing `shouldBe` "flush (unit=1, iostat=x, iomsg=y, err=z)"+ describe "Statement" $ do describe "Declaration" $ do it "prints 90 style with attributes" $ do let sel = Selector () u (Just $ intGen 3) Nothing- let typeSpec = TypeSpec () u TypeCharacter (Just sel)+ let typeSpec = TypeSpec () u (TypeCharacter Nothing Nothing) (Just sel) let attrs = [ AttrIntent () u In , AttrPointer () u ] let declList = [ DeclVariable () u (varGen "x") Nothing (Just $ intGen 42)@@ -114,7 +113,7 @@ let st = StDeclaration () u typeSpec (Just $ AList () u attrs) (AList () u declList)- let expect = "character (len=3), intent(in), pointer :: x = 42, y*3"+ let expect = "character(len=3), intent(in), pointer :: x = 42, y*3" pprint Fortran90 st Nothing `shouldBe` expect it "prints 77 style" $ do@@ -244,11 +243,17 @@ pprint Fortran90 st Nothing `shouldBe` "print *, 42" describe "Allocation" $- describe "Allocate" $+ describe "Allocate" $ do it "prints allocate statement" $ do- let pair = ControlPair () u (Just "stat") (varGen "s")- let st = StAllocate () u (AList () u [ varGen "x" ]) (Just pair)+ let stat = AOStat () u (varGen "s")+ let st = StAllocate () u Nothing (AList () u [ varGen "x" ]) (Just (AList () u [stat])) pprint Fortran90 st Nothing `shouldBe` "allocate (x, stat=s)"+ 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 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)" describe "Where" $ it "prints statement" $ do@@ -256,12 +261,22 @@ let stWhere = StWhere () u valTrue stAssign pprint Fortran90 stWhere Nothing `shouldBe` "where (.true.) x = 42" - describe "Use" $- it "prints exlusive use statement" $ do+ describe "Use" $ do+ it "prints exclusive use statement" $ do let aRenames = AList () u [ UseRename () u (varGen "x") (varGen "y") ]- let st = StUse () u (varGen "my_mod") Exclusive (Just aRenames)+ let st = StUse () u (varGen "my_mod") Nothing Exclusive (Just aRenames) pprint Fortran90 st Nothing `shouldBe` "use my_mod, only: x => y" + it "prints intrinsic use statement" $ do+ let aRenames = AList () u [ UseRename () u (varGen "x") (varGen "y") ]+ let st = StUse () u (varGen "my_mod") (Just ModIntrinsic) Exclusive (Just aRenames)+ pprint Fortran2003 st Nothing `shouldBe` "use, intrinsic :: my_mod, only: x => y"++ it "prints non_intrinsic use statement" $ do+ let aRenames = AList () u [ UseRename () u (varGen "x") (varGen "y") ]+ let st = StUse () u (varGen "my_mod") (Just ModNonIntrinsic) Exclusive (Just aRenames)+ pprint Fortran2003 st Nothing `shouldBe` "use, non_intrinsic :: my_mod, only: x => y"+ let decrementRHS = ExpBinary () u Subtraction (varGen "i") (intGen 1) let st1 = StPrint () u starVal (Just $ AList () u [ varGen "i" ]) let st2 = StExpressionAssign () u (varGen "i") decrementRHS@@ -417,7 +432,7 @@ pprint Fortran90 mod (Just 0) `shouldBe` text expect it "prints module with sub programs" $ do- let sub = PUSubroutine () u (None () u False) "sub" Nothing body Nothing+ let sub = PUSubroutine () u emptyPrefixSuffix "sub" Nothing body Nothing let mod = PUModule () u "my_mod" body (Just [ sub ]) let expect = unlines [ " module my_mod" , " print *, i"@@ -435,7 +450,7 @@ describe "Subroutine" $ do it "prints recursive subroutine with args without sub programs" $ do let args = AList () u [ varGen "x", varGen "y", varGen "z" ]- let sub = PUSubroutine () u (None () u True) "sub" (Just args) body Nothing+ let sub = PUSubroutine () u (Just (AList () u [PfxRecursive () u]), emptySuffixes) "sub" (Just args) body Nothing let expect = unlines [ "recursive subroutine sub(x, y, z)" , "print *, i" , "i = (i - 1)"@@ -443,7 +458,7 @@ pprint Fortran90 sub Nothing `shouldBe` text expect it "prints 66 style subroutine without args" $ do- let mod = PUSubroutine () u (None () u False) "sub" Nothing body Nothing+ let mod = PUSubroutine () u emptyPrefixSuffix "sub" Nothing body Nothing let expect = unlines [ " subroutine sub" , " print *, i" , " i = (i - 1)"@@ -456,7 +471,7 @@ it "prints function with args with result without sub programs" $ do let args = AList () u [ varGen "x", varGen "y", varGen "z" ] let res = Just $ varGen "i"- let fun = PUFunction () u tSpec (None () u False) "f" (Just args) res body Nothing+ let fun = PUFunction () u tSpec emptyPrefixSuffix "f" (Just args) res body Nothing let expect = unlines [ " integer function f(x, y, z) result(i)" , " print *, i" , " i = (i - 1)"@@ -465,8 +480,8 @@ describe "Program file" $ it "prints simple program file" $ do- let body = [ BlStatement () u Nothing (StContinue () u) ]- let pu = PUModule () u "my_mod" body Nothing+ let body' = [ BlStatement () u Nothing (StContinue () u) ]+ let pu = PUModule () u "my_mod" body' Nothing let com = PUComment () u (Comment "hello!") let pf = ProgramFile mi77 [com, pu, com, pu, com, com] let expect = unlines [ "!hello!"
test/Language/Fortran/Transformation/Disambiguation/FunctionSpec.hs view
@@ -4,11 +4,8 @@ import TestUtil import Language.Fortran.Analysis-import Language.Fortran.Analysis.Renaming-import Language.Fortran.Analysis.Types import Language.Fortran.AST import Language.Fortran.Transformer-import Language.Fortran.Transformation.TransformMonad disambiguateFunction :: ProgramFile () -> ProgramFile () disambiguateFunction = transform [ DisambiguateIntrinsic, DisambiguateFunction ]@@ -30,18 +27,37 @@ let pf = disambiguateFunction $ resetSrcSpan ex3 pf `shouldBe'` expectedEx3 + describe "Function call / Variable disambiguation" $+ it "disambiguates function calls in example 4" $ do+ let pf = disambiguateFunction $ resetSrcSpan ex4+ pf `shouldBe'` expectedEx4++ describe "Implicit Function call / Variable disambiguation" $+ it "disambiguates function calls in example 5" $ do+ let pf = disambiguateFunction $ resetSrcSpan ex5+ pf `shouldBe'` expectedEx5++ describe "Implicit array declaration with dimension disambiguation" $+ it "Should not disambiguation to a function call in example 6" $ do+ let pf = disambiguateFunction $ resetSrcSpan ex6+ pf `shouldBe'` expectedEx6+ {- - program Main-- integer a, b(1), c+- integer a, b(1), c, e - dimension a(1) - a(1) = 1 - b(1) = 1 - c(x) = 1 - d(x) = 1+- e() = 1 - end -}+ex1 :: ProgramFile () ex1 = ProgramFile mi77 [ ex1pu1 ]+ex1pu1 :: ProgramUnit () ex1pu1 = PUMain () u (Just "main") ex1pu1bs Nothing+ex1pu1bs :: [Block ()] ex1pu1bs = [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ DeclVariable () u (varGen "a") Nothing Nothing@@ -56,10 +72,15 @@ , BlStatement () u Nothing (StExpressionAssign () u (ExpSubscript () u (varGen "c") (AList () u [ IxSingle () u Nothing $ varGen "x" ])) (intGen 1)) , BlStatement () u Nothing (StExpressionAssign () u- (ExpSubscript () u (varGen "d") (AList () u [ IxSingle () u Nothing $ varGen "x" ])) (intGen 1)) ]+ (ExpSubscript () u (varGen "d") (AList () u [ IxSingle () u Nothing $ varGen "x" ])) (intGen 1))+ , BlStatement () u Nothing (StExpressionAssign () u+ (ExpFunctionCall () u (varGen "e") Nothing) (intGen 1)) ] +expectedEx1 :: ProgramFile () expectedEx1 = ProgramFile mi77 [ expectedEx1pu1 ]+expectedEx1pu1 :: ProgramUnit () expectedEx1pu1 = PUMain () u (Just "main") expectedEx1pu1bs Nothing+expectedEx1pu1bs :: [Block ()] expectedEx1pu1bs = [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ DeclVariable () u (varGen "a") Nothing Nothing@@ -74,7 +95,9 @@ , BlStatement () u Nothing (StFunction () u (ExpValue () u $ ValVariable "c") (AList () u [ varGen "x" ]) (intGen 1)) , BlStatement () u Nothing (StFunction () u- (ExpValue () u $ ValVariable "d") (AList () u [ varGen "x" ]) (intGen 1)) ]+ (ExpValue () u $ ValVariable "d") (AList () u [ varGen "x" ]) (intGen 1))+ , BlStatement () u Nothing (StFunction () u+ (ExpValue () u $ ValVariable "e") (AList () u []) (intGen 1)) ] {- - program@@ -88,9 +111,13 @@ - function y(i,j) - end -}+ex2 :: ProgramFile () ex2 = ProgramFile mi77 [ ex2pu1, ex2pu2 ]+ex2pu1 :: ProgramUnit () ex2pu1 = PUMain () u Nothing ex2pu1bs Nothing-ex2pu2 = PUFunction () u Nothing (None () u False) "y" (Just $ AList () u [ varGen "i", varGen "j" ]) Nothing [ ] Nothing+ex2pu2 :: ProgramUnit ()+ex2pu2 = PUFunction () u Nothing emptyPrefixSuffix "y" (Just $ AList () u [ varGen "i", varGen "j" ]) Nothing [ ] Nothing+ex2pu1bs :: [Block ()] ex2pu1bs = [ BlStatement () u Nothing (StFunction () u@@ -105,8 +132,11 @@ (varGen "f") (AList () u [ ixSinGen 1 ])))) ] +expectedEx2 :: ProgramFile () expectedEx2 = ProgramFile mi77 [ expectedEx2pu1, ex2pu2 ]+expectedEx2pu1 :: ProgramUnit () expectedEx2pu1 = PUMain () u Nothing expectedEx2pu1bs Nothing+expectedEx2pu1bs :: [Block ()] expectedEx2pu1bs = [ BlStatement () u Nothing (StFunction () u@@ -122,9 +152,13 @@ (Just $ AList () u [ Argument () u Nothing (intGen 1) ])))) ] +ex3 :: ProgramFile () ex3 = ProgramFile mi77 [ ex3pu1, ex3pu2 ]+ex3pu1 :: ProgramUnit () ex3pu1 = PUMain () u Nothing ex3pu1bs Nothing-ex3pu2 = PUFunction () u Nothing (None () u False) "y" (Just $ AList () u [ varGen "i", varGen "j" ]) Nothing [ ] Nothing+ex3pu2 :: ProgramUnit ()+ex3pu2 = PUFunction () u Nothing emptyPrefixSuffix "y" (Just $ AList () u [ varGen "i", varGen "j" ]) Nothing [ ] Nothing+ex3pu1bs :: [Block ()] ex3pu1bs = [ BlStatement () u Nothing (StFunction () u@@ -135,10 +169,13 @@ (StExpressionAssign () u (varGen "i") (ExpSubscript () u (varGen "abs") (AList () u [- (IxSingle () u Nothing (ExpSubscript () u (varGen "f") (AList () u [ ixSinGen 1 ])))]))) ]+ IxSingle () u Nothing (ExpSubscript () u (varGen "f") (AList () u [ ixSinGen 1 ]))]))) ] +expectedEx3 :: ProgramFile () expectedEx3 = ProgramFile mi77 [ expectedEx3pu1, ex3pu2 ]+expectedEx3pu1 :: ProgramUnit () expectedEx3pu1 = PUMain () u Nothing expectedEx3pu1bs Nothing+expectedEx3pu1bs :: [Block ()] expectedEx3pu1bs = [ BlStatement () u Nothing (StFunction () u@@ -151,6 +188,110 @@ (Just $ AList () u [ Argument () u Nothing (ExpFunctionCall () u (ExpValue () u $ ValVariable "f") (Just $ AList () u [ Argument () u Nothing (intGen 1) ])) ]))) ]+++{-+- program Main+- integer a, f+- a = f(1)+- end+-}++ex4 :: ProgramFile ()+ex4 = ProgramFile mi77 [ ex4pu1 ]+ex4pu1 :: ProgramUnit ()+ex4pu1 = PUMain () u (Just "main") ex4pu1bs Nothing+ex4pu1bs :: [Block ()]+ex4pu1bs =+ [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u+ [ DeclVariable () u (varGen "a") Nothing Nothing+ , DeclVariable () u (varGen "f") Nothing Nothing ]))+ , BlStatement () u Nothing+ (StExpressionAssign () u (varGen "a") (ExpSubscript () u (varGen "f") (AList () u [ ixSinGen 1 ]))) ]++expectedEx4 :: ProgramFile ()+expectedEx4 = ProgramFile mi77 [ expectedEx4pu1 ]+expectedEx4pu1 :: ProgramUnit ()+expectedEx4pu1 = PUMain () u (Just "main") expectedEx4pu1bs Nothing++expectedEx4pu1bs :: [Block ()]+expectedEx4pu1bs =+ [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u+ [ DeclVariable () u (varGen "a") Nothing Nothing+ , DeclVariable () u (varGen "f") Nothing Nothing ]))+ , BlStatement () u Nothing+ (StExpressionAssign () u (varGen "a")+ (ExpFunctionCall () u (ExpValue () u $ ValVariable "f")+ (Just $ AList () u [ Argument () u Nothing (intGen 1) ] ))) ]++{-+- program Main+- integer a+- a = f(1)+- end+-}++ex5 :: ProgramFile ()+ex5 = ProgramFile mi77 [ ex5pu1 ]+ex5pu1 :: ProgramUnit ()+ex5pu1 = PUMain () u (Just "main") ex5pu1bs Nothing+ex5pu1bs :: [Block ()]+ex5pu1bs =+ [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u+ [ DeclVariable () u (varGen "a") Nothing Nothing+ ]))+ , BlStatement () u Nothing+ (StExpressionAssign () u (varGen "a") (ExpSubscript () u (varGen "f") (AList () u [ ixSinGen 1 ]))) ]++expectedEx5 :: ProgramFile ()+expectedEx5 = ProgramFile mi77 [ expectedEx5pu1 ]+expectedEx5pu1 :: ProgramUnit ()+expectedEx5pu1 = PUMain () u (Just "main") expectedEx5pu1bs Nothing++expectedEx5pu1bs :: [Block ()]+expectedEx5pu1bs =+ [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u+ [ DeclVariable () u (varGen "a") Nothing Nothing ]))+ , BlStatement () u Nothing+ (StExpressionAssign () u (varGen "a")+ (ExpFunctionCall () u (ExpValue () u $ ValVariable "f")+ (Just $ AList () u [ Argument () u Nothing (intGen 1) ] ))) ]++{-+- program Main+- integer a+- dimension f(10)+- a = f(1)+- end+-}++ex6 :: ProgramFile ()+ex6 = ProgramFile mi77 [ ex6pu1 ]+ex6pu1 :: ProgramUnit ()+ex6pu1 = PUMain () u (Just "main") ex6pu1bs Nothing+ex6pu1bs :: [Block ()]+ex6pu1bs =+ [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u+ [ DeclVariable () u (varGen "a") Nothing Nothing+ ]))+ , BlStatement () u Nothing (StDimension () u (AList () u+ [ DeclArray () u (varGen "f") (AList () u [ DimensionDeclarator () u Nothing (Just $ intGen 10 ) ]) Nothing Nothing ]))+ , BlStatement () u Nothing+ (StExpressionAssign () u (varGen "a") (ExpSubscript () u (varGen "f") (AList () u [ ixSinGen 1 ]))) ]++expectedEx6 :: ProgramFile ()+expectedEx6 = ProgramFile mi77 [ expectedEx6pu1 ]+expectedEx6pu1 :: ProgramUnit ()+expectedEx6pu1 = PUMain () u (Just "main") expectedEx6pu1bs Nothing++expectedEx6pu1bs :: [Block ()]+expectedEx6pu1bs =+ [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u+ [ DeclVariable () u (varGen "a") Nothing Nothing ]))+ , BlStatement () u Nothing (StDimension () u (AList () u+ [ DeclArray () u (varGen "f") (AList () u [ DimensionDeclarator () u Nothing (Just $ intGen 10 ) ]) Nothing Nothing ]))+ , BlStatement () u Nothing+ (StExpressionAssign () u (varGen "a") (ExpSubscript () u (varGen "f") (AList () u [ ixSinGen 1 ]))) ] -- Local variables: -- mode: haskell
test/Language/Fortran/Transformation/GroupingSpec.hs view
@@ -1,27 +1,36 @@+{-# OPTIONS_GHC -Wno-orphans #-} module Language.Fortran.Transformation.GroupingSpec where import Test.Hspec hiding (Selector) import TestUtil import Control.Exception (evaluate)-import Control.DeepSeq (force, ($!!), NFData)+import Control.DeepSeq (force, NFData)+import Data.ByteString.Char8 (ByteString, pack) import Language.Fortran.Transformer import Language.Fortran.AST import Language.Fortran.Util.Position import Language.Fortran.ParserMonad+import Language.Fortran.Parser.Fortran95+import Language.Fortran.Parser.Fortran77 +groupIf :: ProgramFile () -> ProgramFile () groupIf = transform [ GroupIf ]+groupDo :: ProgramFile () -> ProgramFile () groupDo = transform [ GroupLabeledDo ]+groupForall :: ProgramFile () -> ProgramFile () groupForall = transform [ GroupForall ] instance NFData MetaInfo instance NFData FortranVersion instance NFData SrcSpan instance NFData Position+instance NFData CharacterLen instance NFData BaseType instance NFData UnaryOp instance NFData BinaryOp instance NFData Only+instance NFData ModuleNature instance NFData Intent instance (NFData a, NFData (t a)) => NFData (AList t a) instance NFData a => NFData (ProgramFile a)@@ -33,6 +42,8 @@ instance NFData a => NFData (Value a) instance NFData a => NFData (Comment a) instance NFData a => NFData (Statement a)+instance NFData a => NFData (ProcDecl a)+instance NFData a => NFData (ProcInterface a) instance NFData a => NFData (DoSpecification a) instance NFData a => NFData (Selector a) instance NFData a => NFData (ForallHeader a)@@ -41,14 +52,17 @@ instance NFData a => NFData (Attribute a) instance NFData a => NFData (CommonGroup a) instance NFData a => NFData (ControlPair a)+instance NFData a => NFData (AllocOpt a) instance NFData a => NFData (DataGroup a) instance NFData a => NFData (DimensionDeclarator a) instance NFData a => NFData (Declarator a) instance NFData a => NFData (FormatItem a)+instance NFData a => NFData (FlushSpec a) instance NFData a => NFData (ImpElement a) instance NFData a => NFData (ImpList a) instance NFData a => NFData (Namelist a)-instance NFData a => NFData (PUFunctionOpt a)+instance NFData a => NFData (Prefix a)+instance NFData a => NFData (Suffix a) instance NFData a => NFData (StructureItem a) instance NFData a => NFData (UnionMap a) @@ -57,9 +71,9 @@ let name = Just "name" let endName = Just "endName" describe "Block FORALL statements" $ do- it "groups unlabelled FORALL blocks" $ do+ it "groups unlabelled FORALL blocks" $ groupForall (exampleForall Nothing Nothing) `shouldBe'` expectedForall Nothing- it "groups unlabelled FORALL blocks" $ do+ it "groups unlabelled FORALL blocks" $ groupForall (exampleForall name name) `shouldBe'` expectedForall name it "groups unlabelled FORALL blocks" $ do let lhs = (evaluate . force) (groupForall $ exampleForall name endName)@@ -78,28 +92,51 @@ it "do group example2 with common end-point" $ groupDo example2do `shouldBe` expectedExample2do + describe "Block SrcSpan's" $ do+ it "Spans all a BlIf" $+ ifSpan `shouldBe` expectedIfSpan+ it "spans all a BlDo" $+ doSpan `shouldBe` expectedDoSpan+ it "spans all a BlDoWhile" $+ doWhileSpan `shouldBe` expectedDoWhileSpan++ describe "Inner block SrcSpan's" $ do+ it "Spans the inner blocks of an if including comments - 77" $+ ifInnerBlockSpan getSingleParsedBlock77 `shouldBe` expectedIfInnerBlockSpan+ it "Spans the inner blocks of an if including comments - 77 legacy" $+ ifInnerBlockSpan getSingleParsedBlock77Legacy `shouldBe` expectedIfInnerBlockSpan++buildExampleProgram :: Name -> [Block ()] -> ProgramFile () buildExampleProgram name blocks = ProgramFile mi77 [ PUMain () u (Just name) blocks Nothing ] +exampleComment :: Block () exampleComment = BlComment () u $ Comment "comment"+exampleHeader :: ForallHeader a exampleHeader = ForallHeader [] Nothing-exampleForall name nameEnd = buildExampleProgram "forall" $+exampleForall :: Maybe String -> Maybe String -> ProgramFile ()+exampleForall name nameEnd = buildExampleProgram "forall" [ BlStatement () u Nothing $ StForall () u name exampleHeader , exampleComment , BlStatement () u Nothing $ StEndForall () u nameEnd ] -expectedForall name = buildExampleProgram "forall" $+expectedForall :: Maybe String -> ProgramFile ()+expectedForall name = buildExampleProgram "forall" [BlForall () u Nothing name exampleHeader [exampleComment] Nothing] -- if (.true.) then -- end if+example1 :: ProgramFile () example1 = ProgramFile mi77 [ PUMain () u (Just "example1") example1Blocks Nothing ]+example1Blocks :: [Block ()] example1Blocks = [ BlStatement () u Nothing (StIfThen () u Nothing valTrue) , BlStatement () u Nothing (StEndif () u Nothing) ] +expectedExample1 :: ProgramFile () expectedExample1 = ProgramFile mi77 [ PUMain () u (Just "example1") expectedExample1Blocks Nothing ]+expectedExample1Blocks :: [Block ()] expectedExample1Blocks = [ BlIf () u Nothing Nothing [ Just valTrue ] [ [ ] ] Nothing ] -- if (.true.) then@@ -111,7 +148,9 @@ -- if (.false.) then -- endif -- end if+example2 :: ProgramFile () example2 = ProgramFile mi77 [ PUMain () u (Just "example2") example2Blocks Nothing ]+example2Blocks :: [Block ()] example2Blocks = [ BlStatement () u Nothing (StIfThen () u Nothing valTrue) , BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ DeclVariable () u (varGen "x") Nothing Nothing ]))@@ -123,40 +162,53 @@ , BlStatement () u Nothing (StEndif () u Nothing) , BlStatement () u Nothing (StEndif () u Nothing) ] +expectedExample2 :: ProgramFile () expectedExample2 = ProgramFile mi77 [ PUMain () u (Just "example2") expectedExample2Blocks Nothing ]+expectedExample2Blocks :: [Block ()] expectedExample2Blocks = [ BlIf () u Nothing Nothing [ Just valTrue, Just valTrue, Nothing ] blockGroups Nothing ]+blockGroups :: [[Block ()]] blockGroups = [ [ BlStatement () u Nothing (StDeclaration () u (TypeSpec () u TypeInteger Nothing) Nothing (AList () u [ DeclVariable () u (varGen "x") Nothing Nothing ])) , innerIf ] , [ ] , [ innerIf ] ]+innerIf :: Block () innerIf = BlIf () u Nothing Nothing [ Just valFalse ] [ [ ] ] Nothing -- do 10 i = 0, 10 -- 10 continue+label10 :: Maybe (Expression ()) label10 = Just (ExpValue () u (ValInteger "10"))+example1do :: ProgramFile () example1do = ProgramFile mi77 [ PUMain () u (Just "example1") example1doblocks Nothing ]+example1doblocks :: [Block ()] example1doblocks = [ BlStatement () u Nothing (StDo () u Nothing label10 dospec) , BlStatement () u label10 (StContinue () u) ]+dospec :: Maybe (DoSpecification ()) dospec = Just (DoSpecification () u (StExpressionAssign () u (ExpValue () u (ValVariable "i")) (ExpValue () u (ValInteger "0"))) (ExpValue () u (ValInteger "10")) Nothing) +expectedExample1do :: ProgramFile () expectedExample1do = ProgramFile mi77 [ PUMain () u (Just "example1") expectedExample1doBlocks Nothing ]+expectedExample1doBlocks :: [Block ()] expectedExample1doBlocks = [ BlDo () u Nothing Nothing label10 dospec- [BlStatement () u label10 (StContinue () u)] label10 ]+ [ ] label10 ] +label20 :: Maybe (Expression ()) label20 = Just (ExpValue () u (ValInteger "20")) -- do 10 i = 0, 10 -- do 10 i = 0, 10 -- 10 continue -- do 20 i = 0, 10 -- 20 continue+example2do :: ProgramFile () example2do = ProgramFile mi77 [ PUMain () u (Just "example2") example2doblocks Nothing ]+example2doblocks :: [Block ()] example2doblocks = [ BlStatement () u Nothing (StDo () u Nothing label10 dospec) , BlStatement () u Nothing (StDo () u Nothing label10 dospec)@@ -165,12 +217,93 @@ , BlStatement () u label20 (StContinue () u) ] +expectedExample2do :: ProgramFile () expectedExample2do = ProgramFile mi77 [ PUMain () u (Just "example2") expectedExample2doBlocks Nothing ]+expectedExample2doBlocks :: [Block ()] expectedExample2doBlocks = [ BlDo () u Nothing Nothing label10 dospec [ BlDo () u Nothing Nothing label10 dospec- [ BlStatement () u label10 (StContinue () u) ] label10+ [ ] label10 ] label10 , BlDo () u Nothing Nothing label20 dospec- [ BlStatement () u label20 (StContinue () u) ] label20+ [ ] label20 ]++getSingleParsedBlock :: Show b => (ByteString -> String -> ParseResult a b (ProgramFile A0)) -> String -> Block A0+getSingleParsedBlock p c =+ let pf = fromRight . fromParseResult $ p (pack c) "foobar.f"+ ProgramFile _ ((PUSubroutine _ _ _ _ _ (b:_) _):_) = pf+ in b++getSingleParsedBlock95 :: String -> Block A0+getSingleParsedBlock95 = getSingleParsedBlock fortran95Parser++getSingleParsedBlock77 :: String -> Block A0+getSingleParsedBlock77 = getSingleParsedBlock fortran77Parser++getSingleParsedBlock77Legacy :: String -> Block A0+getSingleParsedBlock77Legacy = getSingleParsedBlock legacy77Parser++type SimpleSpan = (Int, Int, Int, Int)++simplifySpan :: SrcSpan -> SimpleSpan+simplifySpan (SrcSpan b e) = (posLine b, posColumn b, posLine e, posColumn e)++ifSpanRaw :: String+ifSpanRaw = unlines [+ " subroutine foobar"+ , " if (.TRUE.) then"+ , " print *, 'w00t'"+ , " endif"+ , " end" ]+ifSpan :: SimpleSpan+ifSpan =+ let BlIf _ s _ _ _ _ _ = getSingleParsedBlock95 ifSpanRaw+ in simplifySpan s+expectedIfSpan :: SimpleSpan+expectedIfSpan = (2, 8, 4, 12)++doSpanRaw :: String+doSpanRaw = unlines [+ " subroutine foobar2"+ , " do ii = 2, 5"+ , " if(ii .eq. 2) print *, ii"+ , " if(ii .eq. 4) print *, ii"+ , " end do"+ , " end" ]+doSpan :: SimpleSpan+doSpan =+ let BlDo _ s _ _ _ _ _ _ = getSingleParsedBlock95 doSpanRaw+ in simplifySpan s+expectedDoSpan :: SimpleSpan+expectedDoSpan = (2, 8, 5, 13)++doWhileSpanRaw :: String+doWhileSpanRaw = unlines [+ " subroutine barfoo"+ , " do while (.true.)"+ , " print *, 'foooo'"+ , " enddo"+ , " end" ]+doWhileSpan :: SimpleSpan+doWhileSpan =+ let BlDoWhile _ s _ _ _ _ _ _ = getSingleParsedBlock95 doWhileSpanRaw+ in simplifySpan s+expectedDoWhileSpan :: SimpleSpan+expectedDoWhileSpan = (2, 8, 4, 12)++ifInnerBlockSpanRaw :: String+ifInnerBlockSpanRaw = unlines [+ " subroutine yeet"+ , " if (.true.) then"+ , "c very important comment"+ , " print *, 'yeet'"+ , "c even more important comment"+ , " endif"+ , " end" ]+ifInnerBlockSpan :: (String -> Block A0) -> SimpleSpan+ifInnerBlockSpan p =+ let BlIf _ _ _ _ _ bs _ = p ifInnerBlockSpanRaw+ in simplifySpan $ getSpan bs+expectedIfInnerBlockSpan :: SimpleSpan+expectedIfInnerBlockSpan = (3, 1, 5, 35)
test/Language/Fortran/Util/FirstParameterSpec.hs view
@@ -12,47 +12,47 @@ data A = A Int deriving (Generic, Eq, Show) data B = B Char Char Int Char deriving (Generic, Eq, Show)-data C = CA ([Int]) Char | CB ([Int]) Int deriving (Generic, Eq, Show)+data C = CA [Int] Char | CB [Int] Int deriving (Generic, Eq, Show) data D = DA () | DB () | DC () | DD () | DE () deriving (Generic, Eq, Show) instance FirstParameter A Int instance FirstParameter B Char-instance FirstParameter C ([Int])+instance FirstParameter C [Int] instance FirstParameter D () spec :: Spec-spec = +spec = describe "First parameter accessor type class" $ do describe "data A" $ do- it "retrieves first parameter from 'A 42'" $ do+ it "retrieves first parameter from 'A 42'" $ getFirstParameter (A 42) `shouldBe` 42 - it "sets first parameter in 'A 42' to 24" $ do+ it "sets first parameter in 'A 42' to 24" $ setFirstParameter 24 (A 42) `shouldBe` A 24 describe "data B" $ do- it "retrieves first parameter from \"B 'x' 'y' 42 'z'\"" $ do+ it "retrieves first parameter from \"B 'x' 'y' 42 'z'\"" $ getFirstParameter (B 'x' 'y' 42 'z') `shouldBe` 'x' - it "sets first parameter in \"B 'x' 'y' 42 'z'\" to 'm'" $ do- setFirstParameter 'm' (B 'x' 'y' 42 'z') `shouldBe` (B 'm' 'y' 42 'z')+ it "sets first parameter in \"B 'x' 'y' 42 'z'\" to 'm'" $+ setFirstParameter 'm' (B 'x' 'y' 42 'z') `shouldBe` B 'm' 'y' 42 'z' describe "data C" $ do- it "retrieves first parameter from 'CA [1,2,3] 'a''" $ do + it "retrieves first parameter from 'CA [1,2,3] 'a''" $ getFirstParameter (CA [1,2,3] 'a') `shouldBe` [1,2,3] - it "retrieves first parameter from \"CB [1,2,3] 'a'\"" $ do + it "retrieves first parameter from \"CB [1,2,3] 'a'\"" $ getFirstParameter (CB [] 42) `shouldBe` [] - it "sets first parameter in \"CB [1,2,3] 'a'\" to '[]'" $ do- setFirstParameter [] (CA [1,2,3] 'a') `shouldBe` (CA [] 'a')+ it "sets first parameter in \"CB [1,2,3] 'a'\" to '[]'" $+ setFirstParameter [] (CA [1,2,3] 'a') `shouldBe` CA [] 'a' describe "data D" $ do- it "retrieves first parameter from 'DB ()" $ do + it "retrieves first parameter from 'DB ()" $ getFirstParameter (DB ()) `shouldBe` () - it "retrieves first parameter from 'DD ()" $ do + it "retrieves first parameter from 'DD ()" $ getFirstParameter (DD ()) `shouldBe` () - it "retrieves first parameter from 'DE ()" $ do + it "retrieves first parameter from 'DE ()" $ getFirstParameter (DE ()) `shouldBe` ()
test/Language/Fortran/Util/SecondParameterSpec.hs view
@@ -12,44 +12,44 @@ data A = A Char Int deriving (Generic, Eq, Show) data B = B Int Int Int Int deriving (Generic, Eq, Show)-data C = CA String [Char] | CB Int [Char] () deriving (Generic, Eq, Show)+data C = CA String String | CB Int String () deriving (Generic, Eq, Show) data D = DA () () | DB Int () Int Int Int Int Int Int Int | DC () () | DD () () Char deriving (Generic, Eq, Show) instance SecondParameter A Int instance SecondParameter B Int-instance SecondParameter C [Char]+instance SecondParameter C String instance SecondParameter D () spec :: Spec spec = describe "Second parameter retrieving type class" $ do describe "data A" $ do- it "retrieves second parameter from 'A 'a' 42'" $ do+ it "retrieves second parameter from 'A 'a' 42'" $ getSecondParameter (A 'x' 42) `shouldBe` 42 - it "sets second parameter in \"A 'a' 42\" to 24" $ do+ it "sets second parameter in \"A 'a' 42\" to 24" $ setSecondParameter 24 (A 'x' 42) `shouldBe` A 'x' 24 describe "data B" $ do- it "retrieves second parameter from 'B 41 42 43 44'" $ do+ it "retrieves second parameter from 'B 41 42 43 44'" $ getSecondParameter (B 41 42 43 44) `shouldBe` 42 - it "sets second parameter in \"B 41 42 43 44\" to 24" $ do+ it "sets second parameter in \"B 41 42 43 44\" to 24" $ setSecondParameter 24 (B 41 42 43 44) `shouldBe` B 41 24 43 44 describe "data C" $ do- it "retrieves second parameter from 'CA \"hello\" ['x', 'y']'" $ do+ it "retrieves second parameter from 'CA \"hello\" ['x', 'y']'" $ getSecondParameter (CA "hello" ['x', 'y']) `shouldBe` ['x', 'y'] - it "retrieves second parameter from 'CB 42 [] ()'" $ do+ it "retrieves second parameter from 'CB 42 [] ()'" $ getSecondParameter (CB 42 [] ()) `shouldBe` [] - it "sets second parameter in \"CB 42 []\" to ['x','x','x']" $ do+ it "sets second parameter in \"CB 42 []\" to ['x','x','x']" $ setSecondParameter "xxx" (CB 42 [] ()) `shouldBe` CB 42 "xxx" () describe "data d" $ do- it "retrieves second parameter from 'DB 42 () 42 42 42 42 42 42 42'" $ do+ it "retrieves second parameter from 'DB 42 () 42 42 42 42 42 42 42'" $ getSecondParameter (DB 42 () 42 42 42 42 42 42 42) `shouldBe` () - it "retrieves second parameter from 'DD () () 'a'" $ do+ it "retrieves second parameter from 'DD () () 'a'" $ getSecondParameter (DD () () 'a') `shouldBe` ()
test/TestUtil.hs view
@@ -12,22 +12,27 @@ import Language.Fortran.Util.Position import Language.Fortran.Analysis-import Language.Fortran.Analysis.Renaming hiding (extractNameMap, underRenaming)+import Language.Fortran.Analysis.Renaming import qualified Data.Map as M import Data.Maybe +u :: SrcSpan u = initSrcSpan +mi77 :: MetaInfo mi77 = MetaInfo { miVersion = Fortran77, miFilename = "<unknown>" }+mi90 :: MetaInfo mi90 = MetaInfo { miVersion = Fortran90, miFilename = "<unknown>" } +valTrue :: Expression () valTrue = ExpValue () u $ ValLogical ".true."+valFalse :: Expression () valFalse = ExpValue () u $ ValLogical ".false." varGen :: String -> Expression () varGen str = ExpValue () u $ ValVariable str -intGen :: (Show a, Integral a) => a -> Expression ()+intGen :: Integer -> Expression () intGen i = ExpValue () u $ ValInteger $ show i realGen :: (Fractional a, Show a) => a -> Expression ()@@ -48,11 +53,15 @@ assVal :: Expression () assVal = ExpValue () u ValAssignment +ixSinGen :: Integer -> Index () ixSinGen i = IxSingle () u Nothing (intGen i)+ixRanGen :: Integer -> Integer -> Index () ixRanGen i j = IxRange () u (Just $ intGen i) (Just $ intGen j) Nothing +shouldBe' :: (Data a, Eq a, Show a) => a -> a -> Expectation shouldBe' a b = resetSrcSpan a `shouldBe` resetSrcSpan b +shouldMatchList' :: (Data a, Eq a, Show a) => [a] -> [a] -> Expectation shouldMatchList' a b = resetSrcSpan a `shouldMatchList` resetSrcSpan b -- To be used in testing it reverts the SrcSpans in AST to dummy initial@@ -77,8 +86,8 @@ extractNameMap :: Data a => ProgramFile (Analysis a) -> M.Map String String extractNameMap pf = eMap `M.union` puMap where- eMap = M.fromList [ (un, n) | ExpValue (Analysis { uniqueName = Just un, sourceName = Just n }) _ _ <- uniE pf ]- puMap = M.fromList [ (un, n) | pu <- uniPU pf, (Analysis { uniqueName = Just un, sourceName = Just n }) <- [getAnnotation pu] ]+ eMap = M.fromList [ (un, n) | ExpValue Analysis { uniqueName = Just un, sourceName = Just n } _ _ <- uniE pf ]+ puMap = M.fromList [ (un, n) | pu <- uniPU pf, Analysis { uniqueName = Just un, sourceName = Just n } <- [getAnnotation pu] ] uniE :: Data a => ProgramFile a -> [Expression a] uniE = universeBi uniPU :: Data a => ProgramFile a -> [ProgramUnit a]