Skip to content

Commit b314ba1

Browse files
committed
1 parent 415a33f commit b314ba1

File tree

20 files changed

+288
-236
lines changed

20 files changed

+288
-236
lines changed

purescript.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ library
2929
Language.PureScript.Constants
3030
Language.PureScript.Options
3131
Language.PureScript.Declarations
32+
Language.PureScript.Environment
3233
Language.PureScript.Kinds
3334
Language.PureScript.Names
3435
Language.PureScript.Types
@@ -71,7 +72,6 @@ library
7172
Language.PureScript.Pretty.Kinds
7273
Language.PureScript.Pretty.Types
7374
Language.PureScript.Pretty.Values
74-
Language.PureScript.Prim
7575
Language.PureScript.TypeChecker
7676
Language.PureScript.TypeChecker.Kinds
7777
Language.PureScript.TypeChecker.Monad

src/Language/PureScript.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import Language.PureScript.Pretty as P
2828
import Language.PureScript.Sugar as P
2929
import Language.PureScript.Options as P
3030
import Language.PureScript.ModuleDependencies as P
31+
import Language.PureScript.Environment as P
3132
import Language.PureScript.DeadCodeElimination as P
3233

3334
import qualified Language.PureScript.Constants as C

src/Language/PureScript/CodeGen/Externs.hs

Lines changed: 50 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,55 +17,69 @@ module Language.PureScript.CodeGen.Externs (
1717
moduleToPs
1818
) where
1919

20-
import Data.List (intercalate)
20+
import Data.Maybe (fromMaybe, mapMaybe)
21+
import Data.List (intercalate, find)
2122

2223
import qualified Data.Map as M
2324

2425
import Control.Monad.Writer
2526

2627
import Language.PureScript.Declarations
27-
import Language.PureScript.TypeChecker.Monad
2828
import Language.PureScript.Pretty
2929
import Language.PureScript.Names
30-
import Language.PureScript.Types
31-
import Language.PureScript.Kinds
30+
import Language.PureScript.Values
31+
import Language.PureScript.Environment
3232

3333
-- |
3434
-- Generate foreign imports for all declarations in a module
3535
--
3636
moduleToPs :: Module -> Environment -> String
37-
moduleToPs (Module moduleName _ exts) env = intercalate "\n" . execWriter $ do
37+
moduleToPs (Module _ _ Nothing) _ = error "Module exports were not elaborated in moduleToPs"
38+
moduleToPs (Module moduleName _ (Just exts)) env = intercalate "\n" . execWriter $ do
3839
tell ["module " ++ runModuleName moduleName ++ " where"]
39-
let typesExported = getTypesExportedFrom moduleName exts env
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]
45-
46-
getNamesExportedFrom :: ModuleName -> Maybe [DeclarationRef] -> Environment -> [(Ident, Type)]
47-
getNamesExportedFrom moduleName exps env =
48-
[ (ident, ty)
49-
| ((moduleName', ident), (ty, nameKind)) <- M.toList . names $ env
50-
, moduleName == moduleName'
51-
, nameKind `elem` [Value, Extern ForeignImport]
52-
, isExported ident exps
53-
]
40+
mapM_ exportToPs exts
5441
where
55-
isExported :: Ident -> Maybe [DeclarationRef] -> Bool
56-
isExported _ Nothing = True
57-
isExported ident (Just exps') = ValueRef ident `elem` exps'
5842

59-
getTypesExportedFrom :: ModuleName -> Maybe [DeclarationRef] -> Environment -> [(ProperName, Kind)]
60-
getTypesExportedFrom moduleName exps env =
61-
[ (pn, kind)
62-
| ((Qualified (Just moduleName') pn), kind) <- M.toList . types $ env
63-
, moduleName == moduleName'
64-
, isExported pn exps
65-
]
66-
where
67-
isExported :: ProperName -> Maybe [DeclarationRef] -> Bool
68-
isExported _ Nothing = True
69-
isExported pn (Just exps') = flip any exps' $ \e -> case e of
70-
TypeRef pn' _ | pn == pn' -> True
71-
_ -> False
43+
exportToPs :: DeclarationRef -> Writer [String] ()
44+
exportToPs (TypeRef pn dctors) = do
45+
case Qualified (Just moduleName) pn `M.lookup` types env of
46+
Nothing -> error $ show pn ++ " has no kind in exportToPs"
47+
Just (kind, ExternData) ->
48+
tell ["foreign import data " ++ show pn ++ " :: " ++ prettyPrintKind kind]
49+
Just (_, DataType args tys) -> do
50+
let dctors' = fromMaybe (map fst tys) dctors
51+
printDctor dctor = case dctor `lookup` tys of
52+
Nothing -> Nothing
53+
Just tyArgs -> Just $ show dctor ++ " " ++ unwords (map prettyPrintTypeAtom tyArgs)
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"
61+
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]
67+
_ -> return ()
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
79+
[] -> ""
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)]
82+
83+
isValueExported :: Ident -> Bool
84+
isValueExported ident = ValueRef ident `elem` exts
85+

src/Language/PureScript/CodeGen/JS.hs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import Control.Monad (replicateM, forM)
3030

3131
import qualified Data.Map as M
3232

33-
import Language.PureScript.TypeChecker (Environment(..))
3433
import Language.PureScript.Values
3534
import Language.PureScript.Names
3635
import Language.PureScript.Scope
@@ -41,7 +40,7 @@ import Language.PureScript.CodeGen.JS.AST as AST
4140
import Language.PureScript.Types
4241
import Language.PureScript.Optimizer
4342
import Language.PureScript.CodeGen.Common
44-
import Language.PureScript.Prim
43+
import Language.PureScript.Environment
4544
import qualified Language.PureScript.Constants as C
4645

4746
-- |
@@ -90,7 +89,7 @@ declToJs _ _ _ _ = Nothing
9089
exportToJs :: DeclarationRef -> [JS]
9190
exportToJs (TypeRef _ (Just dctors)) = flip map dctors (export . Escaped . runProperName)
9291
exportToJs (ValueRef name) = [export name]
93-
exportToJs (TypeInstanceRef name _ _) = [export name]
92+
exportToJs (TypeInstanceRef name) = [export name]
9493
exportToJs _ = []
9594

9695
-- |

src/Language/PureScript/DeadCodeElimination.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ eliminateDeadCode entryPoints ms = map go ms
4444
filterExport :: [Declaration] -> DeclarationRef -> Maybe DeclarationRef
4545
filterExport decls r@(TypeRef name _) | (any $ typeExists name) decls = Just r
4646
filterExport decls r@(ValueRef name) | (any $ valueExists name) decls = Just r
47-
filterExport decls r@(TypeInstanceRef name _ _) | (any $ valueExists name) decls = Just r
47+
filterExport decls r@(TypeInstanceRef name) | (any $ valueExists name) decls = Just r
4848
filterExport _ _ = Nothing
4949

5050
valueExists :: Ident -> Declaration -> Bool
@@ -56,7 +56,7 @@ eliminateDeadCode entryPoints ms = map go ms
5656
typeExists :: ProperName -> Declaration -> Bool
5757
typeExists name (DataDeclaration name' _ _) = name == name'
5858
typeExists name (DataBindingGroupDeclaration decls) = any (typeExists name) decls
59-
typeExists _ _ = False
59+
typeExists _ _ = False
6060

6161
type Key = (ModuleName, Either Ident ProperName)
6262

src/Language/PureScript/Declarations.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import Language.PureScript.Types
2121
import Language.PureScript.Names
2222
import Language.PureScript.Kinds
2323
import Language.PureScript.CodeGen.JS.AST
24+
import Language.PureScript.Environment
2425

2526
import qualified Data.Data as D
2627

@@ -64,7 +65,7 @@ data DeclarationRef
6465
-- |
6566
-- A type class instance, created during typeclass desugaring (name, class name, instance types)
6667
--
67-
| TypeInstanceRef Ident (Qualified ProperName) [Type]
68+
| TypeInstanceRef Ident
6869
deriving (Show, Eq, D.Data, D.Typeable)
6970

7071
-- |
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
-----------------------------------------------------------------------------
2+
--
3+
-- Module : Language.PureScript.Prim
4+
-- Copyright : (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors
5+
-- License : MIT
6+
--
7+
-- Maintainer : Phil Freeman <paf31@cantab.net>
8+
-- Stability : experimental
9+
-- Portability :
10+
--
11+
-- |
12+
--
13+
-----------------------------------------------------------------------------
14+
15+
{-# LANGUAGE DeriveDataTypeable #-}
16+
17+
module Language.PureScript.Environment where
18+
19+
import Data.Data
20+
21+
import Language.PureScript.Names
22+
import Language.PureScript.Types
23+
import Language.PureScript.Kinds
24+
import Language.PureScript.Values
25+
import qualified Language.PureScript.Constants as C
26+
27+
import qualified Data.Map as M
28+
29+
-- |
30+
-- The @Environment@ defines all values and types which are currently in scope:
31+
--
32+
data Environment = Environment {
33+
-- |
34+
-- Value names currently in scope
35+
--
36+
names :: M.Map (ModuleName, Ident) (Type, NameKind)
37+
-- |
38+
-- Type names currently in scope
39+
--
40+
, types :: M.Map (Qualified ProperName) (Kind, TypeKind)
41+
-- |
42+
-- Data constructors currently in scope, along with their associated data type constructors
43+
--
44+
, dataConstructors :: M.Map (Qualified ProperName) (ProperName, Type)
45+
-- |
46+
-- Type synonyms currently in scope
47+
--
48+
, typeSynonyms :: M.Map (Qualified ProperName) ([String], Type)
49+
-- |
50+
-- Available type class dictionaries
51+
--
52+
, typeClassDictionaries :: [TypeClassDictionaryInScope]
53+
-- |
54+
-- Type classes
55+
--
56+
, typeClasses :: M.Map (Qualified ProperName) ([String], [(Ident, Type)])
57+
} deriving (Show)
58+
59+
-- |
60+
-- The initial environment with no values and only the default javascript types defined
61+
--
62+
initEnvironment :: Environment
63+
initEnvironment = Environment M.empty primTypes M.empty M.empty [] M.empty
64+
65+
-- |
66+
-- The type of a foreign import
67+
--
68+
data ForeignImportType
69+
-- |
70+
-- A regular foreign import
71+
--
72+
= ForeignImport
73+
-- |
74+
-- A foreign import which contains inline Javascript as a string literal
75+
--
76+
| InlineJavascript
77+
-- |
78+
-- A type class dictionary member accessor import, generated during desugaring of type class declarations
79+
--
80+
| TypeClassAccessorImport deriving (Show, Eq, Data, Typeable)
81+
82+
-- |
83+
-- The kind of a name
84+
--
85+
data NameKind
86+
-- |
87+
-- A value introduced as a binding in a module
88+
--
89+
= Value
90+
-- |
91+
-- A foreign import
92+
--
93+
| Extern ForeignImportType
94+
-- |
95+
-- A local name introduced using a lambda abstraction, variable introduction or binder
96+
--
97+
| LocalVariable
98+
-- |
99+
-- A data constructor
100+
--
101+
| DataConstructor
102+
-- |
103+
-- A type class dictionary, generated during desugaring of type class declarations
104+
--
105+
| TypeInstanceDictionaryValue
106+
-- |
107+
-- A type instance member, generated during desugaring of type class declarations
108+
--
109+
| TypeInstanceMember deriving (Show, Eq, Data, Typeable)
110+
111+
-- |
112+
-- The kinds of a type
113+
--
114+
data TypeKind
115+
-- |
116+
-- Data type
117+
--
118+
= DataType [String] [(ProperName, [Type])]
119+
-- |
120+
-- Type synonym
121+
--
122+
| TypeSynonym
123+
-- |
124+
-- Foreign data
125+
--
126+
| ExternData
127+
-- |
128+
-- A local type variable
129+
--
130+
| LocalTypeVariable deriving (Show, Eq, Data, Typeable)
131+
132+
-- |
133+
-- Construct a ProperName in the Prim module
134+
--
135+
primName :: String -> Qualified ProperName
136+
primName = Qualified (Just $ ModuleName [ProperName C.prim]) . ProperName
137+
138+
-- |
139+
-- Construct a type in the Prim module
140+
--
141+
primTy :: String -> Type
142+
primTy = TypeConstructor . primName
143+
144+
-- |
145+
-- Type constructor for functions
146+
--
147+
tyFunction :: Type
148+
tyFunction = primTy "Function"
149+
150+
-- |
151+
-- Type constructor for strings
152+
--
153+
tyString :: Type
154+
tyString = primTy "String"
155+
156+
-- |
157+
-- Type constructor for numbers
158+
--
159+
tyNumber :: Type
160+
tyNumber = primTy "Number"
161+
162+
-- |
163+
-- Type constructor for booleans
164+
--
165+
tyBoolean :: Type
166+
tyBoolean = primTy "Boolean"
167+
168+
-- |
169+
-- Type constructor for arrays
170+
--
171+
tyArray :: Type
172+
tyArray = primTy "Array"
173+
174+
-- |
175+
-- Smart constructor for function types
176+
--
177+
function :: Type -> Type -> Type
178+
function t1 = TypeApp (TypeApp tyFunction t1)
179+
180+
-- |
181+
-- The primitive types in the external javascript environment with their associated kinds.
182+
--
183+
primTypes :: M.Map (Qualified ProperName) (Kind, TypeKind)
184+
primTypes = M.fromList [ (primName "Function" , (FunKind Star (FunKind Star Star), ExternData))
185+
, (primName "Array" , (FunKind Star Star, ExternData))
186+
, (primName "String" , (Star, ExternData))
187+
, (primName "Number" , (Star, ExternData))
188+
, (primName "Boolean" , (Star, ExternData)) ]

0 commit comments

Comments
 (0)