[project @ 1999-06-17 09:51:16 by simonmar]
[ghc-hetmet.git] / ghc / compiler / deSugar / DsForeign.lhs
index a151d44..b6abdbf 100644 (file)
@@ -22,13 +22,14 @@ import TcHsSyn              ( TypecheckedForeignDecl )
 import CoreUtils       ( coreExprType )
 import Const           ( Con(..), mkMachInt )
 import DataCon         ( DataCon, dataConId )
-import Id              ( Id, idType, idName, 
-                         mkIdVisible, mkWildId
-                       )
+import Id              ( Id, idType, idName, mkWildId, mkVanillaId )
 import Const           ( Literal(..) )
-import Name            ( getOccString, NamedThing(..) )
-import PrelVals                ( realWorldPrimId )
-import PrelInfo                ( deRefStablePtr_NAME, bindIO_NAME, makeStablePtr_NAME )
+import Module          ( Module )
+import Name            ( mkGlobalName, nameModule, nameOccName, getOccString, 
+                         mkForeignExportOcc, isLocalName,
+                         NamedThing(..), Provenance(..), ExportFlag(..)
+                       )
+import PrelInfo                ( deRefStablePtr_NAME, bindIO_NAME, makeStablePtr_NAME, realWorldPrimId )
 import Type            ( splitAlgTyConApp_maybe, 
                          splitTyConApp_maybe, splitFunTys, splitForAllTys,
                          Type, mkFunTys, mkForAllTys, mkTyConApp,
@@ -46,25 +47,28 @@ import Outputable
 
 Desugaring of @foreign@ declarations is naturally split up into
 parts, an @import@ and an @export@  part. A @foreign import@ 
-declaration 
-
+declaration
+\begin{verbatim}
   foreign import cc nm f :: prim_args -> IO prim_res
-
+\end{verbatim}
 is the same as
-
+\begin{verbatim}
   f :: prim_args -> IO prim_res
   f a1 ... an = _ccall_ nm cc a1 ... an
-
+\end{verbatim}
 so we reuse the desugaring code in @DsCCall@ to deal with these.
 
 \begin{code}
-dsForeigns :: [TypecheckedForeignDecl] 
+dsForeigns :: Module
+           -> [TypecheckedForeignDecl] 
           -> DsM ( [CoreBind]        -- desugared foreign imports
                   , [CoreBind]        -- helper functions for foreign exports
-                 , SDoc              -- Header file prototypes for "foreign exported" functions.
-                 , SDoc              -- C stubs to use when calling "foreign exported" funs.
+                 , SDoc              -- Header file prototypes for
+                                      -- "foreign exported" functions.
+                 , SDoc              -- C stubs to use when calling
+                                      -- "foreign exported" functions.
                  )
-dsForeigns fos = foldlDs combine ([],[],empty,empty) fos
+dsForeigns mod_name fos = foldlDs combine ([],[],empty,empty) fos
  where
   combine (acc_fi, acc_fe, acc_h, acc_c) fo@(ForeignDecl i imp_exp _ ext_nm cconv _) 
     | isForeignImport =   -- foreign import (dynamic)?
@@ -74,11 +78,11 @@ dsForeigns fos = foldlDs combine ([],[],empty,empty) fos
         dsFLabel i ext_nm `thenDs` \ b -> 
        returnDs (b:acc_fi, acc_fe, acc_h, acc_c)
     | isDynamic ext_nm =
-        dsFExportDynamic i (idType i) ext_nm cconv  `thenDs` \ (fi,fe,h,c) -> 
+        dsFExportDynamic i (idType i) mod_name ext_nm cconv  `thenDs` \ (fi,fe,h,c) -> 
        returnDs (fi:acc_fi, fe:acc_fe, h $$ acc_h, c $$ acc_c)
 
     | otherwise               =  -- foreign export
-        dsFExport i (idType i) ext_nm cconv False   `thenDs` \ (fe,h,c) ->
+        dsFExport i (idType i) mod_name ext_nm cconv False   `thenDs` \ (fe,h,c) ->
        returnDs (acc_fi, fe:acc_fe, h $$ acc_h, c $$ acc_c)
    where
     isForeignImport = 
@@ -97,7 +101,7 @@ dsForeigns fos = foldlDs combine ([],[],empty,empty) fos
 
 Desugaring foreign imports is just the matter of creating a binding
 that on its RHS unboxes its arguments, performs the external call
-(using the CCallOp primop), before boxing the result up and returning it.
+(using the @CCallOp@ primop), before boxing the result up and returning it.
 
 \begin{code}
 dsFImport :: Id
@@ -162,7 +166,7 @@ dsFImport nm ty may_not_gc ext_name cconv =
                      [Type io_res_ty, Var ds]
 
       fo_rhs = mkLams (tvs ++ args)
-                     (Let (NonRec ds (the_body::CoreExpr)) io_app)
+                     (mkDsLet (NonRec ds (the_body::CoreExpr)) io_app)
     in
     returnDs (NonRec nm fo_rhs)
 \end{code}
@@ -199,13 +203,21 @@ dsFLabel nm ext_name = returnDs (NonRec nm fo_rhs)
 
 \end{code}
 
-The function that does most of the work for 'foreign export' declarations.
-(see below for the boilerplate code a 'foreign export' declaration expands
+The function that does most of the work for `@foreign export@' declarations.
+(see below for the boilerplate code a `@foreign export@' declaration expands
  into.)
 
+For each `@foreign export foo@' in a module M we generate:
+\begin{itemize}
+\item a C function `@foo@', which calls
+\item a Haskell stub `@M.$ffoo@', which calls
+\end{itemize}
+the user-written Haskell function `@M.foo@'.
+
 \begin{code}
 dsFExport :: Id
          -> Type               -- Type of foreign export.
+         -> Module
          -> ExtName
          -> CallConv
          -> Bool               -- True => invoke IO action that's hanging off 
@@ -214,8 +226,21 @@ dsFExport :: Id
                 , SDoc
                 , SDoc
                 )
-dsFExport i ty ext_name cconv isDyn =
-     newSysLocalDs  helper_ty                          `thenDs` \ f_helper ->
+dsFExport i ty mod_name ext_name cconv isDyn =
+     getUniqueDs                                       `thenDs` \ uniq ->
+     getSrcLocDs                                       `thenDs` \ src_loc ->
+     let
+       f_helper_glob = mkVanillaId helper_name helper_ty
+                     where
+                       name                = idName i
+                       mod     
+                        | isLocalName name = mod_name
+                        | otherwise        = nameModule name
+
+                       occ                 = mkForeignExportOcc (nameOccName name)
+                       prov                = LocalDef src_loc Exported
+                       helper_name         = mkGlobalName uniq mod occ prov
+     in
      newSysLocalsDs fe_arg_tys                         `thenDs` \ fe_args ->
      (if isDyn then 
         newSysLocalDs stbl_ptr_ty                      `thenDs` \ stbl_ptr ->
@@ -244,7 +269,7 @@ dsFExport i ty ext_name cconv isDyn =
         returnDs (i, 
                  \ body -> body,
                  panic "stbl_ptr"  -- should never be touched.
-                 ))                                    `thenDs` \ (i, getFun_wrapper, stbl_ptr) ->
+                 ))                    `thenDs` \ (i, getFun_wrapper, stbl_ptr) ->
      let
       wrapper_args
        | isDyn      = stbl_ptr:fe_args
@@ -268,8 +293,8 @@ dsFExport i ty ext_name cconv isDyn =
          ExtName fs _ -> fs
          Dynamic      -> panic "dsFExport: Dynamic - shouldn't ever happen."
 
-      f_helper_glob    = mkIdVisible mod uniq f_helper
-      (h_stub, c_stub) = fexportEntry c_nm f_helper_glob wrapper_arg_tys the_result_ty cconv
+      (h_stub, c_stub) = fexportEntry c_nm f_helper_glob
+                                      wrapper_arg_tys the_result_ty cconv isDyn
      in
      returnDs (NonRec f_helper_glob the_body, h_stub, c_stub)
 
@@ -311,7 +336,7 @@ dsFExport i ty ext_name cconv isDyn =
    
 \end{code}
 
-"foreign export dynamic" lets you dress up Haskell IO actions
+@foreign export dynamic@ lets you dress up Haskell IO actions
 of some fixed type behind an externally callable interface (i.e.,
 as a C function pointer). Useful for callbacks and stuff.
 
@@ -343,18 +368,20 @@ foreign export "f_helper" f_helper :: StablePtr (Addr -> Int -> IO Int) -> Addr
 \begin{code}
 dsFExportDynamic :: Id
                 -> Type                -- Type of foreign export.
+                -> Module
                 -> ExtName
                 -> CallConv
                 -> DsM (CoreBind, CoreBind, SDoc, SDoc)
-dsFExportDynamic i ty ext_name cconv =
+dsFExportDynamic i ty mod_name ext_name cconv =
      newSysLocalDs ty                                   `thenDs` \ fe_id ->
      let 
         -- hack: need to get at the name of the C stub we're about to generate.
        fe_nm      = toCName fe_id
        fe_ext_name = ExtName (_PK_ fe_nm) Nothing
      in
-     dsFExport  i export_ty fe_ext_name cconv True `thenDs` \ (fe@(NonRec fe_helper fe_expr), h_code, c_code) ->
-     newSysLocalDs arg_ty                         `thenDs` \ cback ->
+     dsFExport  i export_ty mod_name fe_ext_name cconv True
+     `thenDs` \ (fe@(NonRec fe_helper fe_expr), h_code, c_code) ->
+     newSysLocalDs arg_ty                                  `thenDs` \ cback ->
      dsLookupGlobalValue makeStablePtr_NAME       `thenDs` \ makeStablePtrId ->
      let
        mk_stbl_ptr_app    = mkApps (Var makeStablePtrId) [ Type arg_ty, Var cback ]
@@ -430,8 +457,14 @@ The C stub constructs the application of the exported Haskell function
 using the hugs/ghc rts invocation API.
 
 \begin{code}
-fexportEntry :: FAST_STRING -> Id -> [Type] -> Maybe Type -> CallConv -> (SDoc, SDoc)
-fexportEntry c_nm helper args res cc = (header_bits, c_bits)
+fexportEntry :: FAST_STRING 
+            -> Id 
+            -> [Type] 
+            -> Maybe Type 
+            -> CallConv 
+            -> Bool
+            -> (SDoc, SDoc)
+fexportEntry c_nm helper args res cc isDyn = (header_bits, c_bits)
  where
    -- name of the (Haskell) helper function generated by the desugarer.
   h_nm     = ppr helper <> text "_closure"
@@ -439,7 +472,7 @@ fexportEntry c_nm helper args res cc = (header_bits, c_bits)
   header_bits = ptext SLIT("extern") <+> fun_proto <> semi
 
   fun_proto = cResType <+> pprCconv <+> ptext c_nm <>
-             parens (hsep (punctuate comma (zipWith (<+>) cParamTypes c_args)))
+             parens (hsep (punctuate comma (zipWith (<+>) cParamTypes proto_args)))
 
   c_bits =
     externDecl $$
@@ -458,7 +491,7 @@ fexportEntry c_nm helper args res cc = (header_bits, c_bits)
   appArg acc (a,c_a) =
      text "rts_apply" <> parens (acc <> comma <> mkHObj a <> parens c_a)
 
-  cParamTypes  = map showStgType args
+  cParamTypes  = map showStgType real_args
 
   cResType = 
    case res of
@@ -487,19 +520,34 @@ fexportEntry c_nm helper args res cc = (header_bits, c_bits)
       Nothing -> empty
       Just t  -> unpackHObj t <> parens (text "ret")
 
-  c_args = zipWith (\ _ n -> text ('a':show n)) args [0..] 
+  c_args = mkCArgNames 0 args
+
+  {-
+   If we're generating an entry point for a 'foreign export ccall dynamic',
+   then we receive the return address of the C function that wants to
+   invoke a Haskell function as any other C function, as second arg.
+   This arg is unused within the body of the generated C stub, but
+   needed by the Adjustor.c code to get the stack cleanup right.
+  -}
+  (proto_args, real_args)
+    | cc == cCallConv && isDyn = ( text "a0" : text "a_" : mkCArgNames 1 (tail args)
+                               , head args : addrTy : tail args)
+    | otherwise = (mkCArgNames 0 args, args)
+
+mkCArgNames :: Int -> [a] -> [SDoc]
+mkCArgNames n as = zipWith (\ _ n -> text ('a':show n)) as [n..] 
 
 mkHObj :: Type -> SDoc
-mkHObj t = text "rts_mk" <> showFFIType t
+mkHObj t = text "rts_mk" <> text (showFFIType t)
 
 unpackHObj :: Type -> SDoc
-unpackHObj t = text "rts_get" <> showFFIType t
+unpackHObj t = text "rts_get" <> text (showFFIType t)
 
 showStgType :: Type -> SDoc
-showStgType t = text "Stg" <> showFFIType t
+showStgType t = text "Stg" <> text (showFFIType t)
 
-showFFIType :: Type -> SDoc
-showFFIType t = text (getOccString (getName tc))
+showFFIType :: Type -> String
+showFFIType t = getOccString (getName tc)
  where
   tc = case splitTyConApp_maybe t of
            Just (tc,_) -> tc