@@ -17,55 +17,69 @@ module Language.PureScript.CodeGen.Externs (
17 moduleToPs
17 moduleToPs
20+import Data.Maybe (fromMaybe, mapMaybe)
20−import Data.List (intercalate)
21+import Data.List (intercalate, find)
22import qualified Data.Map as M
23import qualified Data.Map as M
24import Control.Monad.Writer
25import Control.Monad.Writer
26import Language.PureScript.Declarations
27import Language.PureScript.Declarations
27−import Language.PureScript.TypeChecker.Monad
28import Language.PureScript.Pretty
28import Language.PureScript.Pretty
29import Language.PureScript.Names
29import Language.PureScript.Names
30−import Language.PureScript.Types
30+import Language.PureScript.Values
31−import Language.PureScript.Kinds
31+import Language.PureScript.Environment
34-- Generate foreign imports for all declarations in a module
34-- Generate foreign imports for all declarations in a module
36moduleToPs :: Module -> Environment -> String
36moduleToPs :: Module -> Environment -> String
37+moduleToPs (Module _ _ Nothing) _ = error "Module exports were not elaborated in moduleToPs"
37−moduleToPs (Module moduleName _ exts) env = intercalate "\n" . execWriter $ do
38+moduleToPs (Module moduleName _ (Just exts)) env = intercalate "\n" . execWriter $ do
38 tell ["module " ++ runModuleName moduleName ++ " where"]
39 tell ["module " ++ runModuleName moduleName ++ " where"]
39− let typesExported = getTypesExportedFrom moduleName exts env
40+ mapM_ exportToPs exts
40− forM_ typesExported $ \(pn, kind) ->
41− tell ["foreign import data " ++ show pn ++ " :: " ++ prettyPrintKind kind]
42− let namesExported = getNamesExportedFrom moduleName exts env
43− forM_ namesExported $ \(ident, ty) ->
44− tell ["foreign import " ++ show ident ++ " :: " ++ prettyPrintType ty]
46−getNamesExportedFrom :: ModuleName -> Maybe [DeclarationRef] -> Environment -> [(Ident, Type)]
47−getNamesExportedFrom moduleName exps env =
49− | ((moduleName', ident), (ty, nameKind)) <- M.toList . names $ env
50− , moduleName == moduleName'
51− , nameKind `elem` [Value, Extern ForeignImport]
52− , isExported ident exps
55− isExported :: Ident -> Maybe [DeclarationRef] -> Bool
56− isExported _ Nothing = True
57− isExported ident (Just exps') = ValueRef ident `elem` exps'
59−getTypesExportedFrom :: ModuleName -> Maybe [DeclarationRef] -> Environment -> [(ProperName, Kind)]
43+ exportToPs :: DeclarationRef -> Writer [String] ()
60−getTypesExportedFrom moduleName exps env =
44+ exportToPs (TypeRef pn dctors) = do
62− | ((Qualified (Just moduleName') pn), kind) <- M.toList . types $ env
45+ case Qualified (Just moduleName) pn `M.lookup` types env of
63− , moduleName == moduleName'
46+ Nothing -> error $ show pn ++ " has no kind in exportToPs"
64− , isExported pn exps
47+ Just (kind, ExternData) ->
65− ]
48+ tell ["foreign import data " ++ show pn ++ " :: " ++ prettyPrintKind kind]
66− where
49+ Just (_, DataType args tys) -> do
67− isExported :: ProperName -> Maybe [DeclarationRef] -> Bool
50+ let dctors' = fromMaybe (map fst tys) dctors
68− isExported _ Nothing = True
51+ printDctor dctor = case dctor `lookup` tys of
69− isExported pn (Just exps') = flip any exps' $ \e -> case e of
52+ Nothing -> Nothing
70− TypeRef pn' _ | pn == pn' -> True
53+ Just tyArgs -> Just $ show dctor ++ " " ++ unwords (map prettyPrintTypeAtom tyArgs)
71− _ -> False
54+ tell ["data " ++ show pn ++ " " ++ unwords args ++ " = " ++ intercalate " | " (mapMaybe printDctor dctors')]
55+ Just (_, TypeSynonym) ->
56+ case Qualified (Just moduleName) pn `M.lookup` typeSynonyms env of
57+ Nothing -> error $ show pn ++ " has no type synonym info in exportToPs"
58+ Just (args, synTy) ->
59+ tell ["type " ++ show pn ++ " " ++ unwords args ++ " = " ++ prettyPrintType synTy]
60+ _ -> error "Invalid input in exportToPs"
62+ exportToPs (ValueRef ident) =
63+ case (moduleName, ident) `M.lookup` names env of
64+ Nothing -> error $ show ident ++ " has no type in exportToPs"
65+ Just (ty, nameKind) | nameKind == Value || nameKind == Extern ForeignImport ->
66+ tell ["foreign import " ++ show ident ++ " :: " ++ prettyPrintType ty]
68+ exportToPs (TypeClassRef className) =
69+ case Qualified (Just moduleName) className `M.lookup` typeClasses env of
70+ Nothing -> error $ show className ++ " has no type class definition in exportToPs"
71+ Just (args, ds) -> do
72+ tell ["class " ++ show className ++ " " ++ unwords args ++ " where"]
73+ forM_ (filter (isValueExported . fst) ds) $ \(member ,ty) ->
74+ tell [ " " ++ show member ++ " :: " ++ prettyPrintType ty ]
75+ exportToPs (TypeInstanceRef ident) = do
76+ let TypeClassDictionaryInScope { tcdClassName = className, tcdInstanceTypes = tys, tcdDependencies = deps} =
77+ fromMaybe (error $ "Type class instance has no dictionary in exportToPs") . find ((== Qualified (Just moduleName) ident) . tcdName) $ typeClassDictionaries env
78+ let constraintsText = case fromMaybe [] deps of
80+ cs -> "(" ++ intercalate ", " (map (\(pn, tys') -> show pn ++ " " ++ unwords (map prettyPrintTypeAtom tys')) cs) ++ ") => "
81+ tell ["foreign import instance " ++ show ident ++ " :: " ++ constraintsText ++ show className ++ " " ++ unwords (map prettyPrintTypeAtom tys)]
83+ isValueExported :: Ident -> Bool
84+ isValueExported ident = ValueRef ident `elem` exts