{- The front phase of the compiler this needs to - do lexical analysis - parse the program source code - do "need" analysis which determines which symbols are needed by the program It is especially useful to have this as a seperate phase because it is used repeatedly by Make.lhs in doing dependency analysis. There are two public items front - the function to do the front end of the compiler FrontData - the useful data extracted from the front end -} module Front(front, FrontData(..)) where import System import IO import Util.Extra import Flags import Syntax hiding (TokenId) import Info import Error import qualified Data.Map as Map import qualified Data.Set as Set import Parse.Lexical(lexical) import Parse.Parse(parseProg) import Parse.ParseCore(parseit) import Parse.Pragma(parsePragmas) import Need(needProg,NeedTable) import Import(HideDeclIds,importOne) import Language.Preprocessor.Unlit(unlit) import Overlap(Overlap) import SysDeps(PackedString) import PrettySyntax(ppModule, prettyPrintTokenId) import Data.PackedString(unpackPS) import Phase import TokenId import Language.Preprocessor.Cpphs import System.FilePath import System.Console.GetOpt {- FrontData is the data returns by the front end FIXME: unsure about some things here ... fParsedPrg the abstract syntax tree of the parsed program fNeed the table of values needed by this module fQualFun ... unsure find out what this does!! fOverlap ... unsure find out what this does!! fExpFun ... unsure find out what this does!! fImports a list of things that need to be imported, which is of the form [(mrps, needFun, hideFun)] where mrps the reversed packed string of the imported module needFun .. unsure find out what this does!! hideFun .. unsure find out what this does!! -} data FrontData = FrontData { fParsedPrg :: Module TokenId, fNeed :: NeedTable, fQualFun :: TokenId -> [TokenId], fOverlap :: Overlap, fExpFun :: (TokenId -> Bool) -> TokenId -> IdKind -> IE, fImports :: [(PackedString, (PackedString, PackedString, Set.Set TokenId) -> [[TokenId]] -> Bool, HideDeclIds)], fModName :: String, fFlags :: Flags, fFileFlags :: FileFlags } {- front is the proper front end of the compiler. flags compiler flags filename the filename of the module to load and parse returns a FrontData representing what was loaded from the file -} front :: Flags -> FilePath -> IO FrontData front flags filename = do -- assume unlit for .lhs files flags <- return $ flags{sUnlit = sUnlit flags || (takeExtension filename == ".lhs")} -- do lexical analysis, giving a list of tokens beginPhase "lex" mainChar -- :: String <- tryReadFile "" filename -- read any pragma's that might be around let pragmas = parsePragmas mainChar let (flagchanges, _, _) = getOpt Permute allOpts (concatMap words pragmas) flags <- return $ foldr ($) flags flagchanges mainCpp -- :: String -- The string after running cpphs (if necessary) <- if sCpp flags then cpphs flags filename mainChar else return mainChar lexdata -- :: [PosToken] <- return $ lexical (sUnderscore flags) filename $ (if sUnlit flags then unlit filename else id) $ mainCpp pF (sLex flags) "Lexical" (mixSpace (map (\ (p,l,_,_) -> strPos p ++ ':':show l) lexdata)) -- parse the source code giving an abstract syntax tree of the program beginPhase "parse" parsedPrg -- :: Module TokenId <- catchError2 (parseit parseProg lexdata) (showErr filename) pF (sParse flags) "Parse" (prettyPrintTokenId flags ppModule parsedPrg) -- change the module decl to say to export everything, if that's appropriate ... -- FIXME: bit of a hack really, should be a nicer way to do it -- FIXME: shouldn't this be just before exporting the interface? parsedPrg <- if sExportAll flags then case parsedPrg of Module pos modidl _ impdecls fixdecls topdecls -> let exports = Just [ExportModid pos modidl] in return (Module pos modidl exports impdecls fixdecls topdecls) else return parsedPrg -- Perform "need" analysis (what imported entities are required?) -- Second argument may contain error message or parse tree beginPhase "need" (need -- :: NeedTable ,qualFun -- :: TokenId -> [TokenId] ,overlap -- :: Overlap ,info) -- :: Either String (expFun,imports) <- return (needProg flags parsedPrg) (expFun -- :: (TokenId->Bool) -> TokenId -> IdKind -> IE ,imports) -- :: [ ( PackedString -- , (PackedString, PackedString, Tree (TokenId,IdKind)) -- -> [[TokenId]] -> Bool -- , HideDeclIds -- ) -- ] <- catchError info ("In file: " ++ filename) id pF (sNeed flags) "Need (after reading source module)" (show (Map.toList need)) let (Module _ (Visible modid) _ _ _ _ ) = parsedPrg modName = reverse (unpackPS modid) fileflags = getFileFlags flags filename modName return (FrontData parsedPrg need qualFun overlap expFun imports modName flags fileflags) cpphs :: Flags -> FilePath -> String -> IO String cpphs flags filename contents = return $ runCpphs opts filename contents where opts = defaultCpphsOptions {defines = macros, boolopts = defaultBoolOptions{ansi=True, stripC89=False, stripEol=False}} macros = [("__HASKELL__","98"), ("__HASKELL_98__", "1"), ("__HASKELL98__", "1"), ("__YHC__", "1")]