forked from purescript/purescript
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathEnvironment.hs
More file actions
279 lines (246 loc) · 7.17 KB
/
Environment.hs
File metadata and controls
279 lines (246 loc) · 7.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
module Language.PureScript.Environment where
import Prelude.Compat
import Data.Aeson.TH
import Data.Maybe (fromMaybe)
import qualified Data.Aeson as A
import qualified Data.Map as M
import qualified Data.Text as T
import Language.PureScript.Crash
import Language.PureScript.Kinds
import Language.PureScript.Names
import Language.PureScript.TypeClassDictionaries
import Language.PureScript.Types
import qualified Language.PureScript.Constants as C
-- |
-- The @Environment@ defines all values and types which are currently in scope:
--
data Environment = Environment {
-- |
-- Value names currently in scope
--
names :: M.Map (ModuleName, Ident) (Type, NameKind, NameVisibility)
-- |
-- Type names currently in scope
--
, types :: M.Map (Qualified (ProperName 'TypeName)) (Kind, TypeKind)
-- |
-- Data constructors currently in scope, along with their associated type
-- constructor name, argument types and return type.
, dataConstructors :: M.Map (Qualified (ProperName 'ConstructorName)) (DataDeclType, ProperName 'TypeName, Type, [Ident])
-- |
-- Type synonyms currently in scope
--
, typeSynonyms :: M.Map (Qualified (ProperName 'TypeName)) ([(String, Maybe Kind)], Type)
-- |
-- Available type class dictionaries
--
, typeClassDictionaries :: M.Map (Maybe ModuleName) (M.Map (Qualified (ProperName 'ClassName)) (M.Map (Qualified Ident) TypeClassDictionaryInScope))
-- |
-- Type classes
--
, typeClasses :: M.Map (Qualified (ProperName 'ClassName)) ([(String, Maybe Kind)], [(Ident, Type)], [Constraint])
} deriving (Show, Read)
-- |
-- The initial environment with no values and only the default javascript types defined
--
initEnvironment :: Environment
initEnvironment = Environment M.empty primTypes M.empty M.empty M.empty primClasses
-- |
-- The visibility of a name in scope
--
data NameVisibility
-- |
-- The name is defined in the current binding group, but is not visible
--
= Undefined
-- |
-- The name is defined in the another binding group, or has been made visible by a function binder
--
| Defined deriving (Show, Read, Eq)
-- |
-- A flag for whether a name is for an private or public value - only public values will be
-- included in a generated externs file.
--
data NameKind
-- |
-- A private value introduced as an artifact of code generation (class instances, class member
-- accessors, etc.)
--
= Private
-- |
-- A public value for a module member or foreing import declaration
--
| Public
-- |
-- A name for member introduced by foreign import
--
| External
deriving (Show, Read, Eq)
-- |
-- The kinds of a type
--
data TypeKind
-- |
-- Data type
--
= DataType [(String, Maybe Kind)] [(ProperName 'ConstructorName, [Type])]
-- |
-- Type synonym
--
| TypeSynonym
-- |
-- Foreign data
--
| ExternData
-- |
-- A local type variable
--
| LocalTypeVariable
-- |
-- A scoped type variable
--
| ScopedTypeVar
deriving (Show, Read, Eq)
-- |
-- The type ('data' or 'newtype') of a data type declaration
--
data DataDeclType
-- |
-- A standard data constructor
--
= Data
-- |
-- A newtype constructor
--
| Newtype
deriving (Show, Read, Eq, Ord)
showDataDeclType :: DataDeclType -> String
showDataDeclType Data = "data"
showDataDeclType Newtype = "newtype"
instance A.ToJSON DataDeclType where
toJSON = A.toJSON . showDataDeclType
instance A.FromJSON DataDeclType where
parseJSON = A.withText "DataDeclType" $ \str ->
case str of
"data" -> return Data
"newtype" -> return Newtype
other -> fail $ "invalid type: '" ++ T.unpack other ++ "'"
-- |
-- Construct a ProperName in the Prim module
--
primName :: String -> Qualified (ProperName a)
primName = Qualified (Just $ ModuleName [ProperName C.prim]) . ProperName
-- |
-- Construct a type in the Prim module
--
primTy :: String -> Type
primTy = TypeConstructor . primName
-- |
-- Type constructor for functions
--
tyFunction :: Type
tyFunction = primTy "Function"
-- |
-- Type constructor for strings
--
tyString :: Type
tyString = primTy "String"
-- |
-- Type constructor for strings
--
tyChar :: Type
tyChar = primTy "Char"
-- |
-- Type constructor for numbers
--
tyNumber :: Type
tyNumber = primTy "Number"
-- |
-- Type constructor for integers
--
tyInt :: Type
tyInt = primTy "Int"
-- |
-- Type constructor for booleans
--
tyBoolean :: Type
tyBoolean = primTy "Boolean"
-- |
-- Type constructor for arrays
--
tyArray :: Type
tyArray = primTy "Array"
-- |
-- Type constructor for records
--
tyRecord :: Type
tyRecord = primTy "Record"
-- |
-- Check whether a type is a record
--
isObject :: Type -> Bool
isObject = isTypeOrApplied tyRecord
-- |
-- Check whether a type is a function
--
isFunction :: Type -> Bool
isFunction = isTypeOrApplied tyFunction
isTypeOrApplied :: Type -> Type -> Bool
isTypeOrApplied t1 (TypeApp t2 _) = t1 == t2
isTypeOrApplied t1 t2 = t1 == t2
-- |
-- Smart constructor for function types
--
function :: Type -> Type -> Type
function t1 = TypeApp (TypeApp tyFunction t1)
-- |
-- The primitive types in the external javascript environment with their
-- associated kinds. There is also a pseudo `Partial` type that corresponds to
-- the class with the same name.
--
primTypes :: M.Map (Qualified (ProperName 'TypeName)) (Kind, TypeKind)
primTypes =
M.fromList
[ (primName "Function", (FunKind Star (FunKind Star Star), ExternData))
, (primName "Array", (FunKind Star Star, ExternData))
, (primName "Record", (FunKind (Row Star) Star, ExternData))
, (primName "String", (Star, ExternData))
, (primName "Char", (Star, ExternData))
, (primName "Number", (Star, ExternData))
, (primName "Int", (Star, ExternData))
, (primName "Boolean", (Star, ExternData))
, (primName "Partial", (Star, ExternData))
, (primName "Fail", (FunKind Symbol Star, ExternData))
]
-- |
-- The primitive class map. This just contains to `Partial` class, used as a
-- kind of magic constraint for partial functions.
--
primClasses :: M.Map (Qualified (ProperName 'ClassName)) ([(String, Maybe Kind)], [(Ident, Type)], [Constraint])
primClasses =
M.fromList
[ (primName "Partial", ([], [], []))
, (primName "Fail", ([("message", Just Symbol)], [], []))
]
-- |
-- Finds information about data constructors from the current environment.
--
lookupConstructor :: Environment -> Qualified (ProperName 'ConstructorName) -> (DataDeclType, ProperName 'TypeName, Type, [Ident])
lookupConstructor env ctor =
fromMaybe (internalError "Data constructor not found") $ ctor `M.lookup` dataConstructors env
-- |
-- Checks whether a data constructor is for a newtype.
--
isNewtypeConstructor :: Environment -> Qualified (ProperName 'ConstructorName) -> Bool
isNewtypeConstructor e ctor = case lookupConstructor e ctor of
(Newtype, _, _, _) -> True
(Data, _, _, _) -> False
-- |
-- Finds information about values from the current environment.
--
lookupValue :: Environment -> Qualified Ident -> Maybe (Type, NameKind, NameVisibility)
lookupValue env (Qualified (Just mn) ident) = (mn, ident) `M.lookup` names env
lookupValue _ _ = Nothing
$(deriveJSON (defaultOptions { sumEncoding = ObjectWithSingleField }) ''TypeKind)