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

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


{- ---------------------------------------------------------------------------
Perform "need" analysis (which imported entities are required?) 
-}
module Need(Flags,Module,TokenId,NeedTable,HideDeclIds,PackedString,IdKind
           ,needProg) where

import qualified Data.Map as Map
import qualified Data.Set as Set
import Reduce
import NeedLib(NeedLib,initNeed,needit,popNeed,pushNeed,bindTid,needTid
              ,NeedTable,needQualify)
import Syntax
import IdKind
import PreImport(HideDeclIds,qualRename,preImport)
import TokenId
import TokenInt
import Flags(Flags)
import SyntaxPos
import Util.Extra
import SyntaxUtil(infixFun)

import Overlap(Overlap)
import Info(IE)
import SysDeps(PackedString)


needProg :: Flags
         -> Module TokenId
         -> ( NeedTable
            , TokenId -> [TokenId]
            , Overlap
            , Either [Char] 
                ( (TokenId->Bool) -> TokenId -> IdKind -> IE
                , [ ( PackedString
                    , (PackedString, PackedString, Set.Set TokenId)
                         -> [[TokenId]] -> Bool
                    , HideDeclIds
                    )
                  ]
                )
            )

needProg flags n@(Module pos modidl exports impdecls fixdecls topdecls) =
  let qualFun = qualRename modidl impdecls
  in case needit (needModule n) qualFun (initNeed (modidl == tMain)) of
       (need,overlap) -> ( need
                         , qualFun
                         , overlap
                         , preImport flags modidl
                                     (Set.fromList [i | ((i,_),_) <- Map.toList need])
                                     exports impdecls
                         )


needModule :: Module TokenId -> NeedLib -> NeedLib

needModule (Module pos modid exports imports fixdecls topdecls) =
      pushNeed >>>
      bindDataDecls topdecls >>>
      bindDecls topdecls >>>
      pushNeed >>>
      bindTid Modid modid >>>
      mapR bindImport imports >>>
      ( case exports of
          Nothing   -> unitR
          Just exps -> mapR needExport exps ) >>>
      popNeed >>>
      mapR needImport imports >>>
      mapR needFixDecl fixdecls >>>
      needDecls topdecls >>>
      popNeed


-- ------------------------------


needExport :: Export TokenId -> NeedLib -> NeedLib
needExport  (ExportEntity  pos entity) =
    needEntity id entity
needExport  (ExportModid   pos hs) =
    needTid pos Modid hs


needEntity :: (TokenId->TokenId) -> Entity TokenId -> NeedLib -> NeedLib
needEntity q (EntityVar pos hs) =               -- varid
    needTid pos Var (q hs)
needEntity q (EntityConClsAll pos hs) =         -- TyCon(..) | TyCls(..)
    needTid pos TC (q hs)
needEntity q (EntityConClsSome pos hs posidents) = -- TC | TC(id0,id1,...)
    needTid pos TC (q hs)
    >>> needPosIdents q posidents

needPosIdents :: (TokenId->TokenId) -> [(Pos,TokenId)] -> NeedLib -> NeedLib
needPosIdents q posidents = 
    if any (isTidCon.snd) posidents then
         mapR (\(pos,tid) -> if isTidCon tid then needTid pos Con (q tid)
                                             else needTid pos Field (q tid))
              posidents
    else mapR (\(pos,tid) -> needTid pos Method (q tid)) posidents
                                -- could really be Method or Field.

-----------------------------------

--needImport (Import (pos,tid) impspec) =
--    {- needTid pos Modid tid >>> -} needImpSpec impspec
--needImport (ImportQ (pos,tid)) =
--    unitR -- needTid pos Modid tid
--needImport (ImportQas (pos,tid) (pos2,tid2)) =
--    unitR -- needTid pos Modid tid


needImport :: ImpDecl TokenId -> NeedLib -> NeedLib
needImport (Import (pos,tid) impspec) = needImpSpec id impspec
needImport (Importas (pos,tid) (pos2,tid2) impspec) = needImpSpec id impspec
needImport (ImportQ (pos,tid) impspec) =
    needImpSpec (ensureM (extractV tid)) impspec
needImport (ImportQas (pos,tid) (pos2,tid2) impspec) =
    needImpSpec (ensureM (extractV tid)) impspec


needImpSpec :: (TokenId->TokenId) -> ImpSpec TokenId -> NeedLib -> NeedLib
needImpSpec q (NoHiding entities) = mapR (needEntity q) entities
needImpSpec q (Hiding entities)   = unitR

-----------------------------------

needFixDecl :: (InfixClass TokenId,a,[FixId TokenId]) -> NeedLib -> NeedLib
needFixDecl (InfixPre tid,level,posidents) =
  needTid (getPos (head posidents)) Var tid >>> mapR needFixId posidents
needFixDecl (typeClass,level,posidents) = 
  mapR needFixId posidents


needFixId :: FixId TokenId -> NeedLib -> NeedLib
needFixId (FixCon pos tid) = needTid pos Con tid
needFixId (FixVar pos tid) = needTid pos Var tid

-----------------------------------

needDecls (DeclsParse decls)   = mapR needDecl decls

--        type   simple  = type
needDecl (DeclType simple typ) =
     pushNeed
  >>> needSimple TSyn simple
  >>> needType typ
  >>> popNeed

--        data primitive type = size
needDecl (DeclDataPrim pos tid size) = 
  unitR

--        data context => simple = constrs deriving (tycls)
needDecl (DeclData b ctxs simple constrs posidents) =
     mapR needCtx ctxs
  >>> mapR needConstr constrs
  >>> mapR needDeriving posidents
  >>> unitR             -- needTids (getPos simple) tokenEval


--        class context => class where { csign; valdef }
needDecl (DeclClass pos tctxs tClass tTVars fundeps (DeclsParse decls)) =
     pushNeed
  >>> mapR (bindTid TVar) tTVars
  >>> mapR needCtx tctxs
  >>> mapR needClassInst decls
  >>> popNeed

--        instance context => tycls inst where { valdef }
needDecl (DeclInstance pos ctxs tClass insts (DeclsParse decls)) =
     mapR needCtx ctxs
  >>> mapR needType insts
  >>> mapR needClassInst (map (needQualify tClass) decls)
  >>> needTid pos TClass tClass

--        default (type,..)
needDecl (DeclDefault types) =
     mapR needType types

--      vars :: context => type
needDecl (DeclVarsType posidents ctxs typ) =
     mapR (\ (pos,tid) -> needTid pos Var tid) posidents
  >>> mapR needCtx ctxs
  >>> needType typ

needDecl (DeclPat (Alt pat@(ExpInfixList pos pats) rhs decls)) =
      pushNeed
  >>> bindPat pat   -- Also generate need for constructors
  >>> needExp pat
  >>> bindDecls decls
  >>> needRhs rhs
  >>> needDecls decls
  >>> popNeed

needDecl (DeclPat (Alt pat rhs decls)) =
     needExp pat
  >>> bindDecls decls
  >>> needRhs rhs
  >>> needDecls decls

needDecl (DeclFun pos hs funs) =
      mapR needFun funs
needDecl (DeclPrimitive pos hs arity t) =
      needType t
needDecl (DeclForeignImp pos _ _ hs arity cast t _) =
      needType t
  >>> needTids pos tokenFFI
needDecl (DeclForeignExp pos _ _ hs typ) =
      needTid pos Var hs
  >>> needType typ
  >>> needTids pos tokenFFI
   -- error ("\nAt "++ strPos pos ++ ", foreign export not supported.")
needDecl (DeclFixity f) =
      needFixDecl f

--     Used for unimplemented things
needDecl d@(DeclIgnore str) = unitR
needDecl d@(DeclError str) = unitR
needDecl (DeclAnnot decl annots) = unitR


needDeriving (pos,tid)
        | (ensureM rpsPrelude tid) == tBounded =
                         needTid pos TClass tid >>> needTids pos tokenBounded
        | (ensureM rpsPrelude tid) == tEnum    =
                         needTid pos TClass tid >>> needTids pos tokenEnum
        | (ensureM rpsPrelude tid) == tEq      =
                         needTid pos TClass tid >>> needTids pos tokenEq
        | (ensureM rpsIx tid) == tIx           =
                         needTid pos TClass tid >>> needTids pos tokenIx
        | (ensureM rpsPrelude tid) == tOrd     =
                         needTid pos TClass tid >>> needTids pos tokenOrd
        | (ensureM rpsPrelude tid) == tRead    =
                         needTid pos TClass tid >>> needTids pos tokenRead
        | (ensureM rpsPrelude tid) == tShow    =
                         needTid pos TClass tid >>> needTids pos tokenShow
        | (ensureM rpsBinary tid)  == tBinary  =
                         needTid pos TClass tid >>> needTids pos tokenBinary
        | True = strace ("Warning: Don't know what is needed to derive "
                                 ++ show tid ++ " at " ++ strPos pos ++"\n")
                 (needTid pos TClass tid)

needClassInst (DeclVarsType posidents ctxs typ) =
     mapR needCtx ctxs
  >>> needType typ
needClassInst (DeclPat (Alt (ExpVar pos fun) rhs decls)) =
      needTid pos Method fun
  >>> needFun (Fun [] rhs decls)
needClassInst (DeclPat (Alt (ExpInfixList pos es) rhs decls)) =
  case infixFun es of
    Just (pat1,pos',fun',pat2) ->
         needTid pos Method fun'
      >>> pushNeed
      >>> bindPat pat1 >>> bindPat pat2
      >>> bindDecls decls  
      >>> needExp pat1 >>> needExp pat2
      >>> needRhs rhs
      >>> needDecls decls
      >>> popNeed
    Nothing ->
      error ("Sorry (infix) lhs-patterns doesn't work in instances " ++ strPos pos)
needClassInst (DeclPat (Alt pat gdexps decls)) =
  error ("Sorry lhs-patterns doesn't work in instances " ++ strPos (getPos pat))
needClassInst (DeclFun pos fun funs) =
     needTid pos Method fun
  >>> mapR needFun funs
needClassInst (DeclAnnot decl annots) =
     needClassInst decl
needClassInst (DeclFixity fixdecl) =
     needFixDecl fixdecl

needFun (Fun pats rhs decls) =
     pushNeed
  >>> mapR bindPat pats  -- Also generate need for constructors
  >>> bindDecls decls
  >>> needRhs rhs
  >>> needDecls decls
  >>> popNeed



needRhs (Unguarded exp) = needExp exp
needRhs (PatGuard gdexps) = mapR needPatGdExp gdexps

needPatGdExp (quals,exp) = needQuals quals >>> needExp exp


needAlt (Alt pat rhs decls) =
     pushNeed
  >>> bindPat pat  -- Also generate need for constructors
  >>> bindDecls decls
  >>> needExp pat
  >>> needRhs rhs
  >>> needDecls decls
  >>> popNeed

needType (TypeApp t1 t2) = needType t1 >>> needType t2
needType (TypeCons  pos hs types) = needTid pos TCon hs >>> mapR needType types
needType (TypeVar   pos hs)       = unitR
needType (TypeStrict pos typ)     = needType typ

needSimple kind (Simple pos hs posidents) = needTid pos kind hs -- posidents are typevariables!

needCtx (Context pos hs _) = needTid pos TClass hs

needConstr (Constr                pos hs types) = mapR needFieldType types
needConstr (ConstrCtx forAll ctxs pos hs types) = mapR needCtx ctxs >>> mapR needFieldType types

needFieldType (_,typ) = needType typ

needStmts [] = unitR
needStmts (StmtExp exp:[]) = needExp exp
needStmts (StmtExp exp:r) = needTid (getPos exp) Var t_gtgt >>>  needExp exp >>> needStmts r
needStmts (StmtBind pat exp:r) = needTid (getPos pat) Var t_gtgteq >>> needExp exp >>> pushNeed >>> bindPat pat >>> needStmts r >>> popNeed
needStmts (StmtLet decls :r) =  pushNeed  >>> bindDecls decls  >>> needDecls decls >>> needStmts r >>> popNeed

-- for list comprehensions and pattern guards
needQuals [] = unitR
needQuals (QualExp exp:r)  = needExp exp >>> needQuals r
needQuals (QualPatExp pat exp:r) =
    needExp exp >>> bindPat pat >>> needExp pat >>> needQuals r
needQuals (QualLet decls :r) =
    bindDecls decls >>> needDecls decls >>> needQuals r


needField (FieldExp pos var exp) = needTid pos Field var >>> needExp exp
needField (FieldPun pos var) = needTid pos Field var >>> needTid pos Var var
--needField (FieldPun pos var) = error ("\nAt "++ strPos pos ++ ", token: "++
--      show var ++
--      "\nPunning of named fields has been removed from the Haskell language."++
--      "\nUse "++show var++"="++show var++" instead.")


needExp :: Exp TokenId -> NeedLib -> NeedLib

needExp (ExpScc            str exp) =  needExp exp
needExp (ExpLambda         pos pats exp) =
     pushNeed  >>> mapR bindPat pats  >>> needExp exp  >>> popNeed
needExp (ExpDo            pos stmts) = needTids pos tokenMonad >>> needStmts stmts
needExp (ExpLet            pos decls exp) =
     pushNeed  >>> bindDecls decls  >>> needDecls decls >>> needExp exp  >>> popNeed
needExp (ExpCase           pos exp alts) =  needExp exp  >>> mapR needAlt alts
needExp (ExpIf             pos expCond expThen expElse) =
     needExp expCond >>> needExp  expThen >>> needExp expElse
needExp (ExpRecord exp fields) = needExp exp >>> mapR needField fields
needExp (ExpType           pos exp ctxs typ) =
    needExp exp >>> mapR needCtx ctxs >>> needType typ
needExp (ExpListComp       pos exp quals) =
    needTids pos tokenComprehension >>>
    pushNeed >>> needQuals quals >>> needExp exp >>> popNeed
needExp (ExpListEnum       pos eFrom meThen meTo) =
    needTids pos tokenEnum >>>
    needExp eFrom >>> maybe unitR needExp meThen >>> maybe unitR needExp meTo
needExp (ExpBrack          pos exp) = needExp exp
--- Above only in expressions
needExp (ExpApplication   pos exps) = mapR needExp exps
needExp (ExpInfixList     pos exps) = mapR needExp exps
needExp (ExpVar           pos tid)  = needTid pos Var tid
needExp (ExpCon           pos tid)  = needTid pos Con tid
needExp (ExpVarOp         pos tid)  = needTid pos Var tid
needExp (ExpConOp         pos tid)  = needTid pos Con tid
needExp e@(ExpLit         pos (LitInteger  _ _)) = needTids pos tokenInteger
needExp e@(ExpLit         pos (LitRational _ _)) = needTids pos tokenRational
needExp e@(ExpLit         pos lit)  = unitR
needExp (ExpList          pos exps) = mapR needExp exps
--- Below only in patterns
needExp (PatAs            pos hs pat) = needTid pos Var hs >>> needExp pat
needExp (PatWildcard      pos)        = unitR
needExp (PatIrrefutable    pos pat)   = needExp pat
needExp (PatNplusK        pos tid _ _ _ _) = needTid pos Var tid >>>
                                             needTids pos tokenNplusK


----------- ========================


bindImport :: ImpDecl TokenId -> NeedLib -> NeedLib

bindImport (Import (pos,tid) impspec) =
    bindTid Modid tid
bindImport (ImportQ (pos,tid) impspec) =
    bindTid Modid tid
bindImport (ImportQas (pos,tid) (pos2,tid2) impspec) =
    bindTid Modid tid >>> bindTid Modid tid2
bindImport (Importas (pos,tid) (pos2,tid2) impspec) =
    bindTid Modid tid >>> bindTid Modid tid2


-- Hack to enforce that constructors are bound before need is checked
bindDataDecls :: Decls TokenId -> NeedLib -> NeedLib

bindDataDecls (DeclsParse decls)   = mapR bindDataDecl decls

bindDataDecl (DeclType (Simple pos tid posidents) typ) =  bindTid TSyn tid
bindDataDecl (DeclDataPrim pos tid size) = bindTid TCon tid
bindDataDecl (DeclData b ctxs (Simple pos tid posidents) constrs _) = 
  bindTid TCon tid >>> mapR bindConstr constrs
bindDataDecl _ = unitR

{-
Binds defined class identifiers and term variables,
not type constructors or data constructors, that is,
stores them in a memo inside needLib.
Used both in renaming and need analysis phase.
-}
bindDecls :: Decls TokenId -> NeedLib -> NeedLib

bindDecls (DeclsParse decls)   = mapR bindDecl decls


bindDecl :: Decl TokenId -> Reduce NeedLib NeedLib

bindDecl (DeclType (Simple pos tid posidents) typ) =  unitR 
  -- ABOVE: bindTid TSyn tid
bindDecl (DeclDataPrim pos tid size) = unitR -- bindTid TCon tid
bindDecl (DeclData b ctxs (Simple pos tid posidents) constrs _) = unitR 
  -- ABOVE: bindTid TCon tid >>> mapR bindConstr constrs
bindDecl (DeclClass pos tctxs tClass tTVars fundeps (DeclsParse decls)) = 
  bindTid TClass tClass >>> mapR bindClass decls
bindDecl (DeclInstance pos ctxs tClass inst (DeclsParse decls)) = unitR
bindDecl (DeclDefault types) = unitR
bindDecl (DeclVarsType posidents ctxs typ) = unitR
bindDecl (DeclPat (Alt pat@(ExpInfixList pos pats) _ _)) =
    case filter isVarOp pats of
        [ExpVarOp pos tid] -> bindTid Var tid
        [] -> bindPat pat
        _ -> error (show pos ++ ": (n+k) patterns are not supported\n")
bindDecl (DeclPat (Alt pat gdexps decls)) = bindPat pat  
  -- ABOVE: Also generate need for constructors
bindDecl (DeclPrimitive pos tid arity t) = bindTid Var tid
bindDecl (DeclForeignImp pos _ _ tid arity cast t _) = bindTid Var tid
bindDecl (DeclForeignExp pos _ _ tid t) = unitR
bindDecl (DeclFun pos tid funs) = bindTid Var tid
bindDecl d@(DeclIgnore str) = unitR
bindDecl d@(DeclError str) = unitR
bindDecl (DeclAnnot decl annots) = unitR
bindDecl (DeclFixity f) = unitR


bindConstr :: Constr TokenId -> NeedLib -> NeedLib

bindConstr (Constr                pos hs ftypes) = 
  bindTid Con hs >>> mapR bindFieldType ftypes
bindConstr (ConstrCtx forAll ctxs pos hs ftypes) = 
  bindTid Con hs >>> mapR bindFieldType ftypes

bindFieldType (Nothing,_) = unitR
bindFieldType (Just posidents,_) = 
  mapR ( \ (p,v) -> bindTid Var v >>> bindTid Field v) posidents


bindClass :: Decl TokenId -> NeedLib -> NeedLib

bindClass (DeclVarsType posidents ctxs typ) = 
  mapR (bindTid Method . snd) posidents
bindClass _ = unitR


bindField :: Field TokenId -> NeedLib -> NeedLib

bindField (FieldExp pos var pat) = 
  needTid pos Field var >>> needTid pos Var var >>> bindPat pat
bindField (FieldPun pos var) = needTid pos Field var >>> bindTid Var var
--bindField (FieldPun pos var) = error ("\nAt "++ strPos pos ++ ", token: "++
--      show var ++
--      "\nPunning of named fields has been removed from the Haskell language."++
--      "\nUse "++show var++"="++show var++" instead.")

--- Above only in expressions

bindPat :: Exp TokenId -> NeedLib -> NeedLib

bindPat (ExpBrack         pos exp)  = bindPat exp
bindPat (ExpApplication   pos exps) = mapR bindPat exps
bindPat (ExpInfixList     pos (ExpVarOp _ op:pats)) = -- must be prefix -
  needTid pos Var op >>> mapR bindPat pats
bindPat (ExpInfixList     pos exps) = mapR bindPat exps
bindPat (ExpVar           pos tid)  = bindTid Var tid
bindPat (ExpCon           pos tid)  = needTid pos Con tid
bindPat (ExpVarOp         pos tid)  = bindTid Var tid
bindPat (ExpConOp         pos tid)  = needTid pos Con tid
bindPat e@(ExpLit         pos (LitInteger  _ _)) = 
  needTid pos Var t_equalequal >>> needTids pos tokenInteger
bindPat e@(ExpLit         pos (LitRational _ _)) = 
  needTid pos Var t_equalequal >>> needTids pos tokenRational
bindPat e@(ExpLit         pos lit)  = unitR

bindPat (ExpList          pos exps) = mapR bindPat exps
bindPat (ExpRecord pat fields) = 
  bindPat pat >>> mapR bindField fields   -- pat is alwasy ExpCon
--- Below only in patterns
bindPat (PatAs            pos hs pat) = bindTid Var hs >>> bindPat pat
bindPat (PatWildcard      pos)        = unitR
bindPat (PatIrrefutable   pos pat)    = bindPat pat
bindPat (PatNplusK        pos tid _ _ _ _) = bindTid Var tid >>>
                                             needTids pos tokenNplusK
bindPat pat = error ("Need.hs:bindPat @ "++show (getPos pat))

------
needTids :: Pos -> [(IdKind,TokenId)] -> NeedLib -> NeedLib
needTids pos kindtids = mapR (uncurry (needTid pos)) kindtids


isVarOp :: Exp a -> Bool
isVarOp (ExpVarOp _ _) = True
isVarOp _ = False


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.