@@ -13,15 +13,21 @@ combinators are exposed to assist in manually configuring parsers.
13
13
module Language.Fortran.Parser
14
14
(
15
15
-- * Main parsers (ProgramFile, with transformation)
16
- f66 , f77 , f90 , f95 , f2003
16
+ byVer , byVerWithMods
17
+ , f66 , f77 , f77e , f77l , f90 , f95 , f2003
17
18
18
19
-- * Main parsers without post-parse transformation
19
- , f66NoTransform , f77NoTransform , f90NoTransform , f95NoTransform , f2003NoTransform
20
+ , f66NoTransform , f77NoTransform , f77eNoTransform , f77lNoTransform
21
+ , f90NoTransform , f95NoTransform , f2003NoTransform
20
22
21
- -- * Parser former combinators
23
+ -- * Various combinators
22
24
, transformAs , defaultTransformation
23
25
, StateInit , ParserMaker , makeParser , makeParserFixed , makeParserFree
24
26
, initParseStateFixed , initParseStateFree
27
+
28
+ -- * F77 with inlined includes
29
+ -- $f77includes
30
+ , f77lIncludes
25
31
) where
26
32
27
33
import Language.Fortran.AST
@@ -36,6 +42,7 @@ import qualified Language.Fortran.Parser.Fixed.Lexer as Fixed
36
42
import qualified Language.Fortran.Parser.Free.Lexer as Free
37
43
import Language.Fortran.Version
38
44
import Language.Fortran.Util.Position
45
+ import Language.Fortran.Util.ModFile
39
46
import Language.Fortran.Transformation.Monad
40
47
import qualified Language.Fortran.Transformation.Grouping as Trans
41
48
import qualified Language.Fortran.Transformation.Disambiguation.Function as Trans
@@ -44,24 +51,71 @@ import qualified Language.Fortran.Transformation.Disambiguation.Intrinsic as Tra
44
51
import qualified Data.ByteString.Char8 as B
45
52
import Data.Data
46
53
54
+ import Control.Monad.State
55
+ import qualified Data.Map as Map
56
+ import Data.Map ( Map )
57
+ import Data.Generics.Uniplate.Operations ( descendBiM )
58
+ import Control.Exception ( throwIO )
59
+ import System.FilePath ( (</>) )
60
+ import System.Directory ( doesFileExist )
61
+
47
62
-- | Our common Fortran parser type takes a filename and input, and returns
48
63
-- either a normalized error (tokens are printed) or an untransformed
49
64
-- 'ProgramFile'.
50
65
type Parser a = String -> B. ByteString -> Either ParseErrorSimple a
51
66
52
67
--------------------------------------------------------------------------------
53
68
54
- f66 , f77 , f90 , f95 , f2003 :: Parser (ProgramFile A0 )
55
- f66 = transformAs Fortran66 f66NoTransform
56
- f77 = transformAs Fortran77 f77NoTransform
57
- f90 = transformAs Fortran90 f90NoTransform
58
- f95 = transformAs Fortran95 f95NoTransform
59
- f2003 = transformAs Fortran2003 f2003NoTransform
60
-
61
- f66NoTransform, f77NoTransform, f90NoTransform, f95NoTransform, f2003NoTransform
69
+ byVer :: FortranVersion -> Parser (ProgramFile A0 )
70
+ byVer = \ case
71
+ Fortran66 -> f66
72
+ Fortran77 -> f77
73
+ Fortran77Extended -> f77e
74
+ Fortran77Legacy -> f77l
75
+ Fortran90 -> f90
76
+ Fortran95 -> f95
77
+ Fortran2003 -> f2003
78
+ v -> error $ " Language.Fortran.Parser.byVer: "
79
+ <> " no parser available for requested version: "
80
+ <> show v
81
+
82
+ byVerWithMods :: ModFiles -> FortranVersion -> Parser (ProgramFile A0 )
83
+ byVerWithMods mods = \ case
84
+ Fortran66 -> f66Mods mods
85
+ Fortran77 -> f77Mods mods
86
+ Fortran77Extended -> f77eMods mods
87
+ Fortran77Legacy -> f77lMods mods
88
+ Fortran90 -> f90Mods mods
89
+ Fortran95 -> f95Mods mods
90
+ Fortran2003 -> f2003Mods mods
91
+ v -> error $ " Language.Fortran.Parser.byVerWithMods: no parser available for requested version: " <> show v
92
+
93
+ f66 , f77 , f77e , f77l , f90 , f95 , f2003 :: Parser (ProgramFile A0 )
94
+ f66 = f66Mods []
95
+ f77 = f77Mods []
96
+ f77e = f77eMods []
97
+ f77l = f77lMods []
98
+ f90 = f90Mods []
99
+ f95 = f95Mods []
100
+ f2003 = f2003Mods []
101
+
102
+ f66Mods, f77Mods, f77eMods, f77lMods, f90Mods, f95Mods, f2003Mods
103
+ :: ModFiles -> Parser (ProgramFile A0 )
104
+ f66Mods = transformAs Fortran66 f66NoTransform
105
+ f77Mods = transformAs Fortran77 f77NoTransform
106
+ f77eMods = transformAs Fortran77Extended f77NoTransform
107
+ f77lMods = transformAs Fortran77Legacy f77NoTransform
108
+ f90Mods = transformAs Fortran90 f90NoTransform
109
+ f95Mods = transformAs Fortran95 f95NoTransform
110
+ f2003Mods = transformAs Fortran2003 f2003NoTransform
111
+
112
+ f66NoTransform, f77NoTransform, f77eNoTransform, f77lNoTransform,
113
+ f90NoTransform, f95NoTransform, f2003NoTransform
62
114
:: Parser (ProgramFile A0 )
63
115
f66NoTransform = makeParserFixed F66. programParser Fortran66
64
116
f77NoTransform = makeParserFixed F77. programParser Fortran77
117
+ f77eNoTransform = makeParserFixed F77. programParser Fortran77Extended
118
+ f77lNoTransform = makeParserFixed F77. programParser Fortran77Legacy
65
119
f90NoTransform = makeParserFree F90. programParser Fortran90
66
120
f95NoTransform = makeParserFree F95. programParser Fortran95
67
121
f2003NoTransform = makeParserFree F2003. programParser Fortran2003
@@ -70,9 +124,15 @@ f2003NoTransform = makeParserFree F2003.programParser Fortran2003
70
124
71
125
transformAs
72
126
:: Data a
73
- => FortranVersion -> Parser (ProgramFile a ) -> Parser (ProgramFile a )
74
- transformAs fv p fn bs =
75
- runTransform mempty mempty (defaultTransformation fv) <$> p fn bs
127
+ => FortranVersion -> Parser (ProgramFile a ) -> ModFiles
128
+ -> Parser (ProgramFile a )
129
+ transformAs fv p mods fn bs = do
130
+ pf <- p fn bs
131
+ let pf' = pfSetFilename fn pf
132
+ return $ transform pf'
133
+ where transform = runTransform (combinedTypeEnv mods)
134
+ (combinedModuleMap mods)
135
+ (defaultTransformation fv)
76
136
77
137
-- | The default post-parse AST transformation for each Fortran version.
78
138
--
@@ -130,3 +190,60 @@ initParseStatePartial = ParseState
130
190
, psFilename = undefined
131
191
, psParanthesesCount = ParanthesesCount 0 False
132
192
, psContext = [ ConStart ] }
193
+
194
+ --------------------------------------------------------------------------------
195
+
196
+ {- $f77includes
197
+ The Fortran 77 parser can parse and inline includes at parse time. Parse errors
198
+ are thrown as IO exceptions.
199
+
200
+ Can be cleaned up and generalized to use for other parsers.
201
+ -}
202
+
203
+ f77lIncludes
204
+ :: [FilePath ] -> ModFiles -> String -> B. ByteString
205
+ -> IO (ProgramFile A0 )
206
+ f77lIncludes incs mods fn bs = do
207
+ case f77lNoTransform fn bs of
208
+ Left e -> liftIO $ throwIO e
209
+ Right pf -> do
210
+ let pf' = pfSetFilename fn pf
211
+ pf'' <- evalStateT (descendBiM (f77lIncludesInline incs [] ) pf') Map. empty
212
+ let pf''' = runTransform (combinedTypeEnv mods)
213
+ (combinedModuleMap mods)
214
+ (defaultTransformation Fortran77Legacy )
215
+ pf''
216
+ return pf'''
217
+
218
+ f77lIncludesInner :: Parser [Block A0 ]
219
+ f77lIncludesInner = makeParserFixed F77. includesParser Fortran77Legacy
220
+
221
+ f77lIncludesInline
222
+ :: [FilePath ] -> [FilePath ] -> Statement A0
223
+ -> StateT (Map String [Block A0 ]) IO (Statement A0 )
224
+ f77lIncludesInline dirs seen st = case st of
225
+ StInclude a s e@ (ExpValue _ _ (ValString path)) Nothing -> do
226
+ if notElem path seen then do
227
+ incMap <- get
228
+ case Map. lookup path incMap of
229
+ Just blocks' -> pure $ StInclude a s e (Just blocks')
230
+ Nothing -> do
231
+ (fullPath, inc) <- liftIO $ readInDirs dirs path
232
+ case f77lIncludesInner fullPath inc of
233
+ Right blocks -> do
234
+ blocks' <- descendBiM (f77lIncludesInline dirs (path: seen)) blocks
235
+ modify (Map. insert path blocks')
236
+ return $ StInclude a s e (Just blocks')
237
+ Left err -> liftIO $ throwIO err
238
+ else return st
239
+ _ -> return st
240
+
241
+ readInDirs :: [String ] -> String -> IO (String , B. ByteString )
242
+ readInDirs [] f = fail $ " cannot find file: " ++ f
243
+ readInDirs (d: ds) f = do
244
+ let path = d</> f
245
+ b <- doesFileExist path
246
+ if b then
247
+ (path,) <$> B. readFile path
248
+ else
249
+ readInDirs ds f
0 commit comments