Skip to content

Commit 1fcadb7

Browse files
committed
re-add F77 inlined includes parser
1 parent 94735a1 commit 1fcadb7

File tree

3 files changed

+134
-16
lines changed

3 files changed

+134
-16
lines changed

app/Main.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{-# LANGUAGE FlexibleContexts, FlexibleInstances, ScopedTypeVariables, OverloadedStrings #-}
1+
{-# LANGUAGE ScopedTypeVariables, OverloadedStrings #-}
22
{-# OPTIONS_GHC -Wno-orphans #-}
33

44
module Main where

src/Language/Fortran/Parser.hs

Lines changed: 131 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,21 @@ combinators are exposed to assist in manually configuring parsers.
1313
module Language.Fortran.Parser
1414
(
1515
-- * Main parsers (ProgramFile, with transformation)
16-
f66, f77, f90, f95, f2003
16+
byVer, byVerWithMods
17+
, f66, f77, f77e, f77l, f90, f95, f2003
1718

1819
-- * Main parsers without post-parse transformation
19-
, f66NoTransform, f77NoTransform, f90NoTransform, f95NoTransform, f2003NoTransform
20+
, f66NoTransform, f77NoTransform, f77eNoTransform, f77lNoTransform
21+
, f90NoTransform, f95NoTransform, f2003NoTransform
2022

21-
-- * Parser former combinators
23+
-- * Various combinators
2224
, transformAs, defaultTransformation
2325
, StateInit, ParserMaker, makeParser, makeParserFixed, makeParserFree
2426
, initParseStateFixed, initParseStateFree
27+
28+
-- * F77 with inlined includes
29+
-- $f77includes
30+
, f77lIncludes
2531
) where
2632

2733
import Language.Fortran.AST
@@ -36,6 +42,7 @@ import qualified Language.Fortran.Parser.Fixed.Lexer as Fixed
3642
import qualified Language.Fortran.Parser.Free.Lexer as Free
3743
import Language.Fortran.Version
3844
import Language.Fortran.Util.Position
45+
import Language.Fortran.Util.ModFile
3946
import Language.Fortran.Transformation.Monad
4047
import qualified Language.Fortran.Transformation.Grouping as Trans
4148
import qualified Language.Fortran.Transformation.Disambiguation.Function as Trans
@@ -44,24 +51,71 @@ import qualified Language.Fortran.Transformation.Disambiguation.Intrinsic as Tra
4451
import qualified Data.ByteString.Char8 as B
4552
import Data.Data
4653

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+
4762
-- | Our common Fortran parser type takes a filename and input, and returns
4863
-- either a normalized error (tokens are printed) or an untransformed
4964
-- 'ProgramFile'.
5065
type Parser a = String -> B.ByteString -> Either ParseErrorSimple a
5166

5267
--------------------------------------------------------------------------------
5368

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
62114
:: Parser (ProgramFile A0)
63115
f66NoTransform = makeParserFixed F66.programParser Fortran66
64116
f77NoTransform = makeParserFixed F77.programParser Fortran77
117+
f77eNoTransform = makeParserFixed F77.programParser Fortran77Extended
118+
f77lNoTransform = makeParserFixed F77.programParser Fortran77Legacy
65119
f90NoTransform = makeParserFree F90.programParser Fortran90
66120
f95NoTransform = makeParserFree F95.programParser Fortran95
67121
f2003NoTransform = makeParserFree F2003.programParser Fortran2003
@@ -70,9 +124,15 @@ f2003NoTransform = makeParserFree F2003.programParser Fortran2003
70124

71125
transformAs
72126
:: 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)
76136

77137
-- | The default post-parse AST transformation for each Fortran version.
78138
--
@@ -130,3 +190,60 @@ initParseStatePartial = ParseState
130190
, psFilename = undefined
131191
, psParanthesesCount = ParanthesesCount 0 False
132192
, 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

src/Language/Fortran/Parser/Common.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ data ParseResult b c a = ParseOk a (ParseState b) | ParseFailed (ParseError b c)
8080
data ParseErrorSimple = ParseErrorSimple
8181
{ errorPos :: Position
8282
, errorFilename :: String
83-
, errorMsg :: String }
83+
, errorMsg :: String
84+
} deriving (Exception)
8485

8586
fromParseResultUnsafe :: (Show c) => ParseResult b c a -> a
8687
fromParseResultUnsafe (ParseOk a _) = a

0 commit comments

Comments
 (0)