Plan 9 from Bell Labs’s /usr/web/sources/contrib/fernan/nhc98/src/compiler98/Compile.hs

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


-- Compile takes the data from the front end and does the rest of the compilation

module Compile(compileOne) where

import IO

import Util.Extra
import System.FilePath
import System.Directory
import Control.Monad
import Flags
import Error
import qualified Data.Map as Map
import qualified Data.Set as Set
import SysDeps(PackedString, unpackPS)
import Syntax hiding (TokenId)
import IntState(IntState,getSymbolTable,getErrorsIS,strIS,arityIS,mrpsIS,lookupIS)
import TokenId
import Info
import Id(Id)
import ImportState(ImportState,initIS,getSymbolTableIS,getErrIS
                  ,getRenameTableIS)
import PrettySyntax(prettyPrintTokenId,prettyPrintId
                   ,ppModule,ppTopDecls,ppClassCodes)
import StrPos(strPCode)
import ReportImports(reportFnImports)


import Import(HideDeclIds,importOne)
import IExtract(getNeedIS,addPreludeTupleInstances)
import Rename
import Depend(depend)
import FFITrans(ffiTrans)
import Derive.Derive(derive)
import Extract(extract)
import Remove1_3(removeDecls)
import RmClasses(rmClasses)
import SccModule(sccTopDecls)
import Type.Type(typeTopDecls)
import Type.Lib(typeOfMain)
import Export(buildInterface)
import FixSyntax(fixSyntax)
import FreeVar(freeVar)
import Lift(liftCode)
import Case(caseTopLevel)
import PrimCode(primCode)
import STGArity(stgArity)
import PosAtom(posAtom)
import ByteCode.CompileYhcCore
import ByteCode.ByteCode
import DotNet.Compile
import DotNet.Show

import Core.Convert
import Yhc.Core
import ByteCode.Write(withDirectory) -- FIXME: totally the wrong place for withDirectory

import Front


compileOne :: FrontData -> Map.Map String FilePath -> IO ()
compileOne fd hiDeps = do
  let (parsedPrg, need, qualFun, overlap, expFun, imports, moduName, flags, fileflags) =
          (fParsedPrg fd, fNeed fd, fQualFun fd, fOverlap fd, fExpFun fd,
           fImports fd, fModName fd, fFlags fd, fFileFlags fd)

  (Module _ (Visible modid) _ impdecls inf decls) <- return parsedPrg

  shortName <- System.FilePath.makeRelativeToCurrentDirectory $ sSourceFile fileflags
  putStrLn $ "Compiling " ++ moduName ++
             replicate (max 0 (16 - length moduName)) ' ' ++
             " ( " ++ shortName ++ " )"

 {- Parse interface files for imported modules.  -}
  beginPhase "imports"
  importState   -- :: ImportState
              <- nhcImport flags (addPreludeTupleInstances () (initIS need)) hiDeps
                           imports

  {-
  -- Rename identifiers (also patches fixity information)
  -- Changes from ImportState to IntState
  -}
  beginPhase "rename"
  (decls        -- :: Decls Id  (renamed from decls :: Decls TokenId)
   ,state       -- :: IntState  (internal compiler state)
   ,tidFun      -- :: ((TokenId,IdKind) -> Id)
                --     (mapping from id token and kind to internal id)
   ,tidFunSafe  --   tidFunSafe does not appear to be used anywhere!
   ,derived     -- :: [(Id,[(Pos,Id)])]
                --     instances that have to be derived:
                --     class, position where derived, type constructor
   ,userDefault -- :: Maybe [Id]  (user defaults for Num classes)
   ,rt)         -- :: RenameTable
       <- catchError (rename flags modid qualFun expFun inf decls
                             importState overlap)
                     "when renaming"
  pF (sRename flags) "Declarations after rename and fixity:"
        (prettyPrintId flags state ppTopDecls decls)
  pF (sRBound flags) "Symbol table after rename and fixity:"
        (mixLine (map show (Map.toList (getSymbolTable state))))
  catchErrorStr (getErrorsIS state) "after renaming"

  {- Record dependencies in .dep file -}
  depend flags fileflags state rt


  {-
  -- For foreign imports, transform all functions with IO types to introduce
  -- the appropriate wrapper.
  -}
  beginPhase "ffitrans"
  (decls        -- :: Decls Id
   ,state)      -- :: IntState
             <- return (ffiTrans decls tidFun state)


  {- Derive class instances where required by data definitions -}
  beginPhase "derive"
  (state        -- :: IntState
   ,decls)      -- :: Decls Id
           <- catchErrorStr (derive tidFun state derived decls)
                         "Deriving failed"
  pF (sDerive flags) "Declarations after deriving:"
          (prettyPrintId flags state ppTopDecls decls)
  pF (sDBound flags) "Symbol table after deriving:"
         (mixLine (map show (Map.toList (getSymbolTable state))))


  {-
  -- Adds arity of all defined variables to symbol table of internal state.
  -- Adds type of variables from type declarations and primitive and foreign
  -- function definitions to symbol table of internal state
  -- (but not type declarations from classes).
  -- May discover a few errors and add appropriate messages to internal state.
  -}
  beginPhase "extract"
  state -- :: IntState
           <- return (extract decls state)
  pF (sEBound flags) "Symbol table after extract:"
           (mixLine (map show (Map.toList (getSymbolTable state))))
  catchErrorStr (getErrorsIS state) "after extract phase"


  {-
  -- Create selectors for record fields.
  -- (replace DeclConstrs by definitions for the selectors)
  -}
  beginPhase "remove fields"
  (decls        -- :: Decls Id
   ,zcon        -- :: [Int]
   ,state)      -- :: IntState
          <- return (removeDecls decls tidFun state)
  pF (sRemove flags) "Declarations after remove fields:"
         (prettyPrintId flags state ppTopDecls decls)
  catchErrorStr (getErrorsIS state) "after removing fields"


  {-
  -- First replace class and instance declarations by their type and method
  -- declarations; also fix arity of method definitions.
  -- Strongly Connected Component analysis
  -}
  beginPhase "scc"
  (code         -- :: [ClassCode (Exp Id) Id]
   ,decls       -- :: Decls Id
   ,state)      -- :: IntState
        <- return (rmClasses tidFun state decls)
  decls         -- :: Decls Id
        <- return (sccTopDecls decls)
  pF (sScc flags) "Declarations after scc:"
    (prettyPrintId flags state ppTopDecls decls)
  pF (sScc flags) "Class/instances after scc:"
    (prettyPrintId flags state ppClassCodes code)


  {-
  -- Type inference.
  -- Also remove do notation and record expressions.
  -}
  beginPhase "type"
  (code         -- :: [ClassCode (Exp Id) Id]
   ,decls       -- :: Decls Id
   ,state)      -- :: IntState
          <- return (typeTopDecls tidFun userDefault state code decls)
  pF (sType flags) "Declarations after type deriving:"
         (prettyPrintId flags state ppTopDecls decls)
  pF (sTBound flags) "Symbol table after type deriving:"
         (mixLine (map show (Map.toList (getSymbolTable state))))
  catchErrorStr (getErrorsIS state) "after type inference/checking"


  {- Build interface file for this module and write it out -}
  beginPhase "interface"
  let modname = reverse (unpackPS modid)
  pF (sRImport flags) ("Actual imports used by this module ("++modname++"):")
         (mixLine (reportFnImports modname state))
  state <- if modname == "Main"
                 then typeOfMain flags tidFun decls state
                 else return state

  catch (withDirectory (sTypeFile fileflags) id (buildInterface flags modid state))
        (\ioerror -> do
                       hPutStr stderr ("Couldn't write interface file "
                                       ++ sTypeFile fileflags ++ ":"
                                       ++ show ioerror ++ "\n")
                       exit)

  {-
  -- Fix syntax (small tweaks based on type information)
  -- optimisation: evaluation of `fromInteger' where possible
  -- Also removes data constructors defined by newtype.
  -}
  beginPhase "fixsyntax"
  (decls        -- :: [Decl Id]
   ,state       -- :: IntState
   ,t2i)        -- :: Tree (TokenId,Id)
        <- return (fixSyntax decls state tidFun)
  pF (sFixSyntax flags) "Declarations after fixSyntax"
          (prettyPrintId flags state ppTopDecls (DeclsParse decls))
  pF (sFSBound flags) "Symbol table after fixSyntax:"
          (mixLine (map show (Map.toList (getSymbolTable state))))


  {-
  -- Remove pattern matching: Change all pattern matches to case expressions.
  -- Go from Haskell syntax to STG language (PosLambda).
  -}
  beginPhase "case"
  (decls        -- :: [(Id,PosLambda)]
   ,state)      -- :: IntState
          <- return (caseTopLevel (if sPrelude flags
                                   then "Prelude:"++ sSourceFile fileflags
                                   else reverse (unpackPS (mrpsIS state)))
                                   t2i code decls state tidFun)
  case getErrorsIS state of
    Left errors ->
      pF True "Warning pattern removal" (mixLine errors)
    _ -> return ()
  pF (sCase flags) "Declarations after case:"
          (strPCode (strISInt state) decls)
  pF (sCBound flags) "Symbol table after case:"
          (mixLine (map show (Map.toList (getSymbolTable state))))


  {- Expand primitives -}
  beginPhase "prim"
  (decls        -- :: [(Id,PosLambda)]
   ,state)      -- :: IntState
          <- return (primCode primFlags True tidFun state decls)
  pF (sPrim flags) "Declarations after prim expand:"
          (strPCode (strISInt state) decls)
  pF (sPBound flags) "Symbol table after prim expand:"
          (mixLine (map show (Map.toList (getSymbolTable state))))


  {- Determine free variables (for lambda lifting) -}
  beginPhase "free"
  (decls        -- :: [(Id,PosLambda)]
   ,state)      -- :: IntState
          <- return (freeVar (sKeepCase flags) decls state)
  pF (sFree flags) "Declarations with explicit free variables:"
     (strPCode (strISInt state) decls)


  {- Do arity grouping on declarations (for lambda lifting) -}
  (decls        -- :: [(Id,PosLambda)]
   ,state)      -- :: IntState
          <- return (stgArity state decls)
  pF (sArity flags) "Declarations after first arity grouping"
     (strPCode (strISInt state) decls)


  {- Lambda lift, introduces thunks -}
  beginPhase "lift"
  (decls        -- :: [(Id,PosLambda)]
   ,state)      -- :: IntState
          <- return (liftCode decls state tidFun)
  pF (sLift flags) "Declarations after lambda lifting:"
     (strPCode (strISInt state) decls)
  pF (sLBound flags) "Symbol table after lambda lifting:"
     (mixLine (map show (Map.toList (getSymbolTable state))))

  {- Do arity grouping again -}
  (decls        -- :: [(Id,PosLambda)]
   ,state)      -- :: IntState
          <- return (stgArity state decls)
  pF (sArity flags) "Declarations after second arity grouping"
     (strPCode (strISInt state) decls)


  {- Pos Atom (applies field strictness information and possibly others) -}
  beginPhase "atom"
  (decls        -- :: [(Id,PosLambda)]
   ,state)      -- :: IntState
          <- return (posAtom state decls)
  pF (sAtom flags) "Declarations after atom:" (strPCode (strISInt state) decls)
  pF (sABound flags) "Symbol table after atom:"
     (mixLine (map show (Map.toList (getSymbolTable state))))

  {- Core outputting -}
  let importNames = [reverse $ unpackPS a | (a,b,c) <- imports, a /= rpsInternal]
  (core,coreImps) <- return $ makeCore importNames state zcon decls
  pF (sShowCore flags) "Human Readable Core" (show core)
  when (sGenCore flags) $ do
       let outfile = sCoreFile fileflags
       createDirectoryIfMissing True (takeDirectory outfile)
       saveCore outfile core

  if (sDotNet flags) then do
       {- Compile to DotNet IL -}
       (ilcode,
        state) <- return (ilCompile flags state decls zcon)
       writeFile (reverse ('l':'i':dropWhile (/='.') (reverse (sSourceFile fileflags)))) (strILCode ilcode)
   else when (not (sNoBytecode flags)) $ do
       {- Compile to BCode -}
       bcode <- return (bcCompile flags state coreImps core)
       bcOutput flags fileflags state bcode

-- | begin a phase
beginPhase :: (Monad m) => t -> m ()
beginPhase str = return ()

-- some miscellaneous settings
primFlags :: (Bool, Bool, Bool)
primFlags = (False   -- bool is not the same as Word
            ,False   -- && || not is not primitive
            ,False   -- translate into prim only when strict
            )

-- temporary, until errors as strings are removed
catchErrorStr :: Either [String] a -> String -> IO a
catchErrorStr (Left  xs) msg = catchError (Left (map ErrorRaw xs)) msg
catchErrorStr (Right xs) msg = catchError (Right xs) msg

-- some nicer error handling
catchError :: Either [Error] a -> String -> IO a
catchError comp msg = do
    case comp of
        Left errs -> raiseErrors msg errs
        Right a   -> return a


catchError2 :: Either err res -> (err -> String) -> IO res
catchError2 (Left err)  f = do hPutStr stderr (f err)
                               exit
catchError2 (Right res) f = return res



{- Parse interface files for imported modules -}
nhcImport :: Flags
          -> ImportState
          -> Map.Map String FilePath
          -> [( PackedString
              , (PackedString, PackedString, Set.Set TokenId)
                  -> [[TokenId]] -> Bool
              , HideDeclIds
              )]
          -> IO ImportState

nhcImport flags importState hiDeps [] = do
  --beginPhase "import []"
  pF (sINeed flags) "Need after all imports"
             (show (Set.toList (thd3 (getNeedIS importState))))
  pF (sIBound flags) "Symbol table after import"
             (mixLine (map show (Map.toList (getSymbolTableIS importState))))
  pF (sIRename flags) "Rename table after import"
             (mixLine (map show (Map.toList (getRenameTableIS importState))))
  catchError (getErrIS importState) "importing module"
  return importState

nhcImport flags importState hiDeps (x:xs) =
  {-trace ("import:" ++ (reverse . show . fst3) x) $ -} do
  --beginPhase ("import:" ++ (reverse . show . fst3) x)
  let fname = (reverse . unpackPS . (\(y,_,_)->y)) x
  importState <- importOne flags importState hiDeps x
  pF (sIINeed flags) ("Intermediate need after import "++fname)
       (show (Set.toList (thd3 (getNeedIS importState))))
  pF (sIIBound flags) ("Intermediate symbol table after import "++fname)
       (mixLine (map show (Map.toList (getSymbolTableIS importState))))
  pF (sIIRename flags) ("Intermediate rename table after import "++fname)
       (mixLine (map show (Map.toList (getRenameTableIS importState))))
  nhcImport flags importState hiDeps xs

---   Small help functions

strISInt :: IntState -> (Id -> String, Id -> Int)
strISInt state = (\v -> strIS state v ++ "{"++show v++"}", \v -> arityIS state v)


strISBC :: IntState -> Id -> String
strISBC state v = case lookupIS state v of
                      Just info -> let (md,id) = splitM (tidI info)
                                   in md ++ ";"++id
                      Nothing   -> "v" ++ show v

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.