% % (c) The Foo Project, University of Glasgow, 1998 % % @(#) $Docid: Feb. 8th 2003 07:20 Sigbjorn Finne $ % @(#) $Contactid: sof@galois.com $ % Pass to construct import lists from a list of Haskell declarations. \begin{code}
module MkImport 
       (
        mkImportLists
       ) where

import AbstractH
import AbsHUtils ( ieType, andDecls, ieValue, mkQVarName, tyInt32Name )
import Bag
import Env
import LibUtils  ( bitsLib, prelude, fromEnumName, toEnumName )
import BasicTypes

import List   ( nub )
import Opts   ( optNoImportLists, optQualInstanceMethods, optNoQualNames,
		optLongLongIsInteger )
import Utils  ( concMaybe )
\end{code} \begin{code}
mkImportLists :: String
              -> [QualName]
	      -> [HDecl]
	      -> [(String, Bool, [HIEEntity])]
mkImportLists local_nm hs_imports decls = import_list
  where
   import_list = 
		    -- sigh, to avoid pointless trouble with the generated
		    -- sources due to Hugs' lack of support for qualified
		    -- instance names, we optionally allow method names
		    -- to be emitted in unqual'ed form. GHC (quite rightfully)
		    -- complains when it is fed such input, since it has
		    -- only got the qualified method name in scope.
		    --
		    -- To avoid the unfortunate situation that GHC and Hugs
		    -- require separate Haskell stubs for normal stuff, we
		    -- explicitly bring the unqual'ed Enum instance methods
		    -- into scope.
		    --
		    -- A hack that doesn't solve the general problem.
		    -- 
   		 (if not optQualInstanceMethods && not optNoQualNames then 
		     (("Prelude", False, [ ieValue (qName fromEnumName)
		     			 , ieValue (qName toEnumName)
					 ]):)
		  else
		     id) $
		 ("Prelude", True, []):
   		 filter ofInterest (map mkImpList (envToList (go (andDecls decls) new_env )))

   new_env
     | optLongLongIsInteger = addQName (\ nm -> ieType nm False) tyInt32Name base_env
     | otherwise	    = base_env

   base_env = foldr (addQName ieValue) newEnv hs_imports

   ofInterest ("Prelude",_,_) = False
   ofInterest (nm, _, _)      = nm /= local_nm

   mkImpList (x, bag)	    = (x, True, nub (bagToList bag))

   go :: HDecl -> Env String (Bag HIEEntity) -> Env String (Bag HIEEntity)
   go (AndDecl d1 d2)	         env = go d2 (go d1 env)
   go (TypeSig _ ctxt ty)        env = gatherTyImports ty (gatherTyContext ctxt env)
   go (ValDecl _ _ es)	         env = foldr gatherGExprImports env es
   go (TyD td)		         env = gatherTyDeclImports td env
   go (Primitive _ _ _ _ ty _ _ _) env = gatherTyImports ty env
   go (PrimCast _ _ ty _ _ _ )     env = gatherTyImports ty env
   go (Entry _ _ _ ty)           env = gatherTyImports ty env
   go (Callback _ _ ty)          env = gatherTyImports ty env
   go (ExtLabel _ _ ty)          env = gatherTyImports ty env
   go (Instance ctxt cname t ds) env =
       gatherTyContext (Just ctxt) $
       addQName (\ nm -> ieType nm False) cname $
       gatherTyImports t $
       foldr go env ds
   go _                        env = env

gatherTyImports :: Type -> Env String (Bag HIEEntity) -> Env String (Bag HIEEntity)
gatherTyImports ty env = 
 case ty of
   TyVar _ tv     -> addQName (\ nm -> ieType nm True) tv env 
   TyCon tc	  -> addQName (\ nm -> ieType nm True) tc env 
   TyApply f args -> foldr gatherTyImports env (f:args)
   TyList t	  -> gatherTyImports t env
   TyTuple es	  -> foldr gatherTyImports env es
   TyCtxt c t     -> gatherTyContext (Just c) (gatherTyImports t env)
   TyFun f a	  -> gatherTyImports a (gatherTyImports f env)

addQName :: (String -> a) -> QualName -> Env String (Bag a) -> Env String (Bag a)
addQName f qn env = 
   case concMaybe (qDefModule qn) (qModule qn) of
     Nothing  -> env
     v@(Just md)
	    -- don't record what we're picking up from the Prelude.
        | v == prelude -> env  
	| otherwise    -> addToEnv_C (unionBags) env md nm
       where
        nm 
	 | optNoImportLists = emptyBag
	 | otherwise        = unitBag (f (qName qn))

gatherTyDeclImports :: TyDecl -> Env String (Bag HIEEntity) -> Env String (Bag HIEEntity)
gatherTyDeclImports (TypeSyn _ _ t) env     = gatherTyImports t env
gatherTyDeclImports (TyDecl _ _ _ ds _) env = foldr gatherConDeclImport env ds
 where
  gatherConDeclImport (ConDecl _ ts) env1 = foldr gatherTyImports env1 (map debang ts)
  gatherConDeclImport (RecDecl _ fs) env1 = foldr gatherTyImports env1 (map (debang.snd) fs)
  
  debang (Banged t)   = t
  debang (Unbanged t) = t


gatherTyContext :: Maybe Context -> Env String (Bag HIEEntity) -> Env String (Bag HIEEntity)
gatherTyContext Nothing env = env
gatherTyContext (Just ctxt) env = go ctxt env
  where
   go (CtxtClass nm _) env1 = addQName (\ n -> ieType n True) nm env1
   go (CtxtTuple ls)   env1 = foldr go env1 ls

gatherGExprImports :: GuardedExpr -> Env String (Bag HIEEntity) -> Env String (Bag HIEEntity)
gatherGExprImports (GExpr es e) env = foldr gatherExprImports env (e:es)

gatherExprImports :: Expr -> Env String (Bag HIEEntity) -> Env String (Bag HIEEntity)
gatherExprImports e env =
 case e of
   Lam _ e1 -> gatherExprImports e1 env
   Apply f args -> foldr gatherExprImports env (f:args)
   Tup es -> foldr gatherExprImports env es
   List es -> foldr gatherExprImports env es
   BinOp bop e1 e2  -> gatherExprImports e2 (gatherExprImports e1 (gatherBinOpImports bop env))
   InfixOp e1 op e2 -> gatherExprImports e1 (gatherExprImports e2 (addQName (ieValue) op env))
   RApply e1 e2  -> gatherExprImports e1 (gatherExprImports e2 env)
   UnOp op e1    -> gatherExprImports e1 (gatherUnaryOpImports op env)
   Bind e1 _ e2  -> gatherExprImports e2 (gatherExprImports e1 env)
   Bind_ e1 e2   -> gatherExprImports e2 (gatherExprImports e1 env)
   Return e1     -> gatherExprImports e1 env
   Case e1 alts  -> foldr gatherAltImports (gatherExprImports e1 env) alts
   If e1 e2 e3   -> gatherExprImports e1 (gatherExprImports e2 (gatherExprImports e3 env))
   Let binds e1  -> foldr gatherBindingImports (gatherExprImports e1 env) binds
   Var v 	 -> addQName (ieValue) v env 
   Con c	 -> addQName (ieValue) c env
   WithTy e1 ty  -> gatherExprImports e1 (gatherTyImports ty env)
   _		 -> env

   where
     gatherBindingImports (Binder _ e1) env1 = gatherExprImports e1 env1

     gatherAltImports (Alt _ gs) env1    = foldr gatherExprImports env1 es
       where
        es = concatMap (\ (GExpr gs1 e1) -> e1:gs1) gs
     gatherAltImports (Default _ e1) env1 = gatherExprImports e1 env1


     gatherUnaryOpImports op env1 =
        case op of
	  Not -> addBitsImp "complement" env1
	  _   -> env1

     gatherBinOpImports op env1 =
        case op of
	  Xor -> addBitsImp "xor" env1
	  Or  -> addBitsImp "(.|.)" env1
	  And -> addBitsImp "(.&.)" env1
	  Shift L -> addBitsImp "shiftL" env1
	  Shift R -> addBitsImp "shiftR" env1
	  _ -> env1
	  
	  
     addBitsImp nm env1 = addQName ieValue (mkQVarName bitsLib nm) env1

\end{code}