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

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


-- | Generate C wrappers for haskell FFI functions
module ByteCode.Wrap(bcWrap) where

import Flags
import ByteCode.Type
import IntState
import Id
import ForeignCode
import Syntax(CallConv(..))
import SysDeps (trace)
import ByteCode.Write
import SysDeps (unpackPS)
import TokenId

-- | Generate C stub wrappers for FFI functions.  Writes generated C code
--   to the indicated file.
bcWrap :: IntState     -- ^ internal compiler state
       -> Flags        -- ^ compiler flags
       -> FileFlags    -- ^ information about the file to write
       -> BCModule     -- ^ the declarations from which to generate external wrappers
       -> IO ()

bcWrap state flags fileflags m =
    withDirectory (sWrapFile fileflags) (\s -> "Wrap"++s) (f "")
    where
    ds = bcmDecls m
    f = showString "#include <hsffi.h>\n\n" . catShows (map (wDecl state) ds) . (wInit state ds)

wDecl :: IntState -> BCDecl -> ShowS
wDecl state (External name pos arity cName callConv flags)
    | callConv /= "builtin" = undefined {- FIXME: !!!!!!!!
    wForeign cName' forn callConv
    where
    syms    = getSymbolTable state
    memo    = foreignMemo syms
    mode    = trace ("FIXME: wDecl mode ...") Imported
    forn    = toForeign syms memo callConv mode cName arity name
    cName'  = reverse $ takeWhile (/='&') $ reverse cName -}

wDecl state x                                              = id


wInit :: IntState -> [BCDecl] -> ShowS
wInit state ds =
    showString "\n\n/* autogenerated init function */\n" .
    showString "void init_" . showString initName . showString "(WrapRegisterFun reg, void* arg){\n" .
    catShows (map (wInitDecl state) ds) .
    showString "}\n"
    where
    initName = replace '.' '_' $ reverse $  unpackPS $ mrpsIS state

    replace a b xs = map (\x -> if x == a then b else x) xs


wInitDecl :: IntState -> BCDecl -> ShowS
wInitDecl state (External name pos arity cName callConv flags)
    | callConv /= "builtin" =
        showString "  reg(\"" . showString smod . showString "\", \"" . showString cName . showString "\", " . showString fname .
        showString ", arg);\n"
    where
    fname = if callConv == "primitive" then cName else "Wrap_" ++ cName
    (smod,sname) = splitQualified name
wInitDecl state x = id

wForeign :: String -> Foreign -> String -> ShowS
wForeign cname fr@(Foreign ie proto style mpath _ htok arity args res) callConv =
    wInclude mpath .
    (if proto then wProto style callConv cname args res else id) .
    if callConv /= "primitive"
     then
        (wHeader htok cname .
         wResDecl res .
         catShows ds .
         catShows rs .
         wCall style cname args res .
         wBoxResult res .
         wFooter)
     else id
    where
    (ds,rs) = unzip $ map wArgDecl [0..arity-1]

wInclude :: Maybe FilePath -> ShowS
wInclude Nothing  = id
wInclude (Just p) = showString "#include <" . showString p . showString ">\n\n"

wHeader :: TokenId -> String -> ShowS
wHeader name cName =
    showString "/* auto-generated wrapper for " . shows name . showString " */\n" .
    showString "Node* Wrap_" . showString cName . showString "(Node* node){\n" .
    showString "  Node* nResult = NULL;\n"

wFooter :: ShowS
wFooter =
    showString "  return nResult;\n" .
    showString "}\n\n"

wArgDecl :: Int -> (ShowS,ShowS)
wArgDecl n = (decl,remove)
    where
    decl   = showString "  Node* arg" . shows n . showString " = node->args[" . shows n . showString "];\n"
    remove = showString "  REMOVE_IND(arg" . shows n . showString ", Node*);\n"

wResDecl :: Res -> ShowS
wResDecl Unit = id
wResDecl res  = showString "  " . typeName res . showString " pResult;\n"

wProto :: Style -> String -> String -> [Arg] -> Res -> ShowS
wProto Ordinary callConv cname args res
    | callConv == "primitive" = showString "Node* " . showString cname . showString "(Node* node);\n\n"
    | otherwise                     = typeName res . showChar ' ' . showString cname .
                                      wCommaParens (map typeName args) . showString ";\n\n"
wProto CCast callConv cnaem args res = id

wCall :: Style -> String -> [Arg] -> Res -> ShowS
wCall Ordinary cname args res =
    wPResult res . showString cname . wArgUnboxes args . showString ";\n"
wCall CCast cname [arg] res =
    wPResult res . showChar '(' . typeName res . showChar ')' . wArgUnboxes [arg] . showString ";\n"

wPResult :: Arg -> ShowS
wPResult Unit = showString "  "
wPResult _    = showString "  pResult = "

wArgUnboxes :: [Arg] -> ShowS
wArgUnboxes args = wCommaParens $ map arg (zip args [0..])
    where
    arg (a,n) = showString "UNBOX_" . showString (boxName a) . showString "(arg" . shows n . showChar ')'

wCommaParens :: [ShowS] -> ShowS
wCommaParens xs = showChar '(' . interleave (showChar ',') xs . showChar ')'
    where
    interleave y [] = id
    interleave y xs = foldr1 (\x s -> x . y . s) xs

wBoxResult :: Res -> ShowS
wBoxResult Unit = showString "  nResult = NODE_UNIT;\n"
wBoxResult res = showString "  BOX_" . showString (boxName res) . showString "(nResult,pResult);\n"

boxName :: Arg -> String
boxName Int8 = "INT8"
boxName Int16 = "INT16"
boxName Int32 = "INT32"
boxName Int64 = "INT64"
boxName Word8 = "WORD8"
boxName Word16 = "WORD16"
boxName Word32 = "WORD32"
boxName Word64 = "WORD64"
boxName Int = "INT"
boxName Float = "FLOAT"
boxName Double = "DOUBLE"
boxName Char = "CHAR"
boxName Bool = "BOOL"
boxName Ptr = "PTR"
boxName (FunPtr _) = "FUN_PTR"
boxName StablePtr = "STABLE_PTR"
boxName ForeignPtr = "FOREIGN_PTR"
boxName Addr = "ADDR"
boxName ForeignObj = "FOREIGN_OBJ"
boxName PackedString = "STRING"
boxName Integer = "INTEGER"
boxName (HaskellFun _) = "HS_FUN"
boxName (Unknown _) = "UNKNOWN"
boxName Unit = "UNIT"

typeName :: Arg -> ShowS
typeName (FunPtr _) = showString "FunPtr"
typeName x          = cTypename x

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

showId :: IntState -> Id -> ShowS
showId state i = showString $ strIS state i

catShows :: [ShowS] -> ShowS
catShows = foldr (.) id

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].