1 -----------------------------------------------------------------------------
3 -- Parsing the top of a Haskell source file to get its module name,
4 -- imports and options.
6 -- (c) Simon Marlow 2005
9 -----------------------------------------------------------------------------
11 {-# OPTIONS_GHC -w #-}
12 -- The above warning supression flag is a temporary kludge.
13 -- While working on this module you are encouraged to remove it and fix
14 -- any warnings in the module. See
15 -- http://hackage.haskell.org/trac/ghc/wiki/WorkingConventions#Warnings
18 module HeaderInfo ( getImportsFromFile, getImports
19 , getOptionsFromFile, getOptions
20 , optionsErrorMsgs ) where
22 #include "HsVersions.h"
24 import Parser ( parseHeader )
27 import HsSyn ( ImportDecl(..), HsModule(..) )
28 import Module ( ModuleName, moduleName )
29 import PrelNames ( gHC_PRIM, mAIN_NAME )
30 import StringBuffer ( StringBuffer(..), hGetStringBuffer, hGetStringBufferBlock
31 , appendStringBuffers )
41 import Bag ( emptyBag, listToBag )
43 import Control.Exception
49 #if __GLASGOW_HASKELL__ >= 601
50 import System.IO ( openBinaryFile )
52 import IOExts ( openFileEx, IOModeEx(..) )
55 #if __GLASGOW_HASKELL__ < 601
56 openBinaryFile fp mode = openFileEx fp (BinaryMode mode)
59 -- getImportsFromFile is careful to close the file afterwards, otherwise
60 -- we can end up with a large number of open handles before the garbage
61 -- collector gets around to closing them.
62 getImportsFromFile :: DynFlags -> FilePath
63 -> IO ([Located ModuleName], [Located ModuleName], Located ModuleName)
64 getImportsFromFile dflags filename = do
65 buf <- hGetStringBuffer filename
66 getImports dflags buf filename
68 getImports :: DynFlags -> StringBuffer -> FilePath
69 -> IO ([Located ModuleName], [Located ModuleName], Located ModuleName)
70 getImports dflags buf filename = do
71 let loc = mkSrcLoc (mkFastString filename) 1 0
72 case unP parseHeader (mkPState buf loc dflags) of
73 PFailed span err -> parseError span err
74 POk pst rdr_module -> do
75 let ms = getMessages pst
76 printErrorsAndWarnings dflags ms
77 when (errorsFound dflags ms) $ exitWith (ExitFailure 1)
79 L _ (HsModule mb_mod _ imps _ _ _ _ _) ->
81 mod = mb_mod `orElse` L (srcLocSpan loc) mAIN_NAME
82 (src_idecls, ord_idecls) = partition isSourceIdecl (map unLoc imps)
83 source_imps = map getImpMod src_idecls
84 ordinary_imps = filter ((/= moduleName gHC_PRIM) . unLoc)
85 (map getImpMod ord_idecls)
86 -- GHC.Prim doesn't exist physically, so don't go looking for it.
88 return (source_imps, ordinary_imps, mod)
90 parseError span err = throwDyn $ mkPlainErrMsg span err
92 isSourceIdecl (ImportDecl _ s _ _ _) = s
94 getImpMod (ImportDecl located_mod _ _ _ _) = located_mod
96 --------------------------------------------------------------
98 --------------------------------------------------------------
101 getOptionsFromFile :: FilePath -- input file
102 -> IO [Located String] -- options, if any
103 getOptionsFromFile filename
104 = Control.Exception.bracket
105 (openBinaryFile filename ReadMode)
108 do buf <- hGetStringBufferBlock handle blockSize
110 where blockSize = 1024
112 | len buf == 0 = return []
114 = case getOptions' buf filename of
115 (Nothing, opts) -> return opts
116 (Just buf', opts) -> do nextBlock <- hGetStringBufferBlock handle blockSize
117 newBuf <- appendStringBuffers buf' nextBlock
118 if len newBuf == len buf
120 else do opts' <- loop handle newBuf
123 getOptions :: StringBuffer -> FilePath -> [Located String]
124 getOptions buf filename
125 = case getOptions' buf filename of
128 -- The token parser is written manually because Happy can't
129 -- return a partial result when it encounters a lexer error.
130 -- We want to extract options before the buffer is passed through
131 -- CPP, so we can't use the same trick as 'getImports'.
132 getOptions' :: StringBuffer -- Input buffer
133 -> FilePath -- Source file. Used for msgs only.
134 -> ( Maybe StringBuffer -- Just => we can use more input
135 , [Located String] -- Options.
137 getOptions' buf filename
138 = parseToks (lexAll (pragState buf loc))
139 where loc = mkSrcLoc (mkFastString filename) 1 0
141 getToken (buf,L _loc tok) = tok
142 getLoc (buf,L loc _tok) = loc
143 getBuf (buf,_tok) = buf
144 combine opts (flag, opts') = (flag, opts++opts')
145 add opt (flag, opts) = (flag, opt:opts)
147 parseToks (open:close:xs)
148 | IToptions_prag str <- getToken open
149 , ITclose_prag <- getToken close
150 = map (L (getLoc open)) (words str) `combine`
152 parseToks (open:close:xs)
153 | ITinclude_prag str <- getToken open
154 , ITclose_prag <- getToken close
155 = map (L (getLoc open)) ["-#include",removeSpaces str] `combine`
158 | ITlanguage_prag <- getToken open
160 -- The last token before EOF could have been truncated.
161 -- We ignore it to be on the safe side.
163 | ITeof <- getToken eof
164 = (Just (getBuf tok),[])
166 | ITeof <- getToken eof
167 = (Just (getBuf eof),[])
168 parseToks _ = (Nothing,[])
169 parseLanguage ((_buf,L loc (ITconid fs)):rest)
170 = checkExtension (L loc fs) `add`
172 (_,L loc ITcomma):more -> parseLanguage more
173 (_,L loc ITclose_prag):more -> parseToks more
174 (_,L loc _):_ -> languagePragParseError loc
175 parseLanguage (tok:_)
176 = languagePragParseError (getLoc tok)
177 lexToken t = return t
178 lexAll state = case unP (lexer lexToken) state of
179 POk state' t@(L _ ITeof) -> [(buffer state,t)]
180 POk state' t -> (buffer state,t):lexAll state'
181 _ -> [(buffer state,L (last_loc state) ITeof)]
183 checkExtension :: Located FastString -> Located String
184 checkExtension (L l ext)
185 -- Checks if a given extension is valid, and if so returns
186 -- its corresponding flag. Otherwise it throws an exception.
187 = let ext' = unpackFS ext in
188 if ext' `elem` supportedLanguages
189 || ext' `elem` (map ("No"++) supportedLanguages)
190 then L l ("-X"++ext')
191 else unsupportedExtnError l ext'
193 languagePragParseError loc =
194 pgmError (showSDoc (mkLocMessage loc (
195 text "cannot parse LANGUAGE pragma")))
197 unsupportedExtnError loc unsup =
198 pgmError (showSDoc (mkLocMessage loc (
199 text "unsupported extension: " <>
203 optionsErrorMsgs :: [String] -> [Located String] -> FilePath -> Messages
204 optionsErrorMsgs unhandled_flags flags_lines filename
205 = (emptyBag, listToBag (map mkMsg unhandled_flags_lines))
206 where unhandled_flags_lines = [ L l f | f <- unhandled_flags,
207 L l f' <- flags_lines, f == f' ]
208 mkMsg (L flagSpan flag) =
209 ErrUtils.mkPlainErrMsg flagSpan $
210 text "unknown flag in {-# OPTIONS #-} pragma:" <+> text flag