git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge branch 'master' into pure11
a193b03Andy Arvanitis
examples/failing/2534.pursnew file+8
@@ -0,0 +1,8 @@
1+-- @shouldFailWith InfiniteType
2+module Main where
3+
4+foo :: Array Int -> Int
5+foo xs = go xs where
6+ go :: Array _ -> Int
7+ go [] = 0
8+ go xs = go [xs]
examples/failing/BindInDo-2.pursnew file+9
@@ -0,0 +1,9 @@
1+-- @shouldFailWith CannotUseBindWithDo
2+module Main where
3+
4+import Prelude
5+
6+foo = do
7+ let bind = 42
8+ x <- [4, 5, 6]
9+ pure x
examples/failing/BindInDo.pursnew file+9
@@ -0,0 +1,9 @@
1+-- @shouldFailWith CannotUseBindWithDo
2+module Main where
3+
4+import Prelude
5+
6+foo = do
7+ bind <- [1,2,3]
8+ x <- [4, 5, 6]
9+ pure x
examples/failing/DeclConflictDuplicateCtor.pursnew file+5
@@ -0,0 +1,5 @@
1+-- @shouldFailWith DeclConflict
2+module Main where
3+
4+data T = Fail | Fail
5+
examples/passing/StringEdgeCases.pursnew file+9
@@ -0,0 +1,9 @@
1+module Main where
2+
3+import Prelude
4+import Records as Records
5+import Symbols as Symbols
6+
7+main = do
8+ Records.main
9+ Symbols.main
examples/passing/StringEdgeCases/Records.pursnew file+66
@@ -0,0 +1,66 @@
1+module Records where
2+
3+import Prelude
4+import Data.Generic (class Generic, toSpine, GenericSpine(..))
5+import Control.Monad.Eff.Console (log)
6+import Test.Assert (assert')
7+
8+newtype AstralKeys = AstralKeys { "๐Ÿ’ก" :: Int, "๐Ÿ’ข" :: Int }
9+newtype LoneSurrogateKeys = LoneSurrogateKeys { "\xdf06" :: Int, "\xd834" :: Int }
10+
11+derive instance genericAstralKeys :: Generic AstralKeys
12+derive instance genericLoneSurrogateKeys :: Generic LoneSurrogateKeys
13+
14+spineOf :: forall a. Generic a => a -> Unit -> GenericSpine
15+spineOf x _ = toSpine x
16+
17+testLoneSurrogateKeys =
18+ let
19+ expected = 5
20+ actual = (_."\xd801" <<< helper) { "\xd800": 5 }
21+ in
22+ assert' ("lone surrogate keys: " <> show actual) (expected == actual)
23+
24+ where
25+ helper :: { "\xd800" :: Int } -> { "\xd801" :: Int }
26+ helper o =
27+ case o."\xd800" of
28+ x -> { "\xd801": x }
29+
30+testAstralKeys =
31+ let
32+ expected = 5
33+ actual = (_."๐Ÿ’ข" <<< helper) { "๐Ÿ’ก": 5 }
34+ in
35+ assert' ("astral keys: " <> show actual) (expected == actual)
36+
37+ where
38+ helper :: { "๐Ÿ’ก" :: Int } -> { "๐Ÿ’ข" :: Int }
39+ helper o =
40+ case o."๐Ÿ’ก" of
41+ x -> { "๐Ÿ’ข": x }
42+
43+testGenericLoneSurrogateKeys = do
44+ let expected = SProd "Records.LoneSurrogateKeys"
45+ [ \_ -> SRecord [ {recLabel: "\xd834", recValue: spineOf 1}
46+ , {recLabel: "\xdf06", recValue: spineOf 0}
47+ ]
48+ ]
49+ actual = toSpine (LoneSurrogateKeys { "\xdf06": 0, "\xd834": 1 })
50+ assert' ("generic lone surrogate keys: " <> show actual) (expected == actual)
51+
52+testGenericAstralKeys = do
53+ let expected = SProd "Records.AstralKeys"
54+ [ \_ -> SRecord [ {recLabel: "๐Ÿ’ก", recValue: spineOf 0}
55+ , {recLabel: "๐Ÿ’ข", recValue: spineOf 1}
56+ ]
57+ ]
58+ actual = toSpine (AstralKeys { "๐Ÿ’ก": 0, "๐Ÿ’ข": 1 })
59+ assert' ("generic astral keys: " <> show actual) (expected == actual)
60+
61+main = do
62+ testLoneSurrogateKeys
63+ testAstralKeys
64+ testGenericLoneSurrogateKeys
65+ testGenericAstralKeys
66+ log "Done"
examples/passing/StringEdgeCases/Symbols.pursnew file+30
@@ -0,0 +1,30 @@
1+-- This is similar to StringEscapes except we are performing the same tests
2+-- with Symbols (at the type level).
3+
4+module Symbols where
5+
6+import Prelude
7+import Control.Monad.Eff.Console (log)
8+import Type.Data.Symbol (SProxy(..), class AppendSymbol, appendSymbol, reflectSymbol)
9+import Test.Assert (assert')
10+
11+highS :: SProxy "\xd834"
12+highS = SProxy
13+
14+lowS :: SProxy "\xdf06"
15+lowS = SProxy
16+
17+loneSurrogates :: Boolean
18+loneSurrogates = reflectSymbol (appendSymbol highS lowS) == "\x1d306"
19+
20+outOfOrderSurrogates :: Boolean
21+outOfOrderSurrogates = reflectSymbol (appendSymbol lowS highS) == "\xdf06\xd834"
22+
23+notReplacing :: Boolean
24+notReplacing = reflectSymbol lowS /= "\xfffd"
25+
26+main = do
27+ assert' "lone surrogates may be combined into a surrogate pair" loneSurrogates
28+ assert' "lone surrogates may be combined out of order to remain lone surrogates" outOfOrderSurrogates
29+ assert' "lone surrogates are not replaced with the Unicode replacement character U+FFFD" notReplacing
30+ log "Done"
examples/passing/StringEscapes.purs+1โˆ’1
@@ -22,5 +22,5 @@ main = do
22 assert' "astral code points are represented as a UTF-16 surrogate pair" surrogatePair
22 assert' "astral code points are represented as a UTF-16 surrogate pair" surrogatePair
23 assert' "lone surrogates may be combined into a surrogate pair" loneSurrogates
23 assert' "lone surrogates may be combined into a surrogate pair" loneSurrogates
24 assert' "lone surrogates may be combined out of order to remain lone surrogates" outOfOrderSurrogates
24 assert' "lone surrogates may be combined out of order to remain lone surrogates" outOfOrderSurrogates
25โˆ’ -- assert' "lone surrogates are not replaced with the Unicode replacement character U+FFFD" notReplacing
25+ assert' "lone surrogates are not replaced with the Unicode replacement character U+FFFD" notReplacing
26 log "Done"
26 log "Done"
psc-ide-client/Main.hs+2
@@ -35,6 +35,8 @@ main = do
35
35
36client :: PortID -> IO ()
36client :: PortID -> IO ()
37client port = do
37client port = do
38+ hSetEncoding stdin utf8
39+ hSetEncoding stdout utf8
38 h <-
40 h <-
39 connectTo "127.0.0.1" port `catch`
41 connectTo "127.0.0.1" port `catch`
40 (\(SomeException e) ->
42 (\(SomeException e) ->
purescript.cabal+5โˆ’2
@@ -1,5 +1,5 @@
1name: purescript
1name: purescript
2โˆ’version: 0.10.4
2+version: 0.10.5
3cabal-version: >=1.8
3cabal-version: >=1.8
4build-type: Simple
4build-type: Simple
5license: BSD3
5license: BSD3
@@ -54,6 +54,7 @@ extra-source-files: examples/passing/*.purs
54 , examples/passing/ResolvableScopeConflict3/*.purs
54 , examples/passing/ResolvableScopeConflict3/*.purs
55 , examples/passing/ShadowedModuleName/*.purs
55 , examples/passing/ShadowedModuleName/*.purs
56 , examples/passing/SolvingIsSymbol/*.purs
56 , examples/passing/SolvingIsSymbol/*.purs
57+ , examples/passing/StringEdgeCases/*.purs
57 , examples/passing/TransitiveImport/*.purs
58 , examples/passing/TransitiveImport/*.purs
58 , examples/passing/TypeOperators/*.purs
59 , examples/passing/TypeOperators/*.purs
59 , examples/passing/TypeWithoutParens/*.purs
60 , examples/passing/TypeWithoutParens/*.purs
@@ -151,6 +152,7 @@ library
151 protolude >= 0.1.6,
152 protolude >= 0.1.6,
152 regex-tdfa -any,
153 regex-tdfa -any,
153 safe >= 0.3.9 && < 0.4,
154 safe >= 0.3.9 && < 0.4,
155+ scientific >= 0.3.4.9 && < 0.4,
154 semigroups >= 0.16.2 && < 0.19,
156 semigroups >= 0.16.2 && < 0.19,
155 sourcemap >= 0.1.6,
157 sourcemap >= 0.1.6,
156 spdx == 0.2.*,
158 spdx == 0.2.*,
@@ -221,6 +223,7 @@ library
221 Language.PureScript.Errors
223 Language.PureScript.Errors
222 Language.PureScript.Errors.JSON
224 Language.PureScript.Errors.JSON
223 Language.PureScript.Kinds
225 Language.PureScript.Kinds
226+ Language.PureScript.Label
224 Language.PureScript.Linter
227 Language.PureScript.Linter
225 Language.PureScript.Linter.Exhaustive
228 Language.PureScript.Linter.Exhaustive
226 Language.PureScript.Linter.Imports
229 Language.PureScript.Linter.Imports
@@ -241,6 +244,7 @@ library
241 Language.PureScript.Pretty.Kinds
244 Language.PureScript.Pretty.Kinds
242 Language.PureScript.Pretty.Types
245 Language.PureScript.Pretty.Types
243 Language.PureScript.Pretty.Values
246 Language.PureScript.Pretty.Values
247+ Language.PureScript.PSString
244 Language.PureScript.Renamer
248 Language.PureScript.Renamer
245 Language.PureScript.Sugar
249 Language.PureScript.Sugar
246 Language.PureScript.Sugar.BindingGroups
250 Language.PureScript.Sugar.BindingGroups
@@ -298,7 +302,6 @@ library
298 Language.PureScript.Ide.CaseSplit
302 Language.PureScript.Ide.CaseSplit
299 Language.PureScript.Ide.Command
303 Language.PureScript.Ide.Command
300 Language.PureScript.Ide.Completion
304 Language.PureScript.Ide.Completion
301โˆ’ Language.PureScript.Ide.Conversions
302 Language.PureScript.Ide.Externs
305 Language.PureScript.Ide.Externs
303 Language.PureScript.Ide.Error
306 Language.PureScript.Ide.Error
304 Language.PureScript.Ide.Filter
307 Language.PureScript.Ide.Filter
src/Language/PureScript/AST/Declarations.hs+9โˆ’6
@@ -18,6 +18,8 @@ import Language.PureScript.AST.Literals
18import Language.PureScript.AST.Operators
18import Language.PureScript.AST.Operators
19import Language.PureScript.AST.SourcePos
19import Language.PureScript.AST.SourcePos
20import Language.PureScript.Types
20import Language.PureScript.Types
21+import Language.PureScript.PSString (PSString)
22+import Language.PureScript.Label (Label)
21import Language.PureScript.Names
23import Language.PureScript.Names
22import Language.PureScript.Kinds
24import Language.PureScript.Kinds
23import Language.PureScript.TypeClassDictionaries
25import Language.PureScript.TypeClassDictionaries
@@ -90,7 +92,7 @@ data SimpleErrorMessage
90 | CannotDerive (Qualified (ProperName 'ClassName)) [Type]
92 | CannotDerive (Qualified (ProperName 'ClassName)) [Type]
91 | InvalidNewtypeInstance (Qualified (ProperName 'ClassName)) [Type]
93 | InvalidNewtypeInstance (Qualified (ProperName 'ClassName)) [Type]
92 | CannotFindDerivingType (ProperName 'TypeName)
94 | CannotFindDerivingType (ProperName 'TypeName)
93โˆ’ | DuplicateLabel Text (Maybe Expr)
95+ | DuplicateLabel Label (Maybe Expr)
94 | DuplicateValueDeclaration Ident
96 | DuplicateValueDeclaration Ident
95 | ArgListLengthsDiffer Ident
97 | ArgListLengthsDiffer Ident
96 | OverlappingArgNames (Maybe Ident)
98 | OverlappingArgNames (Maybe Ident)
@@ -99,8 +101,8 @@ data SimpleErrorMessage
99 | ExpectedType Type Kind
101 | ExpectedType Type Kind
100 | IncorrectConstructorArity (Qualified (ProperName 'ConstructorName))
102 | IncorrectConstructorArity (Qualified (ProperName 'ConstructorName))
101 | ExprDoesNotHaveType Expr Type
103 | ExprDoesNotHaveType Expr Type
102โˆ’ | PropertyIsMissing Text
104+ | PropertyIsMissing Label
103โˆ’ | AdditionalProperty Text
105+ | AdditionalProperty Label
104 | TypeSynonymInstance
106 | TypeSynonymInstance
105 | OrphanInstance Ident (Qualified (ProperName 'ClassName)) [Type]
107 | OrphanInstance Ident (Qualified (ProperName 'ClassName)) [Type]
106 | InvalidNewtype (ProperName 'TypeName)
108 | InvalidNewtype (ProperName 'TypeName)
@@ -136,6 +138,7 @@ data SimpleErrorMessage
136 | CannotGeneralizeRecursiveFunction Ident Type
138 | CannotGeneralizeRecursiveFunction Ident Type
137 | CannotDeriveNewtypeForData (ProperName 'TypeName)
139 | CannotDeriveNewtypeForData (ProperName 'TypeName)
138 | ExpectedWildcard (ProperName 'TypeName)
140 | ExpectedWildcard (ProperName 'TypeName)
141+ | CannotUseBindWithDo
139 deriving (Show)
142 deriving (Show)
140
143
141-- | Error message hints, providing more detailed information about failure.
144-- | Error message hints, providing more detailed information about failure.
@@ -145,7 +148,7 @@ data ErrorMessageHint
145 | ErrorInModule ModuleName
148 | ErrorInModule ModuleName
146 | ErrorInInstance (Qualified (ProperName 'ClassName)) [Type]
149 | ErrorInInstance (Qualified (ProperName 'ClassName)) [Type]
147 | ErrorInSubsumption Type Type
150 | ErrorInSubsumption Type Type
148โˆ’ | ErrorCheckingAccessor Expr Text
151+ | ErrorCheckingAccessor Expr PSString
149 | ErrorCheckingType Expr Type
152 | ErrorCheckingType Expr Type
150 | ErrorCheckingKind Type
153 | ErrorCheckingKind Type
151 | ErrorCheckingGuard
154 | ErrorCheckingGuard
@@ -573,11 +576,11 @@ data Expr
573 -- Anonymous arguments will be removed during desugaring and expanded
576 -- Anonymous arguments will be removed during desugaring and expanded
574 -- into a lambda that reads a property from a record.
577 -- into a lambda that reads a property from a record.
575 --
578 --
576โˆ’ | Accessor Text Expr
579+ | Accessor PSString Expr
577 -- |
580 -- |
578 -- Partial record update
581 -- Partial record update
579 --
582 --
580โˆ’ | ObjectUpdate Expr [(Text, Expr)]
583+ | ObjectUpdate Expr [(PSString, Expr)]
581 -- |
584 -- |
582 -- Function introduction
585 -- Function introduction
583 --
586 --
src/Language/PureScript/AST/Literals.hs+3โˆ’3
@@ -4,7 +4,7 @@
4module Language.PureScript.AST.Literals where
4module Language.PureScript.AST.Literals where
5
5
6import Prelude.Compat
6import Prelude.Compat
7โˆ’import Data.Text (Text)
7+import Language.PureScript.PSString (PSString)
8
8
9-- |
9-- |
10-- Data type for literal values. Parameterised so it can be used for Exprs and
10-- Data type for literal values. Parameterised so it can be used for Exprs and
@@ -18,7 +18,7 @@ data Literal a
18 -- |
18 -- |
19 -- A string literal
19 -- A string literal
20 --
20 --
21โˆ’ | StringLiteral Text
21+ | StringLiteral PSString
22 -- |
22 -- |
23 -- A character literal
23 -- A character literal
24 --
24 --
@@ -34,5 +34,5 @@ data Literal a
34 -- |
34 -- |
35 -- An object literal
35 -- An object literal
36 --
36 --
37โˆ’ | ObjectLiteral [(Text, a)]
37+ | ObjectLiteral [(PSString, a)]
38 deriving (Eq, Ord, Show, Functor)
38 deriving (Eq, Ord, Show, Functor)
src/Language/PureScript/CodeGen/JS.hs+20โˆ’14
@@ -20,6 +20,7 @@ import qualified Data.Foldable as F
20import qualified Data.Map as M
20import qualified Data.Map as M
21import Data.Maybe (fromMaybe, isNothing)
21import Data.Maybe (fromMaybe, isNothing)
22import Data.Monoid ((<>))
22import Data.Monoid ((<>))
23+import Data.String (fromString)
23import Data.Text (Text)
24import Data.Text (Text)
24import qualified Data.Text as T
25import qualified Data.Text as T
25
26
@@ -34,6 +35,7 @@ import Language.PureScript.Errors (ErrorMessageHint(..), SimpleErrorMessage(..),
34 errorMessage, rethrowWithPosition, addHint)
35 errorMessage, rethrowWithPosition, addHint)
35import Language.PureScript.Names
36import Language.PureScript.Names
36import Language.PureScript.Options
37import Language.PureScript.Options
38+import Language.PureScript.PSString (PSString, mkString, decodeString)
37import Language.PureScript.Traversals (sndM)
39import Language.PureScript.Traversals (sndM)
38import qualified Language.PureScript.Constants as C
40import qualified Language.PureScript.Constants as C
39
41
@@ -65,8 +67,8 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
65 let moduleBody = header : foreign' ++ jsImports ++ concat optimized
67 let moduleBody = header : foreign' ++ jsImports ++ concat optimized
66 let foreignExps = exps `intersect` (fst `map` foreigns)
68 let foreignExps = exps `intersect` (fst `map` foreigns)
67 let standardExps = exps \\ foreignExps
69 let standardExps = exps \\ foreignExps
68โˆ’ let exps' = JSObjectLiteral Nothing $ map (runIdent &&& JSVar Nothing . identToJs) standardExps
70+ let exps' = JSObjectLiteral Nothing $ map (mkString . runIdent &&& JSVar Nothing . identToJs) standardExps
69โˆ’ ++ map (runIdent &&& foreignIdent) foreignExps
71+ ++ map (mkString . runIdent &&& foreignIdent) foreignExps
70 return $ moduleBody ++ [JSAssignment Nothing (JSAccessor Nothing "exports" (JSVar Nothing "module")) exps']
72 return $ moduleBody ++ [JSAssignment Nothing (JSAccessor Nothing "exports" (JSVar Nothing "module")) exps']
71
73
72 where
74 where
@@ -108,7 +110,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
108 importToJs :: M.Map ModuleName (Ann, ModuleName) -> ModuleName -> m JS
110 importToJs :: M.Map ModuleName (Ann, ModuleName) -> ModuleName -> m JS
109 importToJs mnLookup mn' = do
111 importToJs mnLookup mn' = do
110 let ((ss, _, _, _), mnSafe) = fromMaybe (internalError "Missing value in mnLookup") $ M.lookup mn' mnLookup
112 let ((ss, _, _, _), mnSafe) = fromMaybe (internalError "Missing value in mnLookup") $ M.lookup mn' mnLookup
111โˆ’ let moduleBody = JSApp Nothing (JSVar Nothing "require") [JSStringLiteral Nothing (T.pack (".." </> T.unpack (runModuleName mn')))]
113+ let moduleBody = JSApp Nothing (JSVar Nothing "require") [JSStringLiteral Nothing (fromString (".." </> T.unpack (runModuleName mn')))]
112 withPos ss $ JSVariableIntroduction Nothing (moduleNameToJs mnSafe) (Just moduleBody)
114 withPos ss $ JSVariableIntroduction Nothing (moduleNameToJs mnSafe) (Just moduleBody)
113
115
114 -- |
116 -- |
@@ -176,12 +178,16 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
176 -- indexer is returned.
178 -- indexer is returned.
177 --
179 --
178 accessor :: Ident -> JS -> JS
180 accessor :: Ident -> JS -> JS
179โˆ’ accessor (Ident prop) = accessorString prop
181+ accessor (Ident prop) = accessorString $ mkString prop
180 accessor (GenIdent _ _) = internalError "GenIdent in accessor"
182 accessor (GenIdent _ _) = internalError "GenIdent in accessor"
181
183
182โˆ’ accessorString :: Text -> JS -> JS
184+ accessorString :: PSString -> JS -> JS
185+ accessorString prop =
186+ case decodeString prop of
187+ Just s | not (identNeedsEscaping s) ->
188+ JSAccessor Nothing s
189+ _ ->
183โˆ’ accessorString prop | identNeedsEscaping prop = JSIndexer Nothing (JSStringLiteral Nothing prop)
190+ JSIndexer Nothing (JSStringLiteral Nothing prop)
184โˆ’ | otherwise = JSAccessor Nothing prop
185
191
186 -- |
192 -- |
187 -- Generate code in the simplified Javascript intermediate representation for a value or expression.
193 -- Generate code in the simplified Javascript intermediate representation for a value or expression.
@@ -212,7 +218,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
212 unAbs (Abs _ arg val) = arg : unAbs val
218 unAbs (Abs _ arg val) = arg : unAbs val
213 unAbs _ = []
219 unAbs _ = []
214 assign :: Ident -> JS
220 assign :: Ident -> JS
215โˆ’ assign name = JSAssignment Nothing (accessorString (runIdent name) (JSVar Nothing "this"))
221+ assign name = JSAssignment Nothing (accessorString (mkString $ runIdent name) (JSVar Nothing "this"))
216 (var name)
222 (var name)
217 valueToJs' (Abs _ arg val) = do
223 valueToJs' (Abs _ arg val) = do
218 ret <- valueToJs val
224 ret <- valueToJs val
@@ -272,7 +278,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
272 literalToValueJS (NumericLiteral (Left i)) = return $ JSNumericLiteral Nothing (Left i)
278 literalToValueJS (NumericLiteral (Left i)) = return $ JSNumericLiteral Nothing (Left i)
273 literalToValueJS (NumericLiteral (Right n)) = return $ JSNumericLiteral Nothing (Right n)
279 literalToValueJS (NumericLiteral (Right n)) = return $ JSNumericLiteral Nothing (Right n)
274 literalToValueJS (StringLiteral s) = return $ JSStringLiteral Nothing s
280 literalToValueJS (StringLiteral s) = return $ JSStringLiteral Nothing s
275โˆ’ literalToValueJS (CharLiteral c) = return $ JSStringLiteral Nothing (T.singleton c)
281+ literalToValueJS (CharLiteral c) = return $ JSStringLiteral Nothing (fromString [c])
276 literalToValueJS (BooleanLiteral b) = return $ JSBooleanLiteral Nothing b
282 literalToValueJS (BooleanLiteral b) = return $ JSBooleanLiteral Nothing b
277 literalToValueJS (ArrayLiteral xs) = JSArrayLiteral Nothing <$> mapM valueToJs xs
283 literalToValueJS (ArrayLiteral xs) = JSArrayLiteral Nothing <$> mapM valueToJs xs
278 literalToValueJS (ObjectLiteral ps) = JSObjectLiteral Nothing <$> mapM (sndM valueToJs) ps
284 literalToValueJS (ObjectLiteral ps) = JSObjectLiteral Nothing <$> mapM (sndM valueToJs) ps
@@ -280,7 +286,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
280 -- |
286 -- |
281 -- Shallow copy an object.
287 -- Shallow copy an object.
282 --
288 --
283โˆ’ extendObj :: JS -> [(Text, JS)] -> m JS
289+ extendObj :: JS -> [(PSString, JS)] -> m JS
284 extendObj obj sts = do
290 extendObj obj sts = do
285 newObj <- freshName
291 newObj <- freshName
286 key <- freshName
292 key <- freshName
@@ -317,7 +323,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
317 qualifiedToJS f (Qualified _ a) = JSVar Nothing $ identToJs (f a)
323 qualifiedToJS f (Qualified _ a) = JSVar Nothing $ identToJs (f a)
318
324
319 foreignIdent :: Ident -> JS
325 foreignIdent :: Ident -> JS
320โˆ’ foreignIdent ident = accessorString (runIdent ident) (JSVar Nothing "$foreign")
326+ foreignIdent ident = accessorString (mkString $ runIdent ident) (JSVar Nothing "$foreign")
321
327
322 -- |
328 -- |
323 -- Generate code in the simplified Javascript intermediate representation for pattern match binders
329 -- Generate code in the simplified Javascript intermediate representation for pattern match binders
@@ -341,7 +347,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
341 go _ _ _ = internalError "Invalid arguments to bindersToJs"
347 go _ _ _ = internalError "Invalid arguments to bindersToJs"
342
348
343 failedPatternError :: [Text] -> JS
349 failedPatternError :: [Text] -> JS
344โˆ’ failedPatternError names = JSUnary Nothing JSNew $ JSApp Nothing (JSVar Nothing "Error") [JSBinary Nothing Add (JSStringLiteral Nothing failedPatternMessage) (JSArrayLiteral Nothing $ zipWith valueError names vals)]
350+ failedPatternError names = JSUnary Nothing JSNew $ JSApp Nothing (JSVar Nothing "Error") [JSBinary Nothing Add (JSStringLiteral Nothing $ mkString failedPatternMessage) (JSArrayLiteral Nothing $ zipWith valueError names vals)]
345
351
346 failedPatternMessage :: Text
352 failedPatternMessage :: Text
347 failedPatternMessage = "Failed pattern match" <> maybe "" (((" at " <> runModuleName mn <> " ") <>) . displayStartEndPos) maybeSpan <> ": "
353 failedPatternMessage = "Failed pattern match" <> maybe "" (((" at " <> runModuleName mn <> " ") <>) . displayStartEndPos) maybeSpan <> ": "
@@ -402,7 +408,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
402 literalToBinderJS varName done (NumericLiteral num) =
408 literalToBinderJS varName done (NumericLiteral num) =
403 return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSNumericLiteral Nothing num)) (JSBlock Nothing done) Nothing]
409 return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSNumericLiteral Nothing num)) (JSBlock Nothing done) Nothing]
404 literalToBinderJS varName done (CharLiteral c) =
410 literalToBinderJS varName done (CharLiteral c) =
405โˆ’ return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSStringLiteral Nothing (T.singleton c))) (JSBlock Nothing done) Nothing]
411+ return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSStringLiteral Nothing (fromString [c]))) (JSBlock Nothing done) Nothing]
406 literalToBinderJS varName done (StringLiteral str) =
412 literalToBinderJS varName done (StringLiteral str) =
407 return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSStringLiteral Nothing str)) (JSBlock Nothing done) Nothing]
413 return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSStringLiteral Nothing str)) (JSBlock Nothing done) Nothing]
408 literalToBinderJS varName done (BooleanLiteral True) =
414 literalToBinderJS varName done (BooleanLiteral True) =
@@ -411,7 +417,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
411 return [JSIfElse Nothing (JSUnary Nothing Not (JSVar Nothing varName)) (JSBlock Nothing done) Nothing]
417 return [JSIfElse Nothing (JSUnary Nothing Not (JSVar Nothing varName)) (JSBlock Nothing done) Nothing]
412 literalToBinderJS varName done (ObjectLiteral bs) = go done bs
418 literalToBinderJS varName done (ObjectLiteral bs) = go done bs
413 where
419 where
414โˆ’ go :: [JS] -> [(Text, Binder Ann)] -> m [JS]
420+ go :: [JS] -> [(PSString, Binder Ann)] -> m [JS]
415 go done' [] = return done'
421 go done' [] = return done'
416 go done' ((prop, binder):bs') = do
422 go done' ((prop, binder):bs') = do
417 propVar <- freshName
423 propVar <- freshName
src/Language/PureScript/CodeGen/JS/AST.hs+5โˆ’3
@@ -11,6 +11,7 @@ import Data.Text (Text)
11
11
12import Language.PureScript.AST (SourceSpan(..))
12import Language.PureScript.AST (SourceSpan(..))
13import Language.PureScript.Comments
13import Language.PureScript.Comments
14+import Language.PureScript.PSString (PSString)
14import Language.PureScript.Traversals
15import Language.PureScript.Traversals
15
16
16-- |
17-- |
@@ -132,7 +133,7 @@ data JS
132 -- |
133 -- |
133 -- A string literal
134 -- A string literal
134 --
135 --
135โˆ’ | JSStringLiteral (Maybe SourceSpan) Text
136+ | JSStringLiteral (Maybe SourceSpan) PSString
136 -- |
137 -- |
137 -- A boolean literal
138 -- A boolean literal
138 --
139 --
@@ -156,7 +157,7 @@ data JS
156 -- |
157 -- |
157 -- An object literal
158 -- An object literal
158 --
159 --
159โˆ’ | JSObjectLiteral (Maybe SourceSpan) [(Text, JS)]
160+ | JSObjectLiteral (Maybe SourceSpan) [(PSString, JS)]
160 -- |
161 -- |
161 -- An object property accessor expression
162 -- An object property accessor expression
162 --
163 --
@@ -240,7 +241,8 @@ data JS
240 -- |
241 -- |
241 -- Commented Javascript
242 -- Commented Javascript
242 --
243 --
243โˆ’ | JSComment (Maybe SourceSpan) [Comment] JS deriving (Show, Eq)
244+ | JSComment (Maybe SourceSpan) [Comment] JS
245+ deriving (Show, Eq)
244
246
245withSourceSpan :: SourceSpan -> JS -> JS
247withSourceSpan :: SourceSpan -> JS -> JS
246withSourceSpan withSpan = go
248withSourceSpan withSpan = go
src/Language/PureScript/CodeGen/JS/Optimizer/Common.hs+2โˆ’1
@@ -11,6 +11,7 @@ import Data.Maybe (fromMaybe)
11
11
12import Language.PureScript.Crash
12import Language.PureScript.Crash
13import Language.PureScript.CodeGen.JS.AST
13import Language.PureScript.CodeGen.JS.AST
14+import Language.PureScript.PSString (mkString)
14
15
15applyAll :: [a -> a] -> a -> a
16applyAll :: [a -> a] -> a -> a
16applyAll = foldl' (.) id
17applyAll = foldl' (.) id
@@ -73,7 +74,7 @@ isFn :: (Text, Text) -> JS -> Bool
73isFn (moduleName, fnName) (JSAccessor _ x (JSVar _ y)) =
74isFn (moduleName, fnName) (JSAccessor _ x (JSVar _ y)) =
74 x == fnName && y == moduleName
75 x == fnName && y == moduleName
75isFn (moduleName, fnName) (JSIndexer _ (JSStringLiteral _ x) (JSVar _ y)) =
76isFn (moduleName, fnName) (JSIndexer _ (JSStringLiteral _ x) (JSVar _ y)) =
76โˆ’ x == fnName && y == moduleName
77+ x == mkString fnName && y == moduleName
77isFn _ _ = False
78isFn _ _ = False
78
79
79isDict :: (Text, Text) -> JS -> Bool
80isDict :: (Text, Text) -> JS -> Bool
src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs+1โˆ’1
@@ -239,7 +239,7 @@ inlineCommonOperators = applyAll $
239 isModFn _ _ = False
239 isModFn _ _ = False
240
240
241 isModFnWithDict :: (Text, Text) -> JS -> Bool
241 isModFnWithDict :: (Text, Text) -> JS -> Bool
242โˆ’ isModFnWithDict (m, op) (JSApp _ (JSAccessor _ op' (JSVar _ m')) [(JSVar _ _)]) = m == m' && op == op'
242+ isModFnWithDict (m, op) (JSApp _ (JSAccessor _ op' (JSVar _ m')) [JSVar _ _]) = m == m' && op == op'
243 isModFnWithDict _ _ = False
243 isModFnWithDict _ _ = False
244
244
245-- (f <<< g $ x) = f (g x)
245-- (f <<< g $ x) = f (g x)
src/Language/PureScript/CodeGen/JS/Optimizer/MagicDo.hs+2โˆ’1
@@ -12,6 +12,7 @@ import Data.Maybe (fromJust, isJust)
12import Language.PureScript.CodeGen.JS.AST
12import Language.PureScript.CodeGen.JS.AST
13import Language.PureScript.CodeGen.JS.Optimizer.Common
13import Language.PureScript.CodeGen.JS.Optimizer.Common
14import Language.PureScript.Options
14import Language.PureScript.Options
15+import Language.PureScript.PSString (mkString)
15import qualified Language.PureScript.Constants as C
16import qualified Language.PureScript.Constants as C
16
17
17magicDo :: Options -> JS -> JS
18magicDo :: Options -> JS -> JS
@@ -104,7 +105,7 @@ inlineST = everywhereOnJS convertBlock
104 -- or in a more aggressive way, turning wrappers into local variables depending on the
105 -- or in a more aggressive way, turning wrappers into local variables depending on the
105 -- agg(ressive) parameter.
106 -- agg(ressive) parameter.
106 convert agg (JSApp s1 f [arg]) | isSTFunc C.newSTRef f =
107 convert agg (JSApp s1 f [arg]) | isSTFunc C.newSTRef f =
107โˆ’ JSFunction s1 Nothing [] (JSBlock s1 [JSReturn s1 $ if agg then arg else JSObjectLiteral s1 [(C.stRefValue, arg)]])
108+ JSFunction s1 Nothing [] (JSBlock s1 [JSReturn s1 $ if agg then arg else JSObjectLiteral s1 [(mkString C.stRefValue, arg)]])
108 convert agg (JSApp _ (JSApp s1 f [ref]) []) | isSTFunc C.readSTRef f =
109 convert agg (JSApp _ (JSApp s1 f [ref]) []) | isSTFunc C.readSTRef f =
109 if agg then ref else JSAccessor s1 C.stRefValue ref
110 if agg then ref else JSAccessor s1 C.stRefValue ref
110 convert agg (JSApp _ (JSApp _ (JSApp s1 f [ref]) [arg]) []) | isSTFunc C.writeSTRef f =
111 convert agg (JSApp _ (JSApp _ (JSApp s1 f [ref]) [arg]) []) | isSTFunc C.writeSTRef f =
src/Language/PureScript/CoreFn/Desugar.hs+3โˆ’2
@@ -24,6 +24,7 @@ import Language.PureScript.Environment
24import Language.PureScript.Names
24import Language.PureScript.Names
25import Language.PureScript.Sugar.TypeClasses (typeClassMemberName, superClassDictionaryNames)
25import Language.PureScript.Sugar.TypeClasses (typeClassMemberName, superClassDictionaryNames)
26import Language.PureScript.Types
26import Language.PureScript.Types
27+import Language.PureScript.PSString (mkString)
27import qualified Language.PureScript.AST as A
28import qualified Language.PureScript.AST as A
28
29
29-- |
30-- |
@@ -119,7 +120,7 @@ moduleToCoreFn env (A.Module _ coms mn decls (Just exps)) =
119 in foldl (App (ss, com, Nothing, Nothing)) ctor args
120 in foldl (App (ss, com, Nothing, Nothing)) ctor args
120 exprToCoreFn ss com ty (A.TypeClassDictionaryAccessor _ ident) =
121 exprToCoreFn ss com ty (A.TypeClassDictionaryAccessor _ ident) =
121 Abs (ss, com, ty, Nothing) (Ident "dict")
122 Abs (ss, com, ty, Nothing) (Ident "dict")
122โˆ’ (Accessor nullAnn (runIdent ident) (Var nullAnn $ Qualified Nothing (Ident "dict")))
123+ (Accessor nullAnn (mkString $ runIdent ident) (Var nullAnn $ Qualified Nothing (Ident "dict")))
123 exprToCoreFn _ com ty (A.PositionedValue ss com1 v) =
124 exprToCoreFn _ com ty (A.PositionedValue ss com1 v) =
124 exprToCoreFn (Just ss) (com ++ com1) ty v
125 exprToCoreFn (Just ss) (com ++ com1) ty v
125 exprToCoreFn _ _ _ e =
126 exprToCoreFn _ _ _ e =
@@ -265,7 +266,7 @@ mkTypeClassConstructor :: Maybe SourceSpan -> [Comment] -> [Constraint] -> [A.De
265mkTypeClassConstructor ss com [] [] = Literal (ss, com, Nothing, Just IsTypeClassConstructor) (ObjectLiteral [])
266mkTypeClassConstructor ss com [] [] = Literal (ss, com, Nothing, Just IsTypeClassConstructor) (ObjectLiteral [])
266mkTypeClassConstructor ss com supers members =
267mkTypeClassConstructor ss com supers members =
267 let args@(a:as) = sort $ map typeClassMemberName members ++ superClassDictionaryNames supers
268 let args@(a:as) = sort $ map typeClassMemberName members ++ superClassDictionaryNames supers
268โˆ’ props = [ (arg, Var nullAnn $ Qualified Nothing (Ident arg)) | arg <- args ]
269+ props = [ (mkString arg, Var nullAnn $ Qualified Nothing (Ident arg)) | arg <- args ]
269 dict = Literal nullAnn (ObjectLiteral props)
270 dict = Literal nullAnn (ObjectLiteral props)
270 in Abs (ss, com, Nothing, Just IsTypeClassConstructor)
271 in Abs (ss, com, Nothing, Just IsTypeClassConstructor)
271 (Ident a)
272 (Ident a)
src/Language/PureScript/CoreFn/Expr.hs+3โˆ’3
@@ -6,11 +6,11 @@ module Language.PureScript.CoreFn.Expr where
6import Prelude.Compat
6import Prelude.Compat
7
7
8import Control.Arrow ((***))
8import Control.Arrow ((***))
9โˆ’import Data.Text (Text)
10
9
11import Language.PureScript.AST.Literals
10import Language.PureScript.AST.Literals
12import Language.PureScript.CoreFn.Binders
11import Language.PureScript.CoreFn.Binders
13import Language.PureScript.Names
12import Language.PureScript.Names
13+import Language.PureScript.PSString (PSString)
14
14
15-- |
15-- |
16-- Data type for expressions and terms
16-- Data type for expressions and terms
@@ -27,11 +27,11 @@ data Expr a
27 -- |
27 -- |
28 -- A record property accessor
28 -- A record property accessor
29 --
29 --
30โˆ’ | Accessor a Text (Expr a)
30+ | Accessor a PSString (Expr a)
31 -- |
31 -- |
32 -- Partial record update
32 -- Partial record update
33 --
33 --
34โˆ’ | ObjectUpdate a (Expr a) [(Text, Expr a)]
34+ | ObjectUpdate a (Expr a) [(PSString, Expr a)]
35 -- |
35 -- |
36 -- Function introduction
36 -- Function introduction
37 --
37 --
src/Language/PureScript/CoreFn/ToJSON.hs+13โˆ’2
@@ -9,6 +9,7 @@ module Language.PureScript.CoreFn.ToJSON
9
9
10import Prelude.Compat
10import Prelude.Compat
11
11
12+import Data.Maybe (fromMaybe)
12import Data.Aeson
13import Data.Aeson
13import Data.Version (Version, showVersion)
14import Data.Version (Version, showVersion)
14import Data.Text (Text)
15import Data.Text (Text)
@@ -17,6 +18,7 @@ import qualified Data.Text as T
17import Language.PureScript.AST.Literals
18import Language.PureScript.AST.Literals
18import Language.PureScript.CoreFn
19import Language.PureScript.CoreFn
19import Language.PureScript.Names
20import Language.PureScript.Names
21+import Language.PureScript.PSString (PSString, decodeString)
20
22
21literalToJSON :: (a -> Value) -> Literal a -> Value
23literalToJSON :: (a -> Value) -> Literal a -> Value
22literalToJSON _ (NumericLiteral (Left n)) = toJSON ("IntLiteral", n)
24literalToJSON _ (NumericLiteral (Left n)) = toJSON ("IntLiteral", n)
@@ -51,8 +53,17 @@ bindToJSON :: Bind a -> Value
51bindToJSON (NonRec _ n e) = object [ runIdent n .= exprToJSON e ]
53bindToJSON (NonRec _ n e) = object [ runIdent n .= exprToJSON e ]
52bindToJSON (Rec bs) = object $ map (\((_, n), e) -> runIdent n .= exprToJSON e) bs
54bindToJSON (Rec bs) = object $ map (\((_, n), e) -> runIdent n .= exprToJSON e) bs
53
55
56+-- If all of the labels in the record can safely be converted to JSON strings,
57+-- we generate a JSON object. Otherwise the labels must be represented as
58+-- arrays of integers in the JSON, and in this case we generate the record as
59+-- an array of pairs.
54โˆ’recordToJSON :: (a -> Value) -> [(Text, a)] -> Value
60+recordToJSON :: (a -> Value) -> [(PSString, a)] -> Value
61+recordToJSON f rec = fromMaybe (asArrayOfPairs rec) (asObject rec)
62+ where
63+ asObject = fmap object . traverse (uncurry maybePair)
64+ maybePair label a = fmap (\l -> l .= f a) (decodeString label)
65+
55โˆ’recordToJSON f = object . map (\(label, a) -> label .= f a)
66+ asArrayOfPairs = toJSON . map (\(label, a) -> (toJSON label, f a))
56
67
57exprToJSON :: Expr a -> Value
68exprToJSON :: Expr a -> Value
58exprToJSON (Var _ i) = toJSON ( "Var"
69exprToJSON (Var _ i) = toJSON ( "Var"
src/Language/PureScript/Docs/Convert/ReExports.hs+2โˆ’5
@@ -457,11 +457,8 @@ handleEnv TypeClassEnv{..} =
457 addConstraint constraint =
457 addConstraint constraint =
458 P.quantify . P.moveQuantifiersToFront . P.ConstrainedType [constraint]
458 P.quantify . P.moveQuantifiersToFront . P.ConstrainedType [constraint]
459
459
460โˆ’splitMap :: (Ord k) => Map k (v1, v2) -> (Map k v1, Map k v2)
460+splitMap :: Map k (v1, v2) -> (Map k v1, Map k v2)
461โˆ’splitMap = foldl go (Map.empty, Map.empty) . Map.toList
461+splitMap = fmap fst &&& fmap snd
462โˆ’ where
463โˆ’ go (m1, m2) (k, (v1, v2)) =
464โˆ’ (Map.insert k v1 m1, Map.insert k v2 m2)
465
462
466-- |
463-- |
467-- Given a list of exported constructor names, remove any data constructor
464-- Given a list of exported constructor names, remove any data constructor
src/Language/PureScript/Docs/Convert/Single.hs+4โˆ’10
@@ -3,16 +3,10 @@ module Language.PureScript.Docs.Convert.Single
3 , collectBookmarks
3 , collectBookmarks
4 ) where
4 ) where
5
5
6โˆ’import Prelude.Compat
6+import Protolude
7
7
8import Control.Category ((>>>))
8import Control.Category ((>>>))
9โˆ’import Control.Monad
10
9
11โˆ’import Data.Either
12โˆ’import Data.List (nub)
13โˆ’import Data.Maybe (mapMaybe, fromMaybe)
14โˆ’import Data.Monoid ((<>))
15โˆ’import Data.Text (Text)
16import qualified Data.Text as T
10import qualified Data.Text as T
17
11
18import Language.PureScript.Docs.Types
12import Language.PureScript.Docs.Types
@@ -67,7 +61,7 @@ data DeclarationAugment
67-- the type synonym IntermediateDeclaration for more information.
61-- the type synonym IntermediateDeclaration for more information.
68augmentDeclarations :: [IntermediateDeclaration] -> [Declaration]
62augmentDeclarations :: [IntermediateDeclaration] -> [Declaration]
69augmentDeclarations (partitionEithers -> (augments, toplevels)) =
63augmentDeclarations (partitionEithers -> (augments, toplevels)) =
70โˆ’ foldl go toplevels augments
64+ foldl' go toplevels augments
71 where
65 where
72 go ds (parentTitles, a) =
66 go ds (parentTitles, a) =
73 map (\d ->
67 map (\d ->
@@ -142,14 +136,14 @@ convertDeclaration (P.TypeInstanceDeclaration _ constraints className tys _) tit
142 Just (Left (classNameString : typeNameStrings, AugmentChild childDecl))
136 Just (Left (classNameString : typeNameStrings, AugmentChild childDecl))
143 where
137 where
144 classNameString = unQual className
138 classNameString = unQual className
145โˆ’ typeNameStrings = nub (concatMap (P.everythingOnTypes (++) extractProperNames) tys)
139+ typeNameStrings = ordNub (concatMap (P.everythingOnTypes (++) extractProperNames) tys)
146 unQual x = let (P.Qualified _ y) = x in P.runProperName y
140 unQual x = let (P.Qualified _ y) = x in P.runProperName y
147
141
148 extractProperNames (P.TypeConstructor n) = [unQual n]
142 extractProperNames (P.TypeConstructor n) = [unQual n]
149 extractProperNames _ = []
143 extractProperNames _ = []
150
144
151 childDecl = ChildDeclaration title Nothing Nothing (ChildInstance constraints classApp)
145 childDecl = ChildDeclaration title Nothing Nothing (ChildInstance constraints classApp)
152โˆ’ classApp = foldl P.TypeApp (P.TypeConstructor (fmap P.coerceProperName className)) tys
146+ classApp = foldl' P.TypeApp (P.TypeConstructor (fmap P.coerceProperName className)) tys
153convertDeclaration (P.ValueFixityDeclaration fixity (P.Qualified mn alias) _) title =
147convertDeclaration (P.ValueFixityDeclaration fixity (P.Qualified mn alias) _) title =
154 Just $ Right $ mkDeclaration title (AliasDeclaration fixity (P.Qualified mn (Right alias)))
148 Just $ Right $ mkDeclaration title (AliasDeclaration fixity (P.Qualified mn (Right alias)))
155convertDeclaration (P.TypeFixityDeclaration fixity (P.Qualified mn alias) _) title =
149convertDeclaration (P.TypeFixityDeclaration fixity (P.Qualified mn alias) _) title =
src/Language/PureScript/Docs/ParseAndBookmark.hs+3โˆ’7
@@ -2,14 +2,10 @@ module Language.PureScript.Docs.ParseAndBookmark
2 ( parseAndBookmark
2 ( parseAndBookmark
3 ) where
3 ) where
4
4
5+import Protolude
5โˆ’import Prelude.Compat
6+import Prelude (id)
6โˆ’
7โˆ’import Control.Arrow (first)
8โˆ’import Control.Monad.Error.Class (MonadError(..))
9โˆ’import Control.Monad.IO.Class (MonadIO(..))
10
7
11import qualified Data.Map as M
8import qualified Data.Map as M
12โˆ’import Data.Text (Text)
13
9
14import Language.PureScript.Docs.Convert (collectBookmarks)
10import Language.PureScript.Docs.Convert (collectBookmarks)
15import Language.PureScript.Docs.Types
11import Language.PureScript.Docs.Types
@@ -83,7 +79,7 @@ parseAs :: (MonadIO m) => (FilePath -> a) -> FilePath -> m (a, Text)
83parseAs g = fmap (first g) . liftIO . parseFile
79parseAs g = fmap (first g) . liftIO . parseFile
84
80
85getDepsModuleNames :: [InPackage (FilePath, P.Module)] -> M.Map P.ModuleName PackageName
81getDepsModuleNames :: [InPackage (FilePath, P.Module)] -> M.Map P.ModuleName PackageName
86โˆ’getDepsModuleNames = foldl go M.empty
82+getDepsModuleNames = foldl' go M.empty
87 where
83 where
88 go deps p = deps # case p of
84 go deps p = deps # case p of
89 Local _ -> id
85 Local _ -> id
src/Language/PureScript/Docs/RenderedCode/Render.hs+7โˆ’5
@@ -26,7 +26,9 @@ import Language.PureScript.Environment
26import Language.PureScript.Kinds
26import Language.PureScript.Kinds
27import Language.PureScript.Names
27import Language.PureScript.Names
28import Language.PureScript.Pretty.Kinds
28import Language.PureScript.Pretty.Kinds
29+import Language.PureScript.Pretty.Types
29import Language.PureScript.Types
30import Language.PureScript.Types
31+import Language.PureScript.Label (Label)
30
32
31typeLiterals :: Pattern () Type RenderedCode
33typeLiterals :: Pattern () Type RenderedCode
32typeLiterals = mkPattern match
34typeLiterals = mkPattern match
@@ -79,13 +81,13 @@ renderRow = uncurry renderRow' . rowToList
79 where
81 where
80 renderRow' h t = renderHead h <> renderTail t
82 renderRow' h t = renderHead h <> renderTail t
81
83
82โˆ’renderHead :: [(Text, Type)] -> RenderedCode
84+renderHead :: [(Label, Type)] -> RenderedCode
83renderHead = mintersperse (syntax "," <> sp) . map renderLabel
85renderHead = mintersperse (syntax "," <> sp) . map renderLabel
84
86
85โˆ’renderLabel :: (Text, Type) -> RenderedCode
87+renderLabel :: (Label, Type) -> RenderedCode
86renderLabel (label, ty) =
88renderLabel (label, ty) =
87 mintersperse sp
89 mintersperse sp
88โˆ’ [ ident label
90+ [ syntax $ prettyPrintLabel label
89 , syntax "::"
91 , syntax "::"
90 , renderType ty
92 , renderType ty
91 ]
93 ]
@@ -125,9 +127,9 @@ explicitParens = mkPattern match
125 match _ = Nothing
127 match _ = Nothing
126
128
127matchTypeAtom :: Pattern () Type RenderedCode
129matchTypeAtom :: Pattern () Type RenderedCode
128โˆ’matchTypeAtom = typeLiterals <+> fmap parens matchType
130+matchTypeAtom = typeLiterals <+> fmap parens_ matchType
129 where
131 where
130โˆ’ parens x = syntax "(" <> x <> syntax ")"
132+ parens_ x = syntax "(" <> x <> syntax ")"
131
133
132matchType :: Pattern () Type RenderedCode
134matchType :: Pattern () Type RenderedCode
133matchType = buildPrettyPrinter operators matchTypeAtom
135matchType = buildPrettyPrinter operators matchTypeAtom
src/Language/PureScript/Docs/Types.hs+44โˆ’5
@@ -10,17 +10,19 @@ import Control.Arrow (first, (***))
10import Control.Monad (when)
10import Control.Monad (when)
11import Control.Monad.Error.Class (catchError)
11import Control.Monad.Error.Class (catchError)
12
12
13โˆ’import Data.Monoid ((<>))
14import Data.Aeson ((.=))
13import Data.Aeson ((.=))
15import Data.Aeson.BetterErrors
14import Data.Aeson.BetterErrors
16import Data.ByteString.Lazy (ByteString)
15import Data.ByteString.Lazy (ByteString)
17import Data.Either (isLeft, isRight)
16import Data.Either (isLeft, isRight)
18โˆ’import Data.Maybe (mapMaybe, fromMaybe)
17+import Data.Maybe (mapMaybe, fromMaybe, maybeToList)
18+import Data.Monoid ((<>))
19import Data.Text (Text)
19import Data.Text (Text)
20+import Data.Time.Clock (UTCTime)
21+import qualified Data.Time.Format as TimeFormat
20import Data.Version
22import Data.Version
21โˆ’import qualified Data.Vector as V
22import qualified Data.Aeson as A
23import qualified Data.Aeson as A
23import qualified Data.Text as T
24import qualified Data.Text as T
25+import qualified Data.Vector as V
24
26
25import qualified Language.PureScript as P
27import qualified Language.PureScript as P
26
28
@@ -40,6 +42,10 @@ data Package a = Package
40 { pkgMeta :: PackageMeta
42 { pkgMeta :: PackageMeta
41 , pkgVersion :: Version
43 , pkgVersion :: Version
42 , pkgVersionTag :: Text
44 , pkgVersionTag :: Text
45+ -- TODO: When this field was introduced, it was given the Maybe type for the
46+ -- sake of backwards compatibility, as older JSON blobs will not include the
47+ -- field. It should eventually be changed to just UTCTime.
48+ , pkgTagTime :: Maybe UTCTime
43 , pkgModules :: [Module]
49 , pkgModules :: [Module]
44 , pkgBookmarks :: [Bookmark]
50 , pkgBookmarks :: [Bookmark]
45 , pkgResolvedDependencies :: [(PackageName, Version)]
51 , pkgResolvedDependencies :: [(PackageName, Version)]
@@ -62,6 +68,7 @@ verifyPackage verifiedUser Package{..} =
62 Package pkgMeta
68 Package pkgMeta
63 pkgVersion
69 pkgVersion
64 pkgVersionTag
70 pkgVersionTag
71+ pkgTagTime
65 pkgModules
72 pkgModules
66 pkgBookmarks
73 pkgBookmarks
67 pkgResolvedDependencies
74 pkgResolvedDependencies
@@ -72,6 +79,29 @@ verifyPackage verifiedUser Package{..} =
72packageName :: Package a -> PackageName
79packageName :: Package a -> PackageName
73packageName = bowerName . pkgMeta
80packageName = bowerName . pkgMeta
74
81
82+-- |
83+-- The time format used for serializing package tag times in the JSON format.
84+-- This is the ISO 8601 date format which includes a time and a timezone.
85+--
86+jsonTimeFormat :: String
87+jsonTimeFormat = "%Y-%m-%dT%H:%M:%S%z"
88+
89+-- |
90+-- Convenience function for formatting a time in the format expected by this
91+-- module.
92+--
93+formatTime :: UTCTime -> String
94+formatTime =
95+ TimeFormat.formatTime TimeFormat.defaultTimeLocale jsonTimeFormat
96+
97+-- |
98+-- Convenience function for parsing a time in the format expected by this
99+-- module.
100+--
101+parseTime :: String -> Maybe UTCTime
102+parseTime =
103+ TimeFormat.parseTimeM False TimeFormat.defaultTimeLocale jsonTimeFormat
104+
75data Module = Module
105data Module = Module
76 { modName :: P.ModuleName
106 { modName :: P.ModuleName
77 , modComments :: Maybe Text
107 , modComments :: Maybe Text
@@ -275,6 +305,7 @@ data PackageError
275 | InvalidFixity
305 | InvalidFixity
276 | InvalidKind Text
306 | InvalidKind Text
277 | InvalidDataDeclType Text
307 | InvalidDataDeclType Text
308+ | InvalidTime
278 deriving (Show, Eq, Ord)
309 deriving (Show, Eq, Ord)
279
310
280type Bookmark = InPackage (P.ModuleName, Text)
311type Bookmark = InPackage (P.ModuleName, Text)
@@ -320,6 +351,7 @@ asPackage minimumVersion uploader = do
320 Package <$> key "packageMeta" asPackageMeta .! ErrorInPackageMeta
351 Package <$> key "packageMeta" asPackageMeta .! ErrorInPackageMeta
321 <*> key "version" asVersion
352 <*> key "version" asVersion
322 <*> key "versionTag" asText
353 <*> key "versionTag" asText
354+ <*> keyMay "tagTime" (withString parseTimeEither)
323 <*> key "modules" (eachInArray asModule)
355 <*> key "modules" (eachInArray asModule)
324 <*> key "bookmarks" asBookmarks .! ErrorInPackageMeta
356 <*> key "bookmarks" asBookmarks .! ErrorInPackageMeta
325 <*> key "resolvedDependencies" asResolvedDependencies
357 <*> key "resolvedDependencies" asResolvedDependencies
@@ -327,6 +359,10 @@ asPackage minimumVersion uploader = do
327 <*> key "uploader" uploader
359 <*> key "uploader" uploader
328 <*> pure compilerVersion
360 <*> pure compilerVersion
329
361
362+parseTimeEither :: String -> Either PackageError UTCTime
363+parseTimeEither =
364+ maybe (Left InvalidTime) Right . parseTime
365+
330asUploadedPackage :: Version -> Parse PackageError UploadedPackage
366asUploadedPackage :: Version -> Parse PackageError UploadedPackage
331asUploadedPackage minVersion = asPackage minVersion asNotYetKnown
367asUploadedPackage minVersion = asPackage minVersion asNotYetKnown
332
368
@@ -359,6 +395,8 @@ displayPackageError e = case e of
359 "Invalid kind: \"" <> str <> "\""
395 "Invalid kind: \"" <> str <> "\""
360 InvalidDataDeclType str ->
396 InvalidDataDeclType str ->
361 "Invalid data declaration type: \"" <> str <> "\""
397 "Invalid data declaration type: \"" <> str <> "\""
398+ InvalidTime ->
399+ "Invalid time"
362
400
363instance A.FromJSON a => A.FromJSON (Package a) where
401instance A.FromJSON a => A.FromJSON (Package a) where
364 parseJSON = toAesonParser displayPackageError
402 parseJSON = toAesonParser displayPackageError
@@ -550,7 +588,7 @@ asSourceSpan = P.SourceSpan <$> key "name" asString
550
588
551instance A.ToJSON a => A.ToJSON (Package a) where
589instance A.ToJSON a => A.ToJSON (Package a) where
552 toJSON Package{..} =
590 toJSON Package{..} =
553โˆ’ A.object
591+ A.object $
554 [ "packageMeta" .= pkgMeta
592 [ "packageMeta" .= pkgMeta
555 , "version" .= showVersion pkgVersion
593 , "version" .= showVersion pkgVersion
556 , "versionTag" .= pkgVersionTag
594 , "versionTag" .= pkgVersionTag
@@ -562,7 +600,8 @@ instance A.ToJSON a => A.ToJSON (Package a) where
562 , "github" .= pkgGithub
600 , "github" .= pkgGithub
563 , "uploader" .= pkgUploader
601 , "uploader" .= pkgUploader
564 , "compilerVersion" .= showVersion P.version
602 , "compilerVersion" .= showVersion P.version
565โˆ’ ]
603+ ] ++
604+ fmap (\t -> "tagTime" .= formatTime t) (maybeToList pkgTagTime)
566
605
567instance A.ToJSON NotYetKnown where
606instance A.ToJSON NotYetKnown where
568 toJSON _ = A.Null
607 toJSON _ = A.Null
src/Language/PureScript/Errors.hs+15โˆ’10
@@ -32,10 +32,10 @@ import Language.PureScript.Names
32import Language.PureScript.Pretty
32import Language.PureScript.Pretty
33import Language.PureScript.Traversals
33import Language.PureScript.Traversals
34import Language.PureScript.Types
34import Language.PureScript.Types
35โˆ’import Language.PureScript.Pretty.Common (endWith)
35+import Language.PureScript.Label (Label(..))
36+import Language.PureScript.Pretty.Common (before, endWith)
36import qualified Language.PureScript.Bundle as Bundle
37import qualified Language.PureScript.Bundle as Bundle
37import qualified Language.PureScript.Constants as C
38import qualified Language.PureScript.Constants as C
38โˆ’import Language.PureScript.Pretty.Common (before)
39
39
40import qualified System.Console.ANSI as ANSI
40import qualified System.Console.ANSI as ANSI
41
41
@@ -172,6 +172,7 @@ errorCode em = case unwrapErrorMessage em of
172 CannotGeneralizeRecursiveFunction{} -> "CannotGeneralizeRecursiveFunction"
172 CannotGeneralizeRecursiveFunction{} -> "CannotGeneralizeRecursiveFunction"
173 CannotDeriveNewtypeForData{} -> "CannotDeriveNewtypeForData"
173 CannotDeriveNewtypeForData{} -> "CannotDeriveNewtypeForData"
174 ExpectedWildcard{} -> "ExpectedWildcard"
174 ExpectedWildcard{} -> "ExpectedWildcard"
175+ CannotUseBindWithDo{} -> "CannotUseBindWithDo"
175
176
176-- |
177-- |
177-- A stack trace for an error
178-- A stack trace for an error
@@ -264,7 +265,7 @@ onTypesInErrorMessageM f (ErrorMessage hints simple) = ErrorMessage <$> traverse
264 gSimple (ExprDoesNotHaveType e t) = ExprDoesNotHaveType e <$> f t
265 gSimple (ExprDoesNotHaveType e t) = ExprDoesNotHaveType e <$> f t
265 gSimple (InvalidInstanceHead t) = InvalidInstanceHead <$> f t
266 gSimple (InvalidInstanceHead t) = InvalidInstanceHead <$> f t
266 gSimple (NoInstanceFound con) = NoInstanceFound <$> overConstraintArgs (traverse f) con
267 gSimple (NoInstanceFound con) = NoInstanceFound <$> overConstraintArgs (traverse f) con
267โˆ’ gSimple (AmbiguousTypeVariables t con) = AmbiguousTypeVariables <$> (f t) <*> pure con
268+ gSimple (AmbiguousTypeVariables t con) = AmbiguousTypeVariables <$> f t <*> pure con
268 gSimple (OverlappingInstances cl ts insts) = OverlappingInstances cl <$> traverse f ts <*> pure insts
269 gSimple (OverlappingInstances cl ts insts) = OverlappingInstances cl <$> traverse f ts <*> pure insts
269 gSimple (PossiblyInfiniteInstance cl ts) = PossiblyInfiniteInstance cl <$> traverse f ts
270 gSimple (PossiblyInfiniteInstance cl ts) = PossiblyInfiniteInstance cl <$> traverse f ts
270 gSimple (CannotDerive cl ts) = CannotDerive cl <$> traverse f ts
271 gSimple (CannotDerive cl ts) = CannotDerive cl <$> traverse f ts
@@ -565,12 +566,12 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs) e = flip evalS
565 sortRows t1 t2 = (t1, t2)
566 sortRows t1 t2 = (t1, t2)
566
567
567 -- Put the common labels last
568 -- Put the common labels last
568โˆ’ sortRows' :: ([(Text, Type)], Type) -> ([(Text, Type)], Type) -> (Type, Type)
569+ sortRows' :: ([(Label, Type)], Type) -> ([(Label, Type)], Type) -> (Type, Type)
569 sortRows' (s1, r1) (s2, r2) =
570 sortRows' (s1, r1) (s2, r2) =
570โˆ’ let common :: [(Text, (Type, Type))]
571+ let common :: [(Label, (Type, Type))]
571 common = sortBy (comparing fst) [ (name, (t1, t2)) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
572 common = sortBy (comparing fst) [ (name, (t1, t2)) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
572
573
573โˆ’ sd1, sd2 :: [(Text, Type)]
574+ sd1, sd2 :: [(Label, Type)]
574 sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]
575 sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]
575 sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]
576 sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]
576 in ( rowFromList (sortBy (comparing fst) sd1 ++ map (fst &&& fst . snd) common, r1)
577 in ( rowFromList (sortBy (comparing fst) sd1 ++ map (fst &&& fst . snd) common, r1)
@@ -673,7 +674,7 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs) e = flip evalS
673 renderSimpleErrorMessage (CannotFindDerivingType nm) =
674 renderSimpleErrorMessage (CannotFindDerivingType nm) =
674 line $ "Cannot derive a type class instance, because the type declaration for " <> markCode (runProperName nm) <> " could not be found."
675 line $ "Cannot derive a type class instance, because the type declaration for " <> markCode (runProperName nm) <> " could not be found."
675 renderSimpleErrorMessage (DuplicateLabel l expr) =
676 renderSimpleErrorMessage (DuplicateLabel l expr) =
676โˆ’ paras $ [ line $ "Label " <> markCode l <> " appears more than once in a row type." ]
677+ paras $ [ line $ "Label " <> markCode (prettyPrintLabel l) <> " appears more than once in a row type." ]
677 <> foldMap (\expr' -> [ line "Relevant expression: "
678 <> foldMap (\expr' -> [ line "Relevant expression: "
678 , markCodeBox $ indent $ prettyPrintValue valueDepth expr'
679 , markCodeBox $ indent $ prettyPrintValue valueDepth expr'
679 ]) expr
680 ]) expr
@@ -706,9 +707,9 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs) e = flip evalS
706 , markCodeBox $ indent $ typeAsBox ty
707 , markCodeBox $ indent $ typeAsBox ty
707 ]
708 ]
708 renderSimpleErrorMessage (PropertyIsMissing prop) =
709 renderSimpleErrorMessage (PropertyIsMissing prop) =
709โˆ’ line $ "Type of expression lacks required label " <> markCode prop <> "."
710+ line $ "Type of expression lacks required label " <> markCode (prettyPrintLabel prop) <> "."
710 renderSimpleErrorMessage (AdditionalProperty prop) =
711 renderSimpleErrorMessage (AdditionalProperty prop) =
711โˆ’ line $ "Type of expression contains additional label " <> markCode prop <> "."
712+ line $ "Type of expression contains additional label " <> markCode (prettyPrintLabel prop) <> "."
712 renderSimpleErrorMessage TypeSynonymInstance =
713 renderSimpleErrorMessage TypeSynonymInstance =
713 line "Type class instances for type synonyms are disallowed."
714 line "Type class instances for type synonyms are disallowed."
714 renderSimpleErrorMessage (OrphanInstance nm cnm ts) =
715 renderSimpleErrorMessage (OrphanInstance nm cnm ts) =
@@ -880,6 +881,10 @@ prettyPrintSingleError (PPEOptions codeColor full level showDocs) e = flip evalS
880 paras [ line $ "Expected a type wildcard (_) when deriving an instance for " <> markCode (runProperName tyName) <> "."
881 paras [ line $ "Expected a type wildcard (_) when deriving an instance for " <> markCode (runProperName tyName) <> "."
881 ]
882 ]
882
883
884+ renderSimpleErrorMessage CannotUseBindWithDo =
885+ paras [ line $ "The name " <> markCode "bind" <> " cannot be brought into scope in a do notation block, since do notation uses the same name."
886+ ]
887+
883 renderHint :: ErrorMessageHint -> Box.Box -> Box.Box
888 renderHint :: ErrorMessageHint -> Box.Box -> Box.Box
884 renderHint (ErrorUnifyingTypes t1 t2) detail =
889 renderHint (ErrorUnifyingTypes t1 t2) detail =
885 paras [ detail
890 paras [ detail
@@ -1265,7 +1270,7 @@ renderBox = unlines
1265 whiteSpace = all isSpace
1270 whiteSpace = all isSpace
1266
1271
1267toTypelevelString :: Type -> Maybe Box.Box
1272toTypelevelString :: Type -> Maybe Box.Box
1268โˆ’toTypelevelString (TypeLevelString s) = Just $ Box.text (T.unpack s)
1273+toTypelevelString (TypeLevelString s) = Just $ Box.text $ T.unpack $ prettyPrintString s
1269toTypelevelString (TypeApp (TypeConstructor f) x)
1274toTypelevelString (TypeApp (TypeConstructor f) x)
1270 | f == primName "TypeString" = Just $ typeAsBox x
1275 | f == primName "TypeString" = Just $ typeAsBox x
1271toTypelevelString (TypeApp (TypeApp (TypeConstructor f) x) ret)
1276toTypelevelString (TypeApp (TypeApp (TypeConstructor f) x) ret)
src/Language/PureScript/Ide/Conversions.hsdeletedโˆ’29
@@ -1,29 +0,0 @@
1โˆ’-----------------------------------------------------------------------------
2โˆ’--
3โˆ’-- Module : Language.PureScript.Ide.Conversions
4โˆ’-- Description : Conversions to Text for PureScript types
5โˆ’-- Copyright : Christoph Hegemann 2016
6โˆ’-- License : MIT (http://opensource.org/licenses/MIT)
7โˆ’--
8โˆ’-- Maintainer : Christoph Hegemann <christoph.hegemann1337@gmail.com>
9โˆ’-- Stability : experimental
10โˆ’--
11โˆ’-- |
12โˆ’-- Conversions to Text for PureScript types
13โˆ’-----------------------------------------------------------------------------
14โˆ’
15โˆ’module Language.PureScript.Ide.Conversions where
16โˆ’
17โˆ’import Control.Lens.Iso
18โˆ’import Data.Text (lines, strip, unwords, pack)
19โˆ’import qualified Language.PureScript as P
20โˆ’import Protolude
21โˆ’
22โˆ’properNameT :: Iso' (P.ProperName a) Text
23โˆ’properNameT = iso P.runProperName P.ProperName
24โˆ’
25โˆ’identT :: Iso' P.Ident Text
26โˆ’identT = iso P.runIdent P.Ident
27โˆ’
28โˆ’prettyTypeT :: P.Type -> Text
29โˆ’prettyTypeT = unwords . map strip . lines . pack . P.prettyPrintType
src/Language/PureScript/Ide/Util.hs+18โˆ’3
@@ -24,19 +24,20 @@ module Language.PureScript.Ide.Util
24 , withEmptyAnn
24 , withEmptyAnn
25 , valueOperatorAliasT
25 , valueOperatorAliasT
26 , typeOperatorAliasT
26 , typeOperatorAliasT
27โˆ’ , module Language.PureScript.Ide.Conversions
27+ , prettyTypeT
28+ , properNameT
29+ , identT
28 , module Language.PureScript.Ide.Logging
30 , module Language.PureScript.Ide.Logging
29 ) where
31 ) where
30
32
31import Protolude hiding (decodeUtf8,
33import Protolude hiding (decodeUtf8,
32 encodeUtf8)
34 encodeUtf8)
33
35
34โˆ’import Control.Lens ((^.))
36+import Control.Lens ((^.), Iso', iso)
35import Data.Aeson
37import Data.Aeson
36import qualified Data.Text as T
38import qualified Data.Text as T
37import Data.Text.Lazy.Encoding (decodeUtf8, encodeUtf8)
39import Data.Text.Lazy.Encoding (decodeUtf8, encodeUtf8)
38import qualified Language.PureScript as P
40import qualified Language.PureScript as P
39โˆ’import Language.PureScript.Ide.Conversions
40import Language.PureScript.Ide.Logging
41import Language.PureScript.Ide.Logging
41import Language.PureScript.Ide.Types
42import Language.PureScript.Ide.Types
42
43
@@ -114,3 +115,17 @@ unwrapPositioned x = x
114unwrapPositionedRef :: P.DeclarationRef -> P.DeclarationRef
115unwrapPositionedRef :: P.DeclarationRef -> P.DeclarationRef
115unwrapPositionedRef (P.PositionedDeclarationRef _ _ x) = unwrapPositionedRef x
116unwrapPositionedRef (P.PositionedDeclarationRef _ _ x) = unwrapPositionedRef x
116unwrapPositionedRef x = x
117unwrapPositionedRef x = x
118+
119+properNameT :: Iso' (P.ProperName a) Text
120+properNameT = iso P.runProperName P.ProperName
121+
122+identT :: Iso' P.Ident Text
123+identT = iso P.runIdent P.Ident
124+
125+prettyTypeT :: P.Type -> Text
126+prettyTypeT =
127+ T.unwords
128+ . map T.strip
129+ . T.lines
130+ . T.pack
131+ . P.prettyPrintTypeWithUnicode
src/Language/PureScript/Label.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2+module Language.PureScript.Label (Label(..)) where
3+
4+import Prelude.Compat hiding (lex)
5+import Data.Monoid ()
6+import Data.String (IsString(..))
7+import qualified Data.Aeson as A
8+
9+import Language.PureScript.PSString (PSString)
10+
11+-- |
12+-- Labels are used as record keys and row entry names. Labels newtype PSString
13+-- because records are indexable by PureScript strings at runtime.
14+--
15+newtype Label = Label { runLabel :: PSString }
16+ deriving (Show, Eq, Ord, IsString, Monoid, A.ToJSON, A.FromJSON)
src/Language/PureScript/PSString.hsnew file+187
@@ -0,0 +1,187 @@
1+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+module Language.PureScript.PSString
4+ ( PSString
5+ , toUTF16CodeUnits
6+ , decodeString
7+ , decodeStringEither
8+ , prettyPrintString
9+ , prettyPrintStringJS
10+ , mkString
11+ ) where
12+
13+import Prelude.Compat
14+import Control.Exception (try, evaluate)
15+import Control.Applicative ((<|>))
16+import Data.Char (chr)
17+import Data.Bits (shiftR)
18+import Data.List (unfoldr)
19+import Data.Monoid ((<>))
20+import Data.Scientific (toBoundedInteger)
21+import Data.String (IsString(..))
22+import Data.ByteString (ByteString)
23+import qualified Data.ByteString as BS
24+import Data.Text (Text)
25+import qualified Data.Text as T
26+import Data.Text.Encoding (decodeUtf16BE)
27+import Data.Text.Encoding.Error (UnicodeException)
28+import qualified Data.Vector as V
29+import Data.Word (Word16, Word8)
30+import Numeric (showHex)
31+import System.IO.Unsafe (unsafePerformIO)
32+import qualified Data.Aeson as A
33+import qualified Data.Aeson.Types as A
34+
35+-- |
36+-- Strings in PureScript are sequences of UTF-16 code units, which do not
37+-- necessarily represent UTF-16 encoded text. For example, it is permissible
38+-- for a string to contain *lone surrogates,* i.e. characters in the range
39+-- U+D800 to U+DFFF which do not appear as a part of a surrogate pair.
40+--
41+-- The Show instance for PSString produces a string literal which would
42+-- represent the same data were it inserted into a PureScript source file.
43+--
44+-- Because JSON parsers vary wildly in terms of how they deal with lone
45+-- surrogates in JSON strings, the ToJSON instance for PSString produces JSON
46+-- strings where that would be safe (i.e. when there are no lone surrogates),
47+-- and arrays of UTF-16 code units (integers) otherwise.
48+--
49+newtype PSString = PSString { toUTF16CodeUnits :: [Word16] }
50+ deriving (Eq, Ord, Monoid)
51+
52+instance Show PSString where
53+ show = show . codePoints
54+
55+-- Decode a PSString to a String, representing any lone surrogates as the
56+-- reserved code point with that index. Warning: if there are any lone
57+-- surrogates, converting the result to Text via Data.Text.pack will result in
58+-- loss of information as those lone surrogates will be replaced with U+FFFD
59+-- REPLACEMENT CHARACTER. Because this function requires care to use correctly,
60+-- we do not export it.
61+codePoints :: PSString -> String
62+codePoints = map (either (chr . fromIntegral) id) . decodeStringEither
63+
64+-- |
65+-- Decode a PSString as UTF-16. Lone surrogates in the input are represented in
66+-- the output with the Left constructor; characters which were successfully
67+-- decoded are represented with the Right constructor.
68+--
69+decodeStringEither :: PSString -> [Either Word16 Char]
70+decodeStringEither = unfoldr decode . toUTF16CodeUnits
71+ where
72+ decode :: [Word16] -> Maybe (Either Word16 Char, [Word16])
73+ decode (h:l:rest) | isLead h && isTrail l = Just (Right (unsurrogate h l), rest)
74+ decode (c:rest) | isSurrogate c = Just (Left c, rest)
75+ decode (c:rest) = Just (Right (toChar c), rest)
76+ decode [] = Nothing
77+
78+ unsurrogate :: Word16 -> Word16 -> Char
79+ unsurrogate h l = toEnum ((toInt h - 0xD800) * 0x400 + (toInt l - 0xDC00) + 0x10000)
80+
81+-- |
82+-- Pretty print a PSString, using Haskell/PureScript escape sequences.
83+-- This is identical to the Show instance except that we get a Text out instead
84+-- of a String.
85+--
86+prettyPrintString :: PSString -> Text
87+prettyPrintString = T.pack . show
88+
89+-- |
90+-- Attempt to decode a PSString as UTF-16 text. This will fail (returning
91+-- Nothing) if the argument contains lone surrogates.
92+--
93+decodeString :: PSString -> Maybe Text
94+decodeString = hush . decodeEither . BS.pack . concatMap unpair . toUTF16CodeUnits
95+ where
96+ unpair w = [highByte w, lowByte w]
97+
98+ lowByte :: Word16 -> Word8
99+ lowByte = fromIntegral
100+
101+ highByte :: Word16 -> Word8
102+ highByte = fromIntegral . (`shiftR` 8)
103+
104+ -- Based on a similar function from Data.Text.Encoding for utf8. This is a
105+ -- safe usage of unsafePerformIO because there are no side effects after
106+ -- handling any thrown UnicodeExceptions.
107+ decodeEither :: ByteString -> Either UnicodeException Text
108+ decodeEither = unsafePerformIO . try . evaluate . decodeUtf16BE
109+
110+ hush = either (const Nothing) Just
111+
112+instance IsString PSString where
113+ fromString a = PSString $ concatMap encodeUTF16 a
114+ where
115+ surrogates :: Char -> (Word16, Word16)
116+ surrogates c = (toWord (h + 0xD800), toWord (l + 0xDC00))
117+ where (h, l) = divMod (fromEnum c - 0x10000) 0x400
118+
119+ encodeUTF16 :: Char -> [Word16]
120+ encodeUTF16 c | fromEnum c > 0xFFFF = [high, low]
121+ where (high, low) = surrogates c
122+ encodeUTF16 c = [toWord $ fromEnum c]
123+
124+instance A.ToJSON PSString where
125+ toJSON str =
126+ case decodeString str of
127+ Just t -> A.toJSON t
128+ Nothing -> A.toJSON (toUTF16CodeUnits str)
129+
130+instance A.FromJSON PSString where
131+ parseJSON a = jsonString <|> arrayOfCodeUnits
132+ where
133+ jsonString = fromString <$> A.parseJSON a
134+
135+ arrayOfCodeUnits = PSString <$> parseArrayOfCodeUnits a
136+
137+ parseArrayOfCodeUnits :: A.Value -> A.Parser [Word16]
138+ parseArrayOfCodeUnits = A.withArray "array of UTF-16 code units" (traverse parseCodeUnit . V.toList)
139+
140+ parseCodeUnit :: A.Value -> A.Parser Word16
141+ parseCodeUnit b = A.withScientific "two-byte non-negative integer" (maybe (A.typeMismatch "" b) return . toBoundedInteger) b
142+
143+-- |
144+-- Pretty print a PSString, using JavaScript escape sequences. Intended for
145+-- use in compiled JS output.
146+--
147+prettyPrintStringJS :: PSString -> Text
148+prettyPrintStringJS s = "\"" <> foldMap encodeChar (toUTF16CodeUnits s) <> "\""
149+ where
150+ encodeChar :: Word16 -> Text
151+ encodeChar c | c > 0xFF = "\\u" <> hex 4 c
152+ encodeChar c | c > 0x7E || c < 0x20 = "\\x" <> hex 2 c
153+ encodeChar c | toChar c == '\b' = "\\b"
154+ encodeChar c | toChar c == '\t' = "\\t"
155+ encodeChar c | toChar c == '\n' = "\\n"
156+ encodeChar c | toChar c == '\v' = "\\v"
157+ encodeChar c | toChar c == '\f' = "\\f"
158+ encodeChar c | toChar c == '\r' = "\\r"
159+ encodeChar c | toChar c == '"' = "\\\""
160+ encodeChar c | toChar c == '\\' = "\\\\"
161+ encodeChar c = T.singleton $ toChar c
162+
163+ hex :: (Enum a) => Int -> a -> Text
164+ hex width c =
165+ let hs = showHex (fromEnum c) "" in
166+ T.pack (replicate (width - length hs) '0' <> hs)
167+
168+isLead :: Word16 -> Bool
169+isLead h = h >= 0xD800 && h <= 0xDBFF
170+
171+isTrail :: Word16 -> Bool
172+isTrail l = l >= 0xDC00 && l <= 0xDFFF
173+
174+isSurrogate :: Word16 -> Bool
175+isSurrogate c = isLead c || isTrail c
176+
177+toChar :: Word16 -> Char
178+toChar = toEnum . fromIntegral
179+
180+toWord :: Int -> Word16
181+toWord = fromIntegral
182+
183+toInt :: Word16 -> Int
184+toInt = fromIntegral
185+
186+mkString :: Text -> PSString
187+mkString = fromString . T.unpack
src/Language/PureScript/Parser/Common.hs+7
@@ -16,6 +16,7 @@ import Language.PureScript.Comments
16import Language.PureScript.Names
16import Language.PureScript.Names
17import Language.PureScript.Parser.Lexer
17import Language.PureScript.Parser.Lexer
18import Language.PureScript.Parser.State
18import Language.PureScript.Parser.State
19+import Language.PureScript.PSString (PSString, mkString)
19
20
20import qualified Text.Parsec as P
21import qualified Text.Parsec as P
21
22
@@ -72,6 +73,12 @@ parseQualified parser = part []
72parseIdent :: TokenParser Ident
73parseIdent :: TokenParser Ident
73parseIdent = Ident <$> identifier
74parseIdent = Ident <$> identifier
74
75
76+-- |
77+-- Parse a label, which may look like an identifier or a string
78+--
79+parseLabel :: TokenParser PSString
80+parseLabel = (mkString <$> lname) <|> stringLiteral
81+
75-- |
82-- |
76-- Parse an operator.
83-- Parse an operator.
77--
84--
src/Language/PureScript/Parser/Declarations.hs+9โˆ’8
@@ -33,6 +33,7 @@ import Language.PureScript.Errors
33import Language.PureScript.Kinds
33import Language.PureScript.Kinds
34import Language.PureScript.Names
34import Language.PureScript.Names
35import Language.PureScript.Types
35import Language.PureScript.Types
36+import Language.PureScript.PSString (PSString, mkString)
36import Language.PureScript.Parser.Common
37import Language.PureScript.Parser.Common
37import Language.PureScript.Parser.Kinds
38import Language.PureScript.Parser.Kinds
38import Language.PureScript.Parser.Lexer
39import Language.PureScript.Parser.Lexer
@@ -338,15 +339,15 @@ parseBooleanLiteral = BooleanLiteral <$> booleanLiteral
338parseArrayLiteral :: TokenParser a -> TokenParser (Literal a)
339parseArrayLiteral :: TokenParser a -> TokenParser (Literal a)
339parseArrayLiteral p = ArrayLiteral <$> squares (commaSep p)
340parseArrayLiteral p = ArrayLiteral <$> squares (commaSep p)
340
341
341โˆ’parseObjectLiteral :: TokenParser (Text, a) -> TokenParser (Literal a)
342+parseObjectLiteral :: TokenParser (PSString, a) -> TokenParser (Literal a)
342parseObjectLiteral p = ObjectLiteral <$> braces (commaSep p)
343parseObjectLiteral p = ObjectLiteral <$> braces (commaSep p)
343
344
344โˆ’parseIdentifierAndValue :: TokenParser (Text, Expr)
345+parseIdentifierAndValue :: TokenParser (PSString, Expr)
345parseIdentifierAndValue =
346parseIdentifierAndValue =
346 do
347 do
347 name <- C.indented *> lname
348 name <- C.indented *> lname
348 b <- P.option (Var $ Qualified Nothing (Ident name)) rest
349 b <- P.option (Var $ Qualified Nothing (Ident name)) rest
349โˆ’ return (name, b)
350+ return (mkString name, b)
350 <|> (,) <$> (C.indented *> stringLiteral) <*> rest
351 <|> (,) <$> (C.indented *> stringLiteral) <*> rest
351 where
352 where
352 rest = C.indented *> colon *> C.indented *> parseValue
353 rest = C.indented *> colon *> C.indented *> parseValue
@@ -428,16 +429,16 @@ parseInfixExpr
428parseHole :: TokenParser Expr
429parseHole :: TokenParser Expr
429parseHole = Hole <$> holeLit
430parseHole = Hole <$> holeLit
430
431
431โˆ’parsePropertyUpdate :: TokenParser (Text, Expr)
432+parsePropertyUpdate :: TokenParser (PSString, Expr)
432parsePropertyUpdate = do
433parsePropertyUpdate = do
433โˆ’ name <- lname <|> stringLiteral
434+ name <- parseLabel
434 _ <- C.indented *> equals
435 _ <- C.indented *> equals
435 value <- C.indented *> parseValue
436 value <- C.indented *> parseValue
436 return (name, value)
437 return (name, value)
437
438
438parseAccessor :: Expr -> TokenParser Expr
439parseAccessor :: Expr -> TokenParser Expr
439parseAccessor (Constructor _) = P.unexpected "constructor"
440parseAccessor (Constructor _) = P.unexpected "constructor"
440โˆ’parseAccessor obj = P.try $ Accessor <$> (C.indented *> dot *> C.indented *> (lname <|> stringLiteral)) <*> pure obj
441+parseAccessor obj = P.try $ Accessor <$> (C.indented *> dot *> C.indented *> parseLabel) <*> pure obj
441
442
442parseDo :: TokenParser Expr
443parseDo :: TokenParser Expr
443parseDo = do
444parseDo = do
@@ -520,11 +521,11 @@ parseVarOrNamedBinder = do
520parseNullBinder :: TokenParser Binder
521parseNullBinder :: TokenParser Binder
521parseNullBinder = underscore *> return NullBinder
522parseNullBinder = underscore *> return NullBinder
522
523
523โˆ’parseIdentifierAndBinder :: TokenParser (Text, Binder)
524+parseIdentifierAndBinder :: TokenParser (PSString, Binder)
524parseIdentifierAndBinder =
525parseIdentifierAndBinder =
525 do name <- lname
526 do name <- lname
526 b <- P.option (VarBinder (Ident name)) rest
527 b <- P.option (VarBinder (Ident name)) rest
527โˆ’ return (name, b)
528+ return (mkString name, b)
528 <|> (,) <$> stringLiteral <*> rest
529 <|> (,) <$> stringLiteral <*> rest
529 where
530 where
530 rest = C.indented *> colon *> C.indented *> parseBinder
531 rest = C.indented *> colon *> C.indented *> parseBinder
src/Language/PureScript/Parser/Lexer.hs+8โˆ’18
@@ -70,11 +70,13 @@ import Control.Monad (void, guard)
70import Control.Monad.Identity (Identity)
70import Control.Monad.Identity (Identity)
71import Data.Char (isSpace, isAscii, isSymbol, isAlphaNum)
71import Data.Char (isSpace, isAscii, isSymbol, isAlphaNum)
72import Data.Monoid ((<>))
72import Data.Monoid ((<>))
73+import Data.String (fromString)
73import Data.Text (Text)
74import Data.Text (Text)
74import qualified Data.Text as T
75import qualified Data.Text as T
75
76
76import Language.PureScript.Comments
77import Language.PureScript.Comments
77import Language.PureScript.Parser.State
78import Language.PureScript.Parser.State
79+import Language.PureScript.PSString (PSString)
78
80
79import qualified Text.Parsec as P
81import qualified Text.Parsec as P
80import qualified Text.Parsec.Token as PT
82import qualified Text.Parsec.Token as PT
@@ -106,7 +108,7 @@ data Token
106 | Qualifier Text
108 | Qualifier Text
107 | Symbol Text
109 | Symbol Text
108 | CharLiteral Char
110 | CharLiteral Char
109โˆ’ | StringLiteral Text
111+ | StringLiteral PSString
110 | Number (Either Integer Double)
112 | Number (Either Integer Double)
111 | HoleLit Text
113 | HoleLit Text
112 deriving (Show, Eq, Ord)
114 deriving (Show, Eq, Ord)
@@ -248,19 +250,7 @@ parseToken = P.choice
248
250
249 symbolChar :: Lexer u Char
251 symbolChar :: Lexer u Char
250 symbolChar = P.satisfy isSymbolChar
252 symbolChar = P.satisfy isSymbolChar
251โˆ’{-
253+
252โˆ’ surrogates :: Char -> (Char, Char)
253โˆ’ surrogates c = (high, low)
254โˆ’ where
255โˆ’ (h, l) = divMod (fromEnum c - 0x10000) 0x400
256โˆ’ high = toEnum (h + 0xD800)
257โˆ’ low = toEnum (l + 0xDC00)
258โˆ’
259โˆ’ expandAstralCodePointToUTF16Surrogates :: Char -> [Char]
260โˆ’ expandAstralCodePointToUTF16Surrogates c | fromEnum c > 0xFFFF = [high, low]
261โˆ’ where (high, low) = surrogates c
262โˆ’ expandAstralCodePointToUTF16Surrogates c = [c]
263โˆ’-}
264 parseCharLiteral :: Lexer u Char
254 parseCharLiteral :: Lexer u Char
265 parseCharLiteral = P.try $ do {
255 parseCharLiteral = P.try $ do {
266 c <- PT.charLiteral tokenParser;
256 c <- PT.charLiteral tokenParser;
@@ -269,11 +259,11 @@ parseToken = P.choice
269 else return c
259 else return c
270 }
260 }
271
261
272โˆ’ parseStringLiteral :: Lexer u Text
262+ parseStringLiteral :: Lexer u PSString
273โˆ’ parseStringLiteral = blockString <|> T.pack <$> {- concatMap expandAstralCodePointToUTF16Surrogates <$> -} PT.stringLiteral tokenParser
263+ parseStringLiteral = fromString <$> (blockString <|> PT.stringLiteral tokenParser)
274 where
264 where
275 delimiter = P.try (P.string "\"\"\"")
265 delimiter = P.try (P.string "\"\"\"")
276โˆ’ blockString = delimiter *> (T.pack <$> P.manyTill P.anyChar delimiter)
266+ blockString = delimiter *> P.manyTill P.anyChar delimiter
277
267
278 parseNumber :: Lexer u (Either Integer Double)
268 parseNumber :: Lexer u (Either Integer Double)
279 parseNumber = (consumeLeadingZero *> P.parserZero) <|>
269 parseNumber = (consumeLeadingZero *> P.parserZero) <|>
@@ -516,7 +506,7 @@ charLiteral = token go P.<?> "char literal"
516 go (CharLiteral c) = Just c
506 go (CharLiteral c) = Just c
517 go _ = Nothing
507 go _ = Nothing
518
508
519โˆ’stringLiteral :: TokenParser Text
509+stringLiteral :: TokenParser PSString
520stringLiteral = token go P.<?> "string literal"
510stringLiteral = token go P.<?> "string literal"
521 where
511 where
522 go (StringLiteral s) = Just s
512 go (StringLiteral s) = Just s
src/Language/PureScript/Parser/Types.hs+3โˆ’3
@@ -9,7 +9,6 @@ import Prelude.Compat
9
9
10import Control.Monad (when, unless)
10import Control.Monad (when, unless)
11import Control.Applicative ((<|>))
11import Control.Applicative ((<|>))
12โˆ’import Data.Text (Text)
13import qualified Data.Text as T
12import qualified Data.Text as T
14
13
15import Language.PureScript.AST.SourcePos
14import Language.PureScript.AST.SourcePos
@@ -18,6 +17,7 @@ import Language.PureScript.Parser.Common
18import Language.PureScript.Parser.Kinds
17import Language.PureScript.Parser.Kinds
19import Language.PureScript.Parser.Lexer
18import Language.PureScript.Parser.Lexer
20import Language.PureScript.Types
19import Language.PureScript.Types
20+import Language.PureScript.Label (Label(..))
21
21
22import qualified Text.Parsec as P
22import qualified Text.Parsec as P
23import qualified Text.Parsec.Expr as P
23import qualified Text.Parsec.Expr as P
@@ -118,8 +118,8 @@ noWildcards p = do
118 when (containsWildcards ty) $ P.unexpected "type wildcard"
118 when (containsWildcards ty) $ P.unexpected "type wildcard"
119 return ty
119 return ty
120
120
121โˆ’parseNameAndType :: TokenParser t -> TokenParser (Text, t)
121+parseNameAndType :: TokenParser t -> TokenParser (Label, t)
122โˆ’parseNameAndType p = (,) <$> (indented *> (lname <|> stringLiteral) <* indented <* doubleColon) <*> p
122+parseNameAndType p = (,) <$> (indented *> (Label <$> parseLabel) <* indented <* doubleColon) <*> p
123
123
124parseRowEnding :: TokenParser Type
124parseRowEnding :: TokenParser Type
125parseRowEnding = P.option REmpty $ indented *> pipe *> indented *> parseType
125parseRowEnding = P.option REmpty $ indented *> pipe *> indented *> parseType
src/Language/PureScript/Pretty.hs+1
@@ -15,3 +15,4 @@ import Language.PureScript.Pretty.JS as P
15import Language.PureScript.Pretty.Kinds as P
15import Language.PureScript.Pretty.Kinds as P
16import Language.PureScript.Pretty.Types as P
16import Language.PureScript.Pretty.Types as P
17import Language.PureScript.Pretty.Values as P
17import Language.PureScript.Pretty.Values as P
18+import Language.PureScript.PSString as P (prettyPrintString)
src/Language/PureScript/Pretty/Common.hs+4โˆ’8
@@ -15,7 +15,7 @@ import Data.Text (Text)
15import qualified Data.Text as T
15import qualified Data.Text as T
16
16
17import Language.PureScript.AST (SourcePos(..), SourceSpan(..))
17import Language.PureScript.AST (SourcePos(..), SourceSpan(..))
18โˆ’import Language.PureScript.Parser.Lexer (reservedPsNames, isUnquotedKey)
18+import Language.PureScript.Parser.Lexer (isUnquotedKey, reservedPsNames)
19
19
20import Text.PrettyPrint.Boxes hiding ((<>))
20import Text.PrettyPrint.Boxes hiding ((<>))
21import qualified Text.PrettyPrint.Boxes as Box
21import qualified Text.PrettyPrint.Boxes as Box
@@ -146,13 +146,9 @@ prettyPrintMany f xs = do
146 indentString <- currentIndent
146 indentString <- currentIndent
147 return $ intercalate (emit "\n") $ map (mappend indentString) ss
147 return $ intercalate (emit "\n") $ map (mappend indentString) ss
148
148
149โˆ’-- |
149+objectKeyRequiresQuoting :: Text -> Bool
150โˆ’-- Prints an object key, escaping reserved names.
150+objectKeyRequiresQuoting s =
151โˆ’--
152โˆ’prettyPrintObjectKey :: Text -> Text
153โˆ’prettyPrintObjectKey s | s `elem` reservedPsNames = T.pack (show s)
154โˆ’ | isUnquotedKey s = s
151+ s `elem` reservedPsNames || not (isUnquotedKey s)
155โˆ’ | otherwise = T.pack (show s)
156
152
157-- | Place a box before another, vertically when the first box takes up multiple lines.
153-- | Place a box before another, vertically when the first box takes up multiple lines.
158before :: Box -> Box -> Box
154before :: Box -> Box -> Box
src/Language/PureScript/Pretty/JS.hs+10โˆ’30
@@ -25,8 +25,7 @@ import Language.PureScript.CodeGen.JS.Common
25import Language.PureScript.Comments
25import Language.PureScript.Comments
26import Language.PureScript.Crash
26import Language.PureScript.Crash
27import Language.PureScript.Pretty.Common
27import Language.PureScript.Pretty.Common
28โˆ’
28+import Language.PureScript.PSString (PSString, decodeString, prettyPrintStringJS)
29โˆ’import Numeric
30
29
31-- TODO (Christoph): Get rid of T.unpack / pack
30-- TODO (Christoph): Get rid of T.unpack / pack
32
31
@@ -38,7 +37,7 @@ literals = mkPattern' match'
38
37
39 match :: (Emit gen) => JS -> StateT PrinterState Maybe gen
38 match :: (Emit gen) => JS -> StateT PrinterState Maybe gen
40 match (JSNumericLiteral _ n) = return $ emit $ T.pack $ either show show n
39 match (JSNumericLiteral _ n) = return $ emit $ T.pack $ either show show n
41โˆ’ match (JSStringLiteral _ s) = return $ string s
40+ match (JSStringLiteral _ s) = return $ emit $ prettyPrintStringJS s
42 match (JSBooleanLiteral _ True) = return $ emit "true"
41 match (JSBooleanLiteral _ True) = return $ emit "true"
43 match (JSBooleanLiteral _ False) = return $ emit "false"
42 match (JSBooleanLiteral _ False) = return $ emit "false"
44 match (JSArrayLiteral _ xs) = mconcat <$> sequence
43 match (JSArrayLiteral _ xs) = mconcat <$> sequence
@@ -58,9 +57,13 @@ literals = mkPattern' match'
58 , return $ emit "}"
57 , return $ emit "}"
59 ]
58 ]
60 where
59 where
61โˆ’ objectPropertyToString :: (Emit gen) => Text -> gen
60+ objectPropertyToString :: (Emit gen) => PSString -> gen
62โˆ’ objectPropertyToString s | identNeedsEscaping s = string s
61+ objectPropertyToString s =
63โˆ’ | otherwise = emit s
62+ emit $ case decodeString s of
63+ Just s' | not (identNeedsEscaping s') ->
64+ s'
65+ _ ->
66+ prettyPrintStringJS s
64 match (JSBlock _ sts) = mconcat <$> sequence
67 match (JSBlock _ sts) = mconcat <$> sequence
65 [ return $ emit "{\n"
68 [ return $ emit "{\n"
66 , withIndent $ prettyStatements sts
69 , withIndent $ prettyStatements sts
@@ -150,29 +153,6 @@ literals = mkPattern' match'
150 match (JSRaw _ js) = return $ emit js
153 match (JSRaw _ js) = return $ emit js
151 match _ = mzero
154 match _ = mzero
152
155
153โˆ’string :: (Emit gen) => Text -> gen
154โˆ’string s = emit $ "\"" <> T.concatMap encodeChar s <> "\""
155โˆ’ where
156โˆ’ encodeChar :: Char -> Text
157โˆ’ encodeChar '\b' = "\\b"
158โˆ’ encodeChar '\t' = "\\t"
159โˆ’ encodeChar '\n' = "\\n"
160โˆ’ encodeChar '\v' = "\\v"
161โˆ’ encodeChar '\f' = "\\f"
162โˆ’ encodeChar '\r' = "\\r"
163โˆ’ encodeChar '"' = "\\\""
164โˆ’ encodeChar '\\' = "\\\\"
165โˆ’ -- PureScript strings are sequences of UTF-16 code units, so this case should never be hit.
166โˆ’ -- If it is somehow hit, though, output the designated Unicode replacement character U+FFFD.
167โˆ’ encodeChar c | fromEnum c > 0xFFFF = "\\uFFFD"
168โˆ’ encodeChar c | fromEnum c > 0xFFF = "\\u" <> showHex' (fromEnum c) ""
169โˆ’ encodeChar c | fromEnum c > 0xFF = "\\u0" <> showHex' (fromEnum c) ""
170โˆ’ encodeChar c | fromEnum c < 0x10 = "\\x0" <> showHex' (fromEnum c) ""
171โˆ’ encodeChar c | fromEnum c > 0x7E || fromEnum c < 0x20 = "\\x" <> showHex' (fromEnum c) ""
172โˆ’ encodeChar c = T.singleton c
173โˆ’
174โˆ’ showHex' a b = T.pack (showHex a b)
175โˆ’
176conditional :: Pattern PrinterState JS ((Maybe SourceSpan, JS, JS), JS)
156conditional :: Pattern PrinterState JS ((Maybe SourceSpan, JS, JS), JS)
177conditional = mkPattern match
157conditional = mkPattern match
178 where
158 where
@@ -182,6 +162,7 @@ conditional = mkPattern match
182accessor :: (Emit gen) => Pattern PrinterState JS (gen, JS)
162accessor :: (Emit gen) => Pattern PrinterState JS (gen, JS)
183accessor = mkPattern match
163accessor = mkPattern match
184 where
164 where
165+ -- WARN: if `prop` does not match the `IdentifierName` grammar, this will generate invalid code; see #2513
185 match (JSAccessor _ prop val) = Just (emit prop, val)
166 match (JSAccessor _ prop val) = Just (emit prop, val)
186 match _ = Nothing
167 match _ = Nothing
187
168
@@ -189,7 +170,6 @@ indexer :: (Emit gen) => Pattern PrinterState JS (gen, JS)
189indexer = mkPattern' match
170indexer = mkPattern' match
190 where
171 where
191 match (JSIndexer _ index val) = (,) <$> prettyPrintJS' index <*> pure val
172 match (JSIndexer _ index val) = (,) <$> prettyPrintJS' index <*> pure val
192โˆ’
193 match _ = mzero
173 match _ = mzero
194
174
195lam :: Pattern PrinterState JS ((Maybe Text, [Text], Maybe SourceSpan), JS)
175lam :: Pattern PrinterState JS ((Maybe Text, [Text], Maybe SourceSpan), JS)
src/Language/PureScript/Pretty/Kinds.hs+14โˆ’11
@@ -10,6 +10,7 @@ import Prelude.Compat
10import Control.Arrow (ArrowPlus(..))
10import Control.Arrow (ArrowPlus(..))
11import Control.PatternArrows as PA
11import Control.PatternArrows as PA
12
12
13+import Data.Monoid ((<>))
13import Data.Maybe (fromMaybe)
14import Data.Maybe (fromMaybe)
14import qualified Data.Text as T
15import qualified Data.Text as T
15import Data.Text (Text)
16import Data.Text (Text)
@@ -19,11 +20,15 @@ import Language.PureScript.Kinds
19import Language.PureScript.Names
20import Language.PureScript.Names
20import Language.PureScript.Pretty.Common
21import Language.PureScript.Pretty.Common
21
22
22โˆ’typeLiterals :: Pattern () Kind String
23+typeLiterals :: Pattern () Kind Text
23typeLiterals = mkPattern match
24typeLiterals = mkPattern match
24 where
25 where
25โˆ’ match (KUnknown u) = Just $ 'u' : show u
26+ match (KUnknown u) =
27+ Just $ T.cons 'k' (T.pack (show u))
28+ match (NamedKind name) =
29+ Just $ if isQualifiedWith (moduleNameFromString "Prim") name
30+ then runProperName (disqualify name)
26โˆ’ match (NamedKind name) = Just $ T.unpack (showQualified runProperName name)
31+ else showQualified runProperName name
27 match _ = Nothing
32 match _ = Nothing
28
33
29matchRow :: Pattern () Kind ((), Kind)
34matchRow :: Pattern () Kind ((), Kind)
@@ -41,15 +46,13 @@ funKind = mkPattern match
41-- | Generate a pretty-printed string representing a Kind
46-- | Generate a pretty-printed string representing a Kind
42prettyPrintKind :: Kind -> Text
47prettyPrintKind :: Kind -> Text
43prettyPrintKind
48prettyPrintKind
44โˆ’ -- TODO(Christoph): get rid of T.pack
45โˆ’ = T.pack
46โˆ’ . fromMaybe (internalError "Incomplete pattern")
49+ = fromMaybe (internalError "Incomplete pattern")
47 . PA.pattern matchKind ()
50 . PA.pattern matchKind ()
48 where
51 where
49โˆ’ matchKind :: Pattern () Kind String
52+ matchKind :: Pattern () Kind Text
50โˆ’ matchKind = buildPrettyPrinter operators (typeLiterals <+> fmap parens matchKind)
53+ matchKind = buildPrettyPrinter operators (typeLiterals <+> fmap parensT matchKind)
51
54
52โˆ’ operators :: OperatorTable () Kind String
55+ operators :: OperatorTable () Kind Text
53 operators =
56 operators =
54โˆ’ OperatorTable [ [ Wrap matchRow $ \_ k -> "# " ++ k]
57+ OperatorTable [ [ Wrap matchRow $ \_ k -> "# " <> k]
55โˆ’ , [ AssocR funKind $ \arg ret -> arg ++ " -> " ++ ret ] ]
58+ , [ AssocR funKind $ \arg ret -> arg <> " -> " <> ret ] ]
src/Language/PureScript/Pretty/Types.hs+79โˆ’33
@@ -5,11 +5,13 @@ module Language.PureScript.Pretty.Types
5 ( typeAsBox
5 ( typeAsBox
6 , suggestedTypeAsBox
6 , suggestedTypeAsBox
7 , prettyPrintType
7 , prettyPrintType
8+ , prettyPrintTypeWithUnicode
8 , prettyPrintSuggestedType
9 , prettyPrintSuggestedType
9 , typeAtomAsBox
10 , typeAtomAsBox
10 , prettyPrintTypeAtom
11 , prettyPrintTypeAtom
11โˆ’ , prettyPrintRowWith
12 , prettyPrintRow
12 , prettyPrintRow
13+ , prettyPrintLabel
14+ , prettyPrintObjectKey
13 ) where
15 ) where
14
16
15import Prelude.Compat
17import Prelude.Compat
@@ -18,6 +20,7 @@ import Control.Arrow ((<+>))
18import Control.PatternArrows as PA
20import Control.PatternArrows as PA
19
21
20import Data.Maybe (fromMaybe)
22import Data.Maybe (fromMaybe)
23+import Data.Text (Text)
21import qualified Data.Text as T
24import qualified Data.Text as T
22
25
23import Language.PureScript.Crash
26import Language.PureScript.Crash
@@ -27,14 +30,19 @@ import Language.PureScript.Names
27import Language.PureScript.Pretty.Common
30import Language.PureScript.Pretty.Common
28import Language.PureScript.Pretty.Kinds
31import Language.PureScript.Pretty.Kinds
29import Language.PureScript.Types
32import Language.PureScript.Types
33+import Language.PureScript.PSString (PSString, prettyPrintString, decodeString)
34+import Language.PureScript.Label (Label(..))
30
35
31import Text.PrettyPrint.Boxes hiding ((<+>))
36import Text.PrettyPrint.Boxes hiding ((<+>))
32
37
33-- TODO(Christoph): get rid of T.unpack s
38-- TODO(Christoph): get rid of T.unpack s
34
39
35โˆ’constraintsAsBox :: [Constraint] -> Box -> Box
40+constraintsAsBox :: TypeRenderOptions -> [Constraint] -> Box -> Box
41+constraintsAsBox tro constraints ty = case constraints of
36โˆ’constraintsAsBox [con] ty = text "(" <> constraintAsBox con `before` (text ") => " <> ty)
42+ [con] -> text "(" <> constraintAsBox con `before` (") " <> text doubleRightArrow <> " " <> ty)
37โˆ’constraintsAsBox xs ty = vcat left (zipWith (\i con -> text (if i == 0 then "( " else ", ") <> constraintAsBox con) [0 :: Int ..] xs) `before` (text ") => " <> ty)
43+ xs -> vcat left (zipWith (\i con -> text (if i == 0 then "( " else ", ") <> constraintAsBox con) [0 :: Int ..] xs) `before` (") " <> text doubleRightArrow <> " " <> ty)
44+ where
45+ doubleRightArrow = if troUnicode tro then "โ‡’" else "=>"
38
46
39constraintAsBox :: Constraint -> Box
47constraintAsBox :: Constraint -> Box
40constraintAsBox (Constraint pn tys _) = typeAsBox (foldl TypeApp (TypeConstructor (fmap coerceProperName pn)) tys)
48constraintAsBox (Constraint pn tys _) = typeAsBox (foldl TypeApp (TypeConstructor (fmap coerceProperName pn)) tys)
@@ -42,29 +50,30 @@ constraintAsBox (Constraint pn tys _) = typeAsBox (foldl TypeApp (TypeConstructo
42-- |
50-- |
43-- Generate a pretty-printed string representing a Row
51-- Generate a pretty-printed string representing a Row
44--
52--
45โˆ’prettyPrintRowWith :: Char -> Char -> Type -> Box
53+prettyPrintRowWith :: TypeRenderOptions -> Char -> Char -> Type -> Box
46โˆ’prettyPrintRowWith open close = uncurry listToBox . toList []
54+prettyPrintRowWith tro open close = uncurry listToBox . toList []
47 where
55 where
48โˆ’ nameAndTypeToPs :: Char -> String -> Type -> Box
56+ nameAndTypeToPs :: Char -> Label -> Type -> Box
49โˆ’ nameAndTypeToPs start name ty = text (start : ' ' : T.unpack (prettyPrintObjectKey (T.pack name)) ++ " :: ") <> typeAsBox ty
57+ nameAndTypeToPs start name ty = text (start : ' ' : T.unpack (prettyPrintLabel name) ++ " " ++ doubleColon ++ " ") <> typeAsBox ty
58+
59+ doubleColon = if troUnicode tro then "โˆท" else "::"
50
60
51 tailToPs :: Type -> Box
61 tailToPs :: Type -> Box
52 tailToPs REmpty = nullBox
62 tailToPs REmpty = nullBox
53 tailToPs other = text "| " <> typeAsBox other
63 tailToPs other = text "| " <> typeAsBox other
54
64
55โˆ’ listToBox :: [(String, Type)] -> Type -> Box
65+ listToBox :: [(Label, Type)] -> Type -> Box
56 listToBox [] REmpty = text [open, close]
66 listToBox [] REmpty = text [open, close]
57 listToBox [] rest = text [ open, ' ' ] <> tailToPs rest <> text [ ' ', close ]
67 listToBox [] rest = text [ open, ' ' ] <> tailToPs rest <> text [ ' ', close ]
58 listToBox ts rest = vcat left $
68 listToBox ts rest = vcat left $
59 zipWith (\(nm, ty) i -> nameAndTypeToPs (if i == 0 then open else ',') nm ty) ts [0 :: Int ..] ++
69 zipWith (\(nm, ty) i -> nameAndTypeToPs (if i == 0 then open else ',') nm ty) ts [0 :: Int ..] ++
60 [ tailToPs rest, text [close] ]
70 [ tailToPs rest, text [close] ]
61โˆ’
62โˆ’ toList :: [(String, Type)] -> Type -> ([(String, Type)], Type)
71+ toList :: [(Label, Type)] -> Type -> ([(Label, Type)], Type)
63โˆ’ toList tys (RCons name ty row) = toList ((T.unpack name, ty):tys) row
72+ toList tys (RCons name ty row) = toList ((name, ty):tys) row
64 toList tys r = (reverse tys, r)
73 toList tys r = (reverse tys, r)
65
74
66prettyPrintRow :: Type -> String
75prettyPrintRow :: Type -> String
67โˆ’prettyPrintRow = render . prettyPrintRowWith '(' ')'
76+prettyPrintRow = render . prettyPrintRowWith defaultOptions '(' ')'
68
77
69typeApp :: Pattern () Type (Type, Type)
78typeApp :: Pattern () Type (Type, Type)
70typeApp = mkPattern match
79typeApp = mkPattern match
@@ -108,16 +117,16 @@ explicitParens = mkPattern match
108 match (ParensInType ty) = Just ((), ty)
117 match (ParensInType ty) = Just ((), ty)
109 match _ = Nothing
118 match _ = Nothing
110
119
111โˆ’matchTypeAtom :: Bool -> Pattern () Type Box
120+matchTypeAtom :: TypeRenderOptions -> Pattern () Type Box
112โˆ’matchTypeAtom suggesting =
121+matchTypeAtom tro@TypeRenderOptions{troSuggesting = suggesting} =
113โˆ’ typeLiterals <+> fmap ((`before` (text ")")) . (text "(" <>)) (matchType suggesting)
122+ typeLiterals <+> fmap ((`before` (text ")")) . (text "(" <>)) (matchType tro)
114 where
123 where
115 typeLiterals :: Pattern () Type Box
124 typeLiterals :: Pattern () Type Box
116 typeLiterals = mkPattern match where
125 typeLiterals = mkPattern match where
117 match TypeWildcard{} = Just $ text "_"
126 match TypeWildcard{} = Just $ text "_"
118 match (TypeVar var) = Just $ text $ T.unpack var
127 match (TypeVar var) = Just $ text $ T.unpack var
119โˆ’ match (TypeLevelString s) = Just . text $ show s
128+ match (TypeLevelString s) = Just $ text $ T.unpack $ prettyPrintString s
120โˆ’ match (PrettyPrintObject row) = Just $ prettyPrintRowWith '{' '}' row
129+ match (PrettyPrintObject row) = Just $ prettyPrintRowWith tro '{' '}' row
121 match (TypeConstructor ctor) = Just $ text $ T.unpack $ runProperName $ disqualify ctor
130 match (TypeConstructor ctor) = Just $ text $ T.unpack $ runProperName $ disqualify ctor
122 match (TUnknown u)
131 match (TUnknown u)
123 | suggesting = Just $ text "_"
132 | suggesting = Just $ text "_"
@@ -126,24 +135,28 @@ matchTypeAtom suggesting =
126 | suggesting = Just $ text $ T.unpack name
135 | suggesting = Just $ text $ T.unpack name
127 | otherwise = Just $ text $ T.unpack name ++ show s
136 | otherwise = Just $ text $ T.unpack name ++ show s
128 match REmpty = Just $ text "()"
137 match REmpty = Just $ text "()"
129โˆ’ match row@RCons{} = Just $ prettyPrintRowWith '(' ')' row
138+ match row@RCons{} = Just $ prettyPrintRowWith tro '(' ')' row
130 match (BinaryNoParensType op l r) =
139 match (BinaryNoParensType op l r) =
131 Just $ typeAsBox l <> text " " <> typeAsBox op <> text " " <> typeAsBox r
140 Just $ typeAsBox l <> text " " <> typeAsBox op <> text " " <> typeAsBox r
132 match (TypeOp op) = Just $ text $ T.unpack $ showQualified runOpName op
141 match (TypeOp op) = Just $ text $ T.unpack $ showQualified runOpName op
133 match _ = Nothing
142 match _ = Nothing
134
143
135โˆ’matchType :: Bool -> Pattern () Type Box
144+matchType :: TypeRenderOptions -> Pattern () Type Box
136โˆ’matchType = buildPrettyPrinter operators . matchTypeAtom where
145+matchType tro = buildPrettyPrinter operators (matchTypeAtom tro) where
137 operators :: OperatorTable () Type Box
146 operators :: OperatorTable () Type Box
138 operators =
147 operators =
139 OperatorTable [ [ AssocL typeApp $ \f x -> keepSingleLinesOr (moveRight 2) f x ]
148 OperatorTable [ [ AssocL typeApp $ \f x -> keepSingleLinesOr (moveRight 2) f x ]
140โˆ’ , [ AssocR appliedFunction $ \arg ret -> keepSingleLinesOr id arg (text "-> " <> ret) ]
149+ , [ AssocR appliedFunction $ \arg ret -> keepSingleLinesOr id arg (text rightArrow <> " " <> ret) ]
141โˆ’ , [ Wrap constrained $ \deps ty -> constraintsAsBox deps ty ]
150+ , [ Wrap constrained $ \deps ty -> constraintsAsBox tro deps ty ]
142โˆ’ , [ Wrap forall_ $ \idents ty -> keepSingleLinesOr (moveRight 2) (text ("forall " ++ unwords idents ++ ".")) ty ]
151+ , [ Wrap forall_ $ \idents ty -> keepSingleLinesOr (moveRight 2) (text (forall' ++ " " ++ unwords idents ++ ".")) ty ]
143โˆ’ , [ Wrap kinded $ \k ty -> keepSingleLinesOr (moveRight 2) ty (text (":: " ++ T.unpack (prettyPrintKind k))) ]
152+ , [ Wrap kinded $ \k ty -> keepSingleLinesOr (moveRight 2) ty (text (doubleColon ++ " " ++ T.unpack (prettyPrintKind k))) ]
144 , [ Wrap explicitParens $ \_ ty -> ty ]
153 , [ Wrap explicitParens $ \_ ty -> ty ]
145 ]
154 ]
146
155
156+ rightArrow = if troUnicode tro then "โ†’" else "->"
157+ forall' = if troUnicode tro then "โˆ€" else "forall"
158+ doubleColon = if troUnicode tro then "โˆท" else "::"
159+
147 -- If both boxes span a single line, keep them on the same line, or else
160 -- If both boxes span a single line, keep them on the same line, or else
148 -- use the specified function to modify the second box, then combine vertically.
161 -- use the specified function to modify the second box, then combine vertically.
149 keepSingleLinesOr :: (Box -> Box) -> Box -> Box -> Box
162 keepSingleLinesOr :: (Box -> Box) -> Box -> Box -> Box
@@ -160,7 +173,7 @@ forall_ = mkPattern match
160typeAtomAsBox :: Type -> Box
173typeAtomAsBox :: Type -> Box
161typeAtomAsBox
174typeAtomAsBox
162 = fromMaybe (internalError "Incomplete pattern")
175 = fromMaybe (internalError "Incomplete pattern")
163โˆ’ . PA.pattern (matchTypeAtom False) ()
176+ . PA.pattern (matchTypeAtom defaultOptions) ()
164 . insertPlaceholders
177 . insertPlaceholders
165
178
166-- | Generate a pretty-printed string representing a Type, as it should appear inside parentheses
179-- | Generate a pretty-printed string representing a Type, as it should appear inside parentheses
@@ -168,21 +181,54 @@ prettyPrintTypeAtom :: Type -> String
168prettyPrintTypeAtom = render . typeAtomAsBox
181prettyPrintTypeAtom = render . typeAtomAsBox
169
182
170typeAsBox :: Type -> Box
183typeAsBox :: Type -> Box
171โˆ’typeAsBox = typeAsBoxImpl False
184+typeAsBox = typeAsBoxImpl defaultOptions
172
185
173suggestedTypeAsBox :: Type -> Box
186suggestedTypeAsBox :: Type -> Box
174โˆ’suggestedTypeAsBox = typeAsBoxImpl True
187+suggestedTypeAsBox = typeAsBoxImpl suggestingOptions
188+
189+data TypeRenderOptions = TypeRenderOptions
190+ { troSuggesting :: Bool
191+ , troUnicode :: Bool
192+ }
193+
194+suggestingOptions :: TypeRenderOptions
195+suggestingOptions = TypeRenderOptions True False
175
196
197+defaultOptions :: TypeRenderOptions
198+defaultOptions = TypeRenderOptions False False
199+
200+unicodeOptions :: TypeRenderOptions
201+unicodeOptions = TypeRenderOptions False True
202+
176โˆ’typeAsBoxImpl :: Bool -> Type -> Box
203+typeAsBoxImpl :: TypeRenderOptions -> Type -> Box
177โˆ’typeAsBoxImpl suggesting
204+typeAsBoxImpl tro
178 = fromMaybe (internalError "Incomplete pattern")
205 = fromMaybe (internalError "Incomplete pattern")
179โˆ’ . PA.pattern (matchType suggesting) ()
206+ . PA.pattern (matchType tro) ()
180 . insertPlaceholders
207 . insertPlaceholders
181
208
182-- | Generate a pretty-printed string representing a 'Type'
209-- | Generate a pretty-printed string representing a 'Type'
183prettyPrintType :: Type -> String
210prettyPrintType :: Type -> String
184โˆ’prettyPrintType = render . typeAsBoxImpl False
211+prettyPrintType = prettyPrintType' defaultOptions
212+
213+-- | Generate a pretty-printed string representing a 'Type' using unicode
214+-- symbols where applicable
215+prettyPrintTypeWithUnicode :: Type -> String
216+prettyPrintTypeWithUnicode = prettyPrintType' unicodeOptions
185
217
186-- | Generate a pretty-printed string representing a suggested 'Type'
218-- | Generate a pretty-printed string representing a suggested 'Type'
187prettyPrintSuggestedType :: Type -> String
219prettyPrintSuggestedType :: Type -> String
188โˆ’prettyPrintSuggestedType = render . typeAsBoxImpl True
220+prettyPrintSuggestedType = prettyPrintType' suggestingOptions
221+
222+prettyPrintType' :: TypeRenderOptions -> Type -> String
223+prettyPrintType' tro = render . typeAsBoxImpl tro
224+
225+prettyPrintLabel :: Label -> Text
226+prettyPrintLabel (Label s) =
227+ case decodeString s of
228+ Just s' | not (objectKeyRequiresQuoting s') ->
229+ s'
230+ _ ->
231+ prettyPrintString s
232+
233+prettyPrintObjectKey :: PSString -> Text
234+prettyPrintObjectKey = prettyPrintLabel . Label
src/Language/PureScript/Pretty/Values.hs+8โˆ’7
@@ -20,8 +20,9 @@ import Language.PureScript.AST
20import Language.PureScript.Crash
20import Language.PureScript.Crash
21import Language.PureScript.Names
21import Language.PureScript.Names
22import Language.PureScript.Pretty.Common
22import Language.PureScript.Pretty.Common
23โˆ’import Language.PureScript.Pretty.Types (typeAsBox, typeAtomAsBox)
23+import Language.PureScript.Pretty.Types (typeAsBox, typeAtomAsBox, prettyPrintObjectKey)
24import Language.PureScript.Types (Constraint(..))
24import Language.PureScript.Types (Constraint(..))
25+import Language.PureScript.PSString (PSString, prettyPrintString)
25
26
26import Text.PrettyPrint.Boxes
27import Text.PrettyPrint.Boxes
27
28
@@ -40,10 +41,10 @@ list open close f xs = vcat left (zipWith toLine [0 :: Int ..] xs ++ [ text [ cl
40ellipsis :: Box
41ellipsis :: Box
41ellipsis = text "..."
42ellipsis = text "..."
42
43
43โˆ’prettyPrintObject :: Int -> [(Text, Maybe Expr)] -> Box
44+prettyPrintObject :: Int -> [(PSString, Maybe Expr)] -> Box
44prettyPrintObject d = list '{' '}' prettyPrintObjectProperty
45prettyPrintObject d = list '{' '}' prettyPrintObjectProperty
45 where
46 where
46โˆ’ prettyPrintObjectProperty :: (Text, Maybe Expr) -> Box
47+ prettyPrintObjectProperty :: (PSString, Maybe Expr) -> Box
47 prettyPrintObjectProperty (key, value) = textT (prettyPrintObjectKey key Monoid.<> ": ") <> maybe (text "_") (prettyPrintValue (d - 1)) value
48 prettyPrintObjectProperty (key, value) = textT (prettyPrintObjectKey key Monoid.<> ": ") <> maybe (text "_") (prettyPrintValue (d - 1)) value
48
49
49-- | Pretty-print an expression
50-- | Pretty-print an expression
@@ -55,7 +56,7 @@ prettyPrintValue d (IfThenElse cond th el) =
55 , text "else " <> prettyPrintValueAtom (d - 1) el
56 , text "else " <> prettyPrintValueAtom (d - 1) el
56 ])
57 ])
57prettyPrintValue d (Accessor prop val) = prettyPrintValueAtom (d - 1) val `before` textT ("." Monoid.<> prettyPrintObjectKey prop)
58prettyPrintValue d (Accessor prop val) = prettyPrintValueAtom (d - 1) val `before` textT ("." Monoid.<> prettyPrintObjectKey prop)
58โˆ’prettyPrintValue d (ObjectUpdate o ps) = prettyPrintValueAtom (d - 1) o `beforeWithSpace` list '{' '}' (\(key, val) -> textT (key Monoid.<> " = ") <> prettyPrintValue (d - 1) val) ps
59+prettyPrintValue d (ObjectUpdate o ps) = prettyPrintValueAtom (d - 1) o `beforeWithSpace` list '{' '}' (\(key, val) -> textT (prettyPrintObjectKey key Monoid.<> " = ") <> prettyPrintValue (d - 1) val) ps
59prettyPrintValue d (App val arg) = prettyPrintValueAtom (d - 1) val `beforeWithSpace` prettyPrintValueAtom (d - 1) arg
60prettyPrintValue d (App val arg) = prettyPrintValueAtom (d - 1) val `beforeWithSpace` prettyPrintValueAtom (d - 1) arg
60prettyPrintValue d (Abs (Left arg) val) = text ('\\' : T.unpack (showIdent arg) ++ " -> ") // moveRight 2 (prettyPrintValue (d - 1) val)
61prettyPrintValue d (Abs (Left arg) val) = text ('\\' : T.unpack (showIdent arg) ++ " -> ") // moveRight 2 (prettyPrintValue (d - 1) val)
61prettyPrintValue d (Abs (Right arg) val) = text ('\\' : T.unpack (prettyPrintBinder arg) ++ " -> ") // moveRight 2 (prettyPrintValue (d - 1) val)
62prettyPrintValue d (Abs (Right arg) val) = text ('\\' : T.unpack (prettyPrintBinder arg) ++ " -> ") // moveRight 2 (prettyPrintValue (d - 1) val)
@@ -105,7 +106,7 @@ prettyPrintValueAtom d expr = (text "(" <> prettyPrintValue d expr) `before` tex
105
106
106prettyPrintLiteralValue :: Int -> Literal Expr -> Box
107prettyPrintLiteralValue :: Int -> Literal Expr -> Box
107prettyPrintLiteralValue _ (NumericLiteral n) = text $ either show show n
108prettyPrintLiteralValue _ (NumericLiteral n) = text $ either show show n
108โˆ’prettyPrintLiteralValue _ (StringLiteral s) = text $ show s
109+prettyPrintLiteralValue _ (StringLiteral s) = text $ T.unpack $ prettyPrintString s
109prettyPrintLiteralValue _ (CharLiteral c) = text $ show c
110prettyPrintLiteralValue _ (CharLiteral c) = text $ show c
110prettyPrintLiteralValue _ (BooleanLiteral True) = text "true"
111prettyPrintLiteralValue _ (BooleanLiteral True) = text "true"
111prettyPrintLiteralValue _ (BooleanLiteral False) = text "false"
112prettyPrintLiteralValue _ (BooleanLiteral False) = text "false"
@@ -169,7 +170,7 @@ prettyPrintBinderAtom (BinaryNoParensBinder op b1 b2) =
169prettyPrintBinderAtom (ParensInBinder b) = parensT (prettyPrintBinder b)
170prettyPrintBinderAtom (ParensInBinder b) = parensT (prettyPrintBinder b)
170
171
171prettyPrintLiteralBinder :: Literal Binder -> Text
172prettyPrintLiteralBinder :: Literal Binder -> Text
172โˆ’prettyPrintLiteralBinder (StringLiteral str) = T.pack (show str)
173+prettyPrintLiteralBinder (StringLiteral str) = prettyPrintString str
173prettyPrintLiteralBinder (CharLiteral c) = T.pack (show c)
174prettyPrintLiteralBinder (CharLiteral c) = T.pack (show c)
174prettyPrintLiteralBinder (NumericLiteral num) = either (T.pack . show) (T.pack . show) num
175prettyPrintLiteralBinder (NumericLiteral num) = either (T.pack . show) (T.pack . show) num
175prettyPrintLiteralBinder (BooleanLiteral True) = "true"
176prettyPrintLiteralBinder (BooleanLiteral True) = "true"
@@ -179,7 +180,7 @@ prettyPrintLiteralBinder (ObjectLiteral bs) =
179 Monoid.<> T.intercalate ", " (map prettyPrintObjectPropertyBinder bs)
180 Monoid.<> T.intercalate ", " (map prettyPrintObjectPropertyBinder bs)
180 Monoid.<> " }"
181 Monoid.<> " }"
181 where
182 where
182โˆ’ prettyPrintObjectPropertyBinder :: (Text, Binder) -> Text
183+ prettyPrintObjectPropertyBinder :: (PSString, Binder) -> Text
183 prettyPrintObjectPropertyBinder (key, binder) = prettyPrintObjectKey key Monoid.<> ": " Monoid.<> prettyPrintBinder binder
184 prettyPrintObjectPropertyBinder (key, binder) = prettyPrintObjectKey key Monoid.<> ": " Monoid.<> prettyPrintBinder binder
184prettyPrintLiteralBinder (ArrayLiteral bs) =
185prettyPrintLiteralBinder (ArrayLiteral bs) =
185 "[ "
186 "[ "
src/Language/PureScript/Publish.hs+13โˆ’2
@@ -39,12 +39,13 @@ import Data.List (stripPrefix, (\\), nubBy)
39import Data.List.NonEmpty (NonEmpty(..))
39import Data.List.NonEmpty (NonEmpty(..))
40import Data.List.Split (splitOn)
40import Data.List.Split (splitOn)
41import Data.Maybe
41import Data.Maybe
42โˆ’import Data.Version
43โˆ’import qualified Data.SPDX as SPDX
44import Data.Text (Text)
42import Data.Text (Text)
45import qualified Data.Text as T
43import qualified Data.Text as T
46import qualified Data.Text.Lazy as TL
44import qualified Data.Text.Lazy as TL
47import qualified Data.Text.Lazy.Encoding as TL
45import qualified Data.Text.Lazy.Encoding as TL
46+import Data.Time.Clock (UTCTime)
47+import Data.Version
48+import qualified Data.SPDX as SPDX
48
49
49import Safe (headMay)
50import Safe (headMay)
50
51
@@ -67,6 +68,7 @@ data PublishOptions = PublishOptions
67 { -- | How to obtain the version tag and version that the data being
68 { -- | How to obtain the version tag and version that the data being
68 -- generated will refer to.
69 -- generated will refer to.
69 publishGetVersion :: PrepareM (Text, Version)
70 publishGetVersion :: PrepareM (Text, Version)
71+ , publishGetTagTime :: Text -> PrepareM UTCTime
70 , -- | What to do when the working tree is dirty
72 , -- | What to do when the working tree is dirty
71 publishWorkingTreeDirty :: PrepareM ()
73 publishWorkingTreeDirty :: PrepareM ()
72 }
74 }
@@ -74,6 +76,7 @@ data PublishOptions = PublishOptions
74defaultPublishOptions :: PublishOptions
76defaultPublishOptions :: PublishOptions
75defaultPublishOptions = PublishOptions
77defaultPublishOptions = PublishOptions
76 { publishGetVersion = getVersionFromGitTag
78 { publishGetVersion = getVersionFromGitTag
79+ , publishGetTagTime = getTagTime
77 , publishWorkingTreeDirty = userError DirtyWorkingTree
80 , publishWorkingTreeDirty = userError DirtyWorkingTree
78 }
81 }
79
82
@@ -139,6 +142,7 @@ preparePackage' opts = do
139 checkLicense pkgMeta
142 checkLicense pkgMeta
140
143
141 (pkgVersionTag, pkgVersion) <- publishGetVersion opts
144 (pkgVersionTag, pkgVersion) <- publishGetVersion opts
145+ pkgTagTime <- Just <$> publishGetTagTime opts pkgVersionTag
142 pkgGithub <- getBowerRepositoryInfo pkgMeta
146 pkgGithub <- getBowerRepositoryInfo pkgMeta
143 (pkgBookmarks, pkgModules) <- getModulesAndBookmarks
147 (pkgBookmarks, pkgModules) <- getModulesAndBookmarks
144
148
@@ -200,6 +204,13 @@ getVersionFromGitTag = do
200 digits <- stripPrefix "v" str
204 digits <- stripPrefix "v" str
201 (str,) <$> D.parseVersion' digits
205 (str,) <$> D.parseVersion' digits
202
206
207+-- | Given a git tag, get the time it was created.
208+getTagTime :: Text -> PrepareM UTCTime
209+getTagTime tag = do
210+ out <- readProcess' "git" ["show", T.unpack tag, "--no-patch", "--format=%aI"] ""
211+ let time = headMay (lines out) >>= D.parseTime
212+ maybe (internalError (CouldntParseGitTagDate tag)) pure time
213+
203getBowerRepositoryInfo :: PackageMeta -> PrepareM (D.GithubUser, D.GithubRepo)
214getBowerRepositoryInfo :: PackageMeta -> PrepareM (D.GithubUser, D.GithubRepo)
204getBowerRepositoryInfo = either (userError . BadRepositoryField) return . tryExtract
215getBowerRepositoryInfo = either (userError . BadRepositoryField) return . tryExtract
205 where
216 where
src/Language/PureScript/Publish/ErrorsWarnings.hs+4
@@ -73,6 +73,7 @@ data RepositoryFieldError
73-- | An error that probably indicates a bug in this module.
73-- | An error that probably indicates a bug in this module.
74data InternalError
74data InternalError
75 = JSONError JSONSource (ParseError BowerError)
75 = JSONError JSONSource (ParseError BowerError)
76+ | CouldntParseGitTagDate Text
76 deriving (Show)
77 deriving (Show)
77
78
78data JSONSource
79data JSONSource
@@ -289,6 +290,9 @@ displayInternalError e = case e of
289 [ "Error in JSON " ++ displayJSONSource src ++ ":"
290 [ "Error in JSON " ++ displayJSONSource src ++ ":"
290 , T.unpack (Bower.displayError r)
291 , T.unpack (Bower.displayError r)
291 ]
292 ]
293+ CouldntParseGitTagDate tag ->
294+ [ "Unable to parse the date for a git tag: " ++ T.unpack tag
295+ ]
292
296
293displayJSONSource :: JSONSource -> String
297displayJSONSource :: JSONSource -> String
294displayJSONSource s = case s of
298displayJSONSource s = case s of
src/Language/PureScript/Sugar/DoNotation.hs+8โˆ’1
@@ -9,7 +9,6 @@ import Prelude.Compat
9import Control.Monad.Error.Class (MonadError(..))
9import Control.Monad.Error.Class (MonadError(..))
10import Control.Monad.Supply.Class
10import Control.Monad.Supply.Class
11
11
12โˆ’
13import Language.PureScript.AST
12import Language.PureScript.AST
14import Language.PureScript.Crash
13import Language.PureScript.Crash
15import Language.PureScript.Errors
14import Language.PureScript.Errors
@@ -49,6 +48,8 @@ desugarDo d =
49 return $ App (App bind val) (Abs (Left (Ident C.__unused)) rest')
48 return $ App (App bind val) (Abs (Left (Ident C.__unused)) rest')
50 go [DoNotationBind _ _] = throwError . errorMessage $ InvalidDoBind
49 go [DoNotationBind _ _] = throwError . errorMessage $ InvalidDoBind
51 go (DoNotationBind NullBinder val : rest) = go (DoNotationValue val : rest)
50 go (DoNotationBind NullBinder val : rest) = go (DoNotationValue val : rest)
51+ go (DoNotationBind b _ : _) | Ident C.bind `elem` binderNames b =
52+ throwError . errorMessage $ CannotUseBindWithDo
52 go (DoNotationBind (VarBinder ident) val : rest) = do
53 go (DoNotationBind (VarBinder ident) val : rest) = do
53 rest' <- go rest
54 rest' <- go rest
54 return $ App (App bind val) (Abs (Left ident) rest')
55 return $ App (App bind val) (Abs (Left ident) rest')
@@ -58,6 +59,12 @@ desugarDo d =
58 return $ App (App bind val) (Abs (Left ident) (Case [Var (Qualified Nothing ident)] [CaseAlternative [binder] (Right rest')]))
59 return $ App (App bind val) (Abs (Left ident) (Case [Var (Qualified Nothing ident)] [CaseAlternative [binder] (Right rest')]))
59 go [DoNotationLet _] = throwError . errorMessage $ InvalidDoLet
60 go [DoNotationLet _] = throwError . errorMessage $ InvalidDoLet
60 go (DoNotationLet ds : rest) = do
61 go (DoNotationLet ds : rest) = do
62+ let checkBind :: Declaration -> m ()
63+ checkBind (ValueDeclaration (Ident name) _ _ _)
64+ | name == C.bind = throwError . errorMessage $ CannotUseBindWithDo
65+ checkBind (PositionedDeclaration pos _ decl) = rethrowWithPosition pos (checkBind decl)
66+ checkBind _ = pure ()
67+ mapM_ checkBind ds
61 rest' <- go rest
68 rest' <- go rest
62 return $ Let ds rest'
69 return $ Let ds rest'
63 go (PositionedDoNotationElement pos com el : rest) = rethrowWithPosition pos $ PositionedValue pos com <$> go (el : rest)
70 go (PositionedDoNotationElement pos com el : rest) = rethrowWithPosition pos $ PositionedValue pos com <$> go (el : rest)
src/Language/PureScript/Sugar/Names/Env.hs+6โˆ’1
@@ -242,7 +242,12 @@ exportType
242 -> m Exports
242 -> m Exports
243exportType exportMode exps name dctors mn = do
243exportType exportMode exps name dctors mn = do
244 let exTypes = exportedTypes exps
244 let exTypes = exportedTypes exps
245โˆ’ let exClasses = exportedTypeClasses exps
245+ exClasses = exportedTypeClasses exps
246+ dctorNameCounts :: [(ProperName 'ConstructorName, Int)]
247+ dctorNameCounts = M.toList $ M.fromListWith (+) (map (,1) dctors)
248+ forM_ dctorNameCounts $ \(dctorName, count) ->
249+ when (count > 1) $
250+ throwDeclConflict (DctorName dctorName) (DctorName dctorName)
246 case exportMode of
251 case exportMode of
247 Internal -> do
252 Internal -> do
248 when (name `M.member` exTypes) $
253 when (name `M.member` exTypes) $
src/Language/PureScript/Sugar/ObjectWildcards.hs+4โˆ’4
@@ -11,11 +11,11 @@ import Control.Monad.Supply.Class
11
11
12import Data.List (partition)
12import Data.List (partition)
13import Data.Maybe (catMaybes)
13import Data.Maybe (catMaybes)
14โˆ’import Data.Text (Text)
15
14
16import Language.PureScript.AST
15import Language.PureScript.AST
17import Language.PureScript.Errors
16import Language.PureScript.Errors
18import Language.PureScript.Names
17import Language.PureScript.Names
18+import Language.PureScript.PSString (PSString)
19
19
20desugarObjectConstructors
20desugarObjectConstructors
21 :: forall m
21 :: forall m
@@ -62,7 +62,7 @@ desugarDecl other = fn other
62 return $ foldr (Abs . Left) if_ (catMaybes [u', t', f'])
62 return $ foldr (Abs . Left) if_ (catMaybes [u', t', f'])
63 desugarExpr e = return e
63 desugarExpr e = return e
64
64
65โˆ’ wrapLambda :: ([(Text, Expr)] -> Expr) -> [(Text, Expr)] -> m Expr
65+ wrapLambda :: ([(PSString, Expr)] -> Expr) -> [(PSString, Expr)] -> m Expr
66 wrapLambda mkVal ps =
66 wrapLambda mkVal ps =
67 let (args, props) = partition (isAnonymousArgument . snd) ps
67 let (args, props) = partition (isAnonymousArgument . snd) ps
68 in if null args
68 in if null args
@@ -75,7 +75,7 @@ desugarDecl other = fn other
75 stripPositionInfo (PositionedValue _ _ e) = stripPositionInfo e
75 stripPositionInfo (PositionedValue _ _ e) = stripPositionInfo e
76 stripPositionInfo e = e
76 stripPositionInfo e = e
77
77
78โˆ’ peelAnonAccessorChain :: Expr -> Maybe [Text]
78+ peelAnonAccessorChain :: Expr -> Maybe [PSString]
79 peelAnonAccessorChain (Accessor p e) = (p :) <$> peelAnonAccessorChain e
79 peelAnonAccessorChain (Accessor p e) = (p :) <$> peelAnonAccessorChain e
80 peelAnonAccessorChain (PositionedValue _ _ e) = peelAnonAccessorChain e
80 peelAnonAccessorChain (PositionedValue _ _ e) = peelAnonAccessorChain e
81 peelAnonAccessorChain AnonymousArgument = Just []
81 peelAnonAccessorChain AnonymousArgument = Just []
@@ -86,7 +86,7 @@ desugarDecl other = fn other
86 isAnonymousArgument (PositionedValue _ _ e) = isAnonymousArgument e
86 isAnonymousArgument (PositionedValue _ _ e) = isAnonymousArgument e
87 isAnonymousArgument _ = False
87 isAnonymousArgument _ = False
88
88
89โˆ’ mkProp :: (Text, Expr) -> m (Maybe Ident, (Text, Expr))
89+ mkProp :: (PSString, Expr) -> m (Maybe Ident, (PSString, Expr))
90 mkProp (name, e) = do
90 mkProp (name, e) = do
91 arg <- freshIfAnon e
91 arg <- freshIfAnon e
92 return (arg, (name, maybe e argToExpr arg))
92 return (arg, (name, maybe e argToExpr arg))
src/Language/PureScript/Sugar/TypeClasses.hs+4โˆ’2
@@ -19,6 +19,8 @@ import Language.PureScript.Externs
19import Language.PureScript.Sugar.CaseDeclarations
19import Language.PureScript.Sugar.CaseDeclarations
20import Control.Monad.Supply.Class
20import Control.Monad.Supply.Class
21import Language.PureScript.Types
21import Language.PureScript.Types
22+import Language.PureScript.Label (Label(..))
23+import Language.PureScript.PSString (mkString)
22
24
23import qualified Language.PureScript.Constants as C
25import qualified Language.PureScript.Constants as C
24
26
@@ -240,7 +242,7 @@ typeClassDictionaryDeclaration name args implies members =
240 ]
242 ]
241 members' = map (first runIdent . memberToNameAndType) members
243 members' = map (first runIdent . memberToNameAndType) members
242 mtys = members' ++ superclassTypes
244 mtys = members' ++ superclassTypes
243โˆ’ in TypeSynonymDeclaration (coerceProperName name) args (TypeApp tyRecord $ rowFromList (mtys, REmpty))
245+ in TypeSynonymDeclaration (coerceProperName name) args (TypeApp tyRecord $ rowFromList (map (first (Label . mkString)) mtys, REmpty))
244
246
245typeClassMemberToDictionaryAccessor
247typeClassMemberToDictionaryAccessor
246 :: ModuleName
248 :: ModuleName
@@ -297,7 +299,7 @@ typeInstanceDictionaryDeclaration name mn deps className tys decls =
297 , let tyArgs = map (replaceAllTypeVars (zip (map fst typeClassArguments) tys)) suTyArgs
299 , let tyArgs = map (replaceAllTypeVars (zip (map fst typeClassArguments) tys)) suTyArgs
298 ]
300 ]
299
301
300โˆ’ let props = Literal $ ObjectLiteral (members ++ superclasses)
302+ let props = Literal $ ObjectLiteral $ map (first mkString) (members ++ superclasses)
301 dictTy = foldl TypeApp (TypeConstructor (fmap coerceProperName className)) tys
303 dictTy = foldl TypeApp (TypeConstructor (fmap coerceProperName className)) tys
302 constrainedTy = quantify (if null deps then dictTy else ConstrainedType deps dictTy)
304 constrainedTy = quantify (if null deps then dictTy else ConstrainedType deps dictTy)
303 dict = TypeClassDictionaryConstructorApp className props
305 dict = TypeClassDictionaryConstructorApp className props
src/Language/PureScript/Sugar/TypeClasses/Deriving.hs+39โˆ’24
@@ -11,9 +11,11 @@ import Control.Monad.Error.Class (MonadError(..))
11import Control.Monad.Supply.Class (MonadSupply)
11import Control.Monad.Supply.Class (MonadSupply)
12import Data.List (foldl', find, sortBy, unzip5)
12import Data.List (foldl', find, sortBy, unzip5)
13import qualified Data.Map as M
13import qualified Data.Map as M
14+import Data.Monoid ((<>))
14import Data.Maybe (fromMaybe, mapMaybe)
15import Data.Maybe (fromMaybe, mapMaybe)
15import Data.Ord (comparing)
16import Data.Ord (comparing)
16import Data.Text (Text)
17import Data.Text (Text)
18+import qualified Data.Text as T
17import Language.PureScript.AST
19import Language.PureScript.AST
18import qualified Language.PureScript.Constants as C
20import qualified Language.PureScript.Constants as C
19import Language.PureScript.Crash
21import Language.PureScript.Crash
@@ -22,6 +24,8 @@ import Language.PureScript.Errors
22import Language.PureScript.Externs
24import Language.PureScript.Externs
23import Language.PureScript.Kinds
25import Language.PureScript.Kinds
24import Language.PureScript.Names
26import Language.PureScript.Names
27+import Language.PureScript.Label (Label(..))
28+import Language.PureScript.PSString (mkString, decodeStringEither)
25import Language.PureScript.Types
29import Language.PureScript.Types
26import Language.PureScript.TypeChecker (checkNewtype)
30import Language.PureScript.TypeChecker (checkNewtype)
27import Language.PureScript.TypeChecker.Synonyms (SynonymMap, replaceAllTypeSynonymsM)
31import Language.PureScript.TypeChecker.Synonyms (SynonymMap, replaceAllTypeSynonymsM)
@@ -207,7 +211,7 @@ deriveGeneric mn syns ds tyConNm dargs = do
207 idents <- replicateM (length tys) freshIdent'
211 idents <- replicateM (length tys) freshIdent'
208 tys' <- mapM (replaceAllTypeSynonymsM syns) tys
212 tys' <- mapM (replaceAllTypeSynonymsM syns) tys
209 let caseResult =
213 let caseResult =
210โˆ’ App (prodConstructor (Literal . StringLiteral . showQualified runProperName $ Qualified (Just mn) ctorName))
214+ App (prodConstructor (Literal . StringLiteral . mkString . showQualified runProperName $ Qualified (Just mn) ctorName))
211 . Literal . ArrayLiteral
215 . Literal . ArrayLiteral
212 $ zipWith toSpineFun (map (Var . Qualified Nothing) idents) tys'
216 $ zipWith toSpineFun (map (Var . Qualified Nothing) idents) tys'
213 return $ CaseAlternative [ConstructorBinder (Qualified (Just mn) ctorName) (map VarBinder idents)] (Right caseResult)
217 return $ CaseAlternative [ConstructorBinder (Qualified (Just mn) ctorName) (map VarBinder idents)] (Right caseResult)
@@ -216,7 +220,7 @@ deriveGeneric mn syns ds tyConNm dargs = do
216 toSpineFun i r | Just rec <- objectType r =
220 toSpineFun i r | Just rec <- objectType r =
217 lamNull . recordConstructor . Literal . ArrayLiteral
221 lamNull . recordConstructor . Literal . ArrayLiteral
218 . map
222 . map
219โˆ’ (\(str,typ) ->
223+ (\((Label str),typ) ->
220 Literal $ ObjectLiteral
224 Literal $ ObjectLiteral
221 [ ("recLabel", Literal (StringLiteral str))
225 [ ("recLabel", Literal (StringLiteral str))
222 , ("recValue", toSpineFun (Accessor str i) typ)
226 , ("recValue", toSpineFun (Accessor str i) typ)
@@ -235,7 +239,7 @@ deriveGeneric mn syns ds tyConNm dargs = do
235 App
239 App
236 (App
240 (App
237 (Constructor (Qualified (Just dataGeneric) (ProperName "SigProd")))
241 (Constructor (Qualified (Just dataGeneric) (ProperName "SigProd")))
238โˆ’ (Literal (StringLiteral (showQualified runProperName (Qualified (Just mn) name))))
242+ (Literal (StringLiteral $ mkString (showQualified runProperName (Qualified (Just mn) name))))
239 )
243 )
240 . Literal
244 . Literal
241 . ArrayLiteral
245 . ArrayLiteral
@@ -249,7 +253,7 @@ deriveGeneric mn syns ds tyConNm dargs = do
249 mkProdClause :: (ProperName 'ConstructorName, [Type]) -> Expr
253 mkProdClause :: (ProperName 'ConstructorName, [Type]) -> Expr
250 mkProdClause (ctorName, tys) =
254 mkProdClause (ctorName, tys) =
251 Literal $ ObjectLiteral
255 Literal $ ObjectLiteral
252โˆ’ [ ("sigConstructor", Literal (StringLiteral (showQualified runProperName (Qualified (Just mn) ctorName))))
256+ [ ("sigConstructor", Literal (StringLiteral $ mkString (showQualified runProperName (Qualified (Just mn) ctorName))))
253 , ("sigValues", Literal . ArrayLiteral . map (mkProductSignature . instantiate) $ tys)
257 , ("sigValues", Literal . ArrayLiteral . map (mkProductSignature . instantiate) $ tys)
254 ]
258 ]
255
259
@@ -260,7 +264,7 @@ deriveGeneric mn syns ds tyConNm dargs = do
260 [ ("recLabel", Literal (StringLiteral str))
264 [ ("recLabel", Literal (StringLiteral str))
261 , ("recValue", mkProductSignature typ)
265 , ("recValue", mkProductSignature typ)
262 ]
266 ]
263โˆ’ | (str, typ) <- decomposeRec rec
267+ | ((Label str), typ) <- decomposeRec rec
264 ]
268 ]
265 mkProductSignature typ = lamNull $ App (mkGenVar (Ident C.toSignature))
269 mkProductSignature typ = lamNull $ App (mkGenVar (Ident C.toSignature))
266 (TypedValue False (mkGenVar (Ident "anyProxy")) (proxy typ))
270 (TypedValue False (mkGenVar (Ident "anyProxy")) (proxy typ))
@@ -291,7 +295,7 @@ deriveGeneric mn syns ds tyConNm dargs = do
291 return $
295 return $
292 CaseAlternative
296 CaseAlternative
293 [ prodBinder
297 [ prodBinder
294โˆ’ [ LiteralBinder (StringLiteral (showQualified runProperName (Qualified (Just mn) ctorName)))
298+ [ LiteralBinder (StringLiteral $ mkString (showQualified runProperName (Qualified (Just mn) ctorName)))
295 , LiteralBinder (ArrayLiteral (map VarBinder idents))
299 , LiteralBinder (ArrayLiteral (map VarBinder idents))
296 ]
300 ]
297 ]
301 ]
@@ -314,16 +318,16 @@ deriveGeneric mn syns ds tyConNm dargs = do
314 (App e unitVal)
318 (App e unitVal)
315 fromSpineFun e _ = App (mkGenVar (Ident C.fromSpine)) (App e unitVal)
319 fromSpineFun e _ = App (mkGenVar (Ident C.fromSpine)) (App e unitVal)
316
320
317โˆ’ mkRecCase :: [(Text, Type)] -> CaseAlternative
321+ mkRecCase :: [(Label, Type)] -> CaseAlternative
318 mkRecCase rs =
322 mkRecCase rs =
319 CaseAlternative
323 CaseAlternative
320โˆ’ [ recordBinder [ LiteralBinder (ArrayLiteral (map (VarBinder . Ident . fst) rs)) ] ]
324+ [ recordBinder [ LiteralBinder (ArrayLiteral (map (VarBinder . labelToIdent . fst) rs)) ] ]
321 . Right
325 . Right
322โˆ’ $ liftApplicative (mkRecFun rs) (map (\(x, y) -> fromSpineFun (Accessor "recValue" (mkVar (Ident x))) y) rs)
326+ $ liftApplicative (mkRecFun rs) (map (\(x, y) -> fromSpineFun (Accessor "recValue" (mkVar $ labelToIdent x)) y) rs)
323
327
324โˆ’ mkRecFun :: [(Text, Type)] -> Expr
328+ mkRecFun :: [(Label, Type)] -> Expr
325โˆ’ mkRecFun xs = mkJust $ foldr (lam . Ident . fst) recLiteral xs
329+ mkRecFun xs = mkJust $ foldr (lam . labelToIdent . fst) recLiteral xs
326โˆ’ where recLiteral = Literal . ObjectLiteral $ map (\(s,_) -> (s, mkVar (Ident s))) xs
330+ where recLiteral = Literal . ObjectLiteral $ map (\(l@(Label s), _) -> (s, mkVar $ labelToIdent l)) xs
327 mkFromSpineFunction (PositionedDeclaration _ _ d) = mkFromSpineFunction d
331 mkFromSpineFunction (PositionedDeclaration _ _ d) = mkFromSpineFunction d
328 mkFromSpineFunction _ = internalError "mkFromSpineFunction: expected DataDeclaration"
332 mkFromSpineFunction _ = internalError "mkFromSpineFunction: expected DataDeclaration"
329
333
@@ -405,7 +409,7 @@ deriveGenericRep mn syns ds tyConNm tyConArgs repTy = do
405 args' <- mapM (replaceAllTypeSynonymsM syns) args
409 args' <- mapM (replaceAllTypeSynonymsM syns) args
406 (ctorTy, matchProduct, ctorArgs, matchCtor, mkProduct) <- makeProduct args'
410 (ctorTy, matchProduct, ctorArgs, matchCtor, mkProduct) <- makeProduct args'
407 return ( TypeApp (TypeApp (TypeConstructor constructor)
411 return ( TypeApp (TypeApp (TypeConstructor constructor)
408โˆ’ (TypeLevelString (runProperName ctorName)))
412+ (TypeLevelString $ mkString (runProperName ctorName)))
409 ctorTy
413 ctorTy
410 , CaseAlternative [ ConstructorBinder constructor [matchProduct] ]
414 , CaseAlternative [ ConstructorBinder constructor [matchProduct] ]
411 (Right (foldl App (Constructor (Qualified (Just mn) ctorName)) ctorArgs))
415 (Right (foldl App (Constructor (Qualified (Just mn) ctorName)) ctorArgs))
@@ -430,19 +434,19 @@ deriveGenericRep mn syns ds tyConNm tyConArgs repTy = do
430 makeArg :: Type -> m (Type, Binder, Expr, Binder, Expr)
434 makeArg :: Type -> m (Type, Binder, Expr, Binder, Expr)
431 makeArg arg | Just rec <- objectType arg = do
435 makeArg arg | Just rec <- objectType arg = do
432 let fields = decomposeRec rec
436 let fields = decomposeRec rec
433โˆ’ fieldNames <- traverse freshIdent (map fst fields)
437+ fieldNames <- traverse freshIdent (map (runIdent . labelToIdent . fst) fields)
434 pure ( TypeApp (TypeConstructor record)
438 pure ( TypeApp (TypeConstructor record)
435 (foldr1 (\f -> TypeApp (TypeApp (TypeConstructor productName) f))
439 (foldr1 (\f -> TypeApp (TypeApp (TypeConstructor productName) f))
436โˆ’ (map (\(name, ty) ->
440+ (map (\((Label name), ty) ->
437 TypeApp (TypeApp (TypeConstructor field) (TypeLevelString name)) ty) fields))
441 TypeApp (TypeApp (TypeConstructor field) (TypeLevelString name)) ty) fields))
438 , ConstructorBinder record
442 , ConstructorBinder record
439 [ foldr1 (\b1 b2 -> ConstructorBinder productName [b1, b2])
443 [ foldr1 (\b1 b2 -> ConstructorBinder productName [b1, b2])
440 (map (\ident -> ConstructorBinder field [VarBinder ident]) fieldNames)
444 (map (\ident -> ConstructorBinder field [VarBinder ident]) fieldNames)
441 ]
445 ]
442 , Literal . ObjectLiteral $
446 , Literal . ObjectLiteral $
443โˆ’ zipWith (\(name, _) ident -> (name, Var (Qualified Nothing ident))) fields fieldNames
447+ zipWith (\((Label name), _) ident -> (name, Var (Qualified Nothing ident))) fields fieldNames
444 , LiteralBinder . ObjectLiteral $
448 , LiteralBinder . ObjectLiteral $
445โˆ’ zipWith (\(name, _) ident -> (name, VarBinder ident)) fields fieldNames
449+ zipWith (\((Label name), _) ident -> (name, VarBinder ident)) fields fieldNames
446 , record' $
450 , record' $
447 foldr1 (\e1 -> App (App (Constructor productName) e1))
451 foldr1 (\e1 -> App (App (Constructor productName) e1))
448 (map (field' . Var . Qualified Nothing) fieldNames)
452 (map (field' . Var . Qualified Nothing) fieldNames)
@@ -574,7 +578,7 @@ deriveEq mn syns ds tyConNm = do
574 toEqTest :: Expr -> Expr -> Type -> Expr
578 toEqTest :: Expr -> Expr -> Type -> Expr
575 toEqTest l r ty | Just rec <- objectType ty =
579 toEqTest l r ty | Just rec <- objectType ty =
576 conjAll
580 conjAll
577โˆ’ . map (\(str, typ) -> toEqTest (Accessor str l) (Accessor str r) typ)
581+ . map (\((Label str), typ) -> toEqTest (Accessor str l) (Accessor str r) typ)
578 $ decomposeRec rec
582 $ decomposeRec rec
579 toEqTest l r _ = preludeEq l r
583 toEqTest l r _ = preludeEq l r
580
584
@@ -661,7 +665,7 @@ deriveOrd mn syns ds tyConNm = do
661 toOrdering :: Expr -> Expr -> Type -> Expr
665 toOrdering :: Expr -> Expr -> Type -> Expr
662 toOrdering l r ty | Just rec <- objectType ty =
666 toOrdering l r ty | Just rec <- objectType ty =
663 appendAll
667 appendAll
664โˆ’ . map (\(str, typ) -> toOrdering (Accessor str l) (Accessor str r) typ)
668+ . map (\((Label str), typ) -> toOrdering (Accessor str l) (Accessor str r) typ)
665 $ decomposeRec rec
669 $ decomposeRec rec
666 toOrdering l r _ = ordCompare l r
670 toOrdering l r _ = ordCompare l r
667
671
@@ -733,11 +737,22 @@ mkVarMn mn = Var . Qualified mn
733mkVar :: Ident -> Expr
737mkVar :: Ident -> Expr
734mkVar = mkVarMn Nothing
738mkVar = mkVarMn Nothing
735
739
740+-- This function may seem a little obtuse, but it's only this way to ensure
741+-- that it is injective. Injectivity is important here; without it, we can end
742+-- up with accidental variable shadowing in the generated code.
743+labelToIdent :: Label -> Ident
744+labelToIdent =
745+ Ident . foldMap (either loneSurrogate char) . decodeStringEither . runLabel
746+ where
747+ char '_' = "__"
748+ char c = T.singleton c
749+ loneSurrogate x = "_" <> T.pack (show x) <> "_"
750+
736objectType :: Type -> Maybe Type
751objectType :: Type -> Maybe Type
737objectType (TypeApp (TypeConstructor (Qualified (Just (ModuleName [ProperName "Prim"])) (ProperName "Record"))) rec) = Just rec
752objectType (TypeApp (TypeConstructor (Qualified (Just (ModuleName [ProperName "Prim"])) (ProperName "Record"))) rec) = Just rec
738objectType _ = Nothing
753objectType _ = Nothing
739
754
740โˆ’decomposeRec :: Type -> [(Text, Type)]
755+decomposeRec :: Type -> [(Label, Type)]
741decomposeRec = sortBy (comparing fst) . go
756decomposeRec = sortBy (comparing fst) . go
742 where go (RCons str typ typs) = (str, typ) : decomposeRec typs
757 where go (RCons str typ typs) = (str, typ) : decomposeRec typs
743 go _ = []
758 go _ = []
@@ -790,17 +805,17 @@ deriveFunctor mn syns ds tyConNm = do
790 goType recTy | Just row <- objectType recTy =
805 goType recTy | Just row <- objectType recTy =
791 traverse buildUpdate (decomposeRec row) >>= (traverse buildRecord . justUpdates)
806 traverse buildUpdate (decomposeRec row) >>= (traverse buildRecord . justUpdates)
792 where
807 where
793โˆ’ justUpdates :: [Maybe (Text, Expr)] -> Maybe [(Text, Expr)]
808+ justUpdates :: [Maybe (Label, Expr)] -> Maybe [(Label, Expr)]
794 justUpdates = foldMap (fmap return)
809 justUpdates = foldMap (fmap return)
795
810
796โˆ’ buildUpdate :: (Text, Type) -> m (Maybe (Text, Expr))
811+ buildUpdate :: (Label, Type) -> m (Maybe (Label, Expr))
797 buildUpdate (lbl, ty) = do upd <- goType ty
812 buildUpdate (lbl, ty) = do upd <- goType ty
798 return ((lbl,) <$> upd)
813 return ((lbl,) <$> upd)
799
814
800โˆ’ buildRecord :: [(Text, Expr)] -> m Expr
815+ buildRecord :: [(Label, Expr)] -> m Expr
801 buildRecord updates = do arg <- freshIdent "o"
816 buildRecord updates = do arg <- freshIdent "o"
802 let argVar = mkVar arg
817 let argVar = mkVar arg
803โˆ’ mkAssignment (l, x) = (l, App x (Accessor l argVar))
818+ mkAssignment ((Label l), x) = (l, App x (Accessor l argVar))
804 return (lam arg (ObjectUpdate argVar (mkAssignment <$> updates)))
819 return (lam arg (ObjectUpdate argVar (mkAssignment <$> updates)))
805
820
806 -- under a `* -> *`, just assume functor for now
821 -- under a `* -> *`, just assume functor for now
src/Language/PureScript/TypeChecker/Entailment.hs+6โˆ’4
@@ -37,13 +37,15 @@ import Language.PureScript.TypeChecker.Monad
37import Language.PureScript.TypeChecker.Unify
37import Language.PureScript.TypeChecker.Unify
38import Language.PureScript.TypeClassDictionaries
38import Language.PureScript.TypeClassDictionaries
39import Language.PureScript.Types
39import Language.PureScript.Types
40+import Language.PureScript.Label (Label(..))
41+import Language.PureScript.PSString (PSString, mkString)
40import qualified Language.PureScript.Constants as C
42import qualified Language.PureScript.Constants as C
41
43
42-- | Describes what sort of dictionary to generate for type class instances
44-- | Describes what sort of dictionary to generate for type class instances
43data Evidence
45data Evidence
44 = NamedInstance (Qualified Ident)
46 = NamedInstance (Qualified Ident)
45 -- ^ An existing named instance
47 -- ^ An existing named instance
46โˆ’ | IsSymbolInstance Text
48+ | IsSymbolInstance PSString
47 -- ^ Computed instance of the IsSymbol type class for a given Symbol literal
49 -- ^ Computed instance of the IsSymbol type class for a given Symbol literal
48 | CompareSymbolInstance
50 | CompareSymbolInstance
49 -- ^ Computed instance of CompareSymbol
51 -- ^ Computed instance of CompareSymbol
@@ -319,7 +321,7 @@ entails SolverOptions{..} constraint context hints =
319 -- Turn a DictionaryValue into a Expr
321 -- Turn a DictionaryValue into a Expr
320 subclassDictionaryValue :: Expr -> Qualified (ProperName a) -> Integer -> Expr
322 subclassDictionaryValue :: Expr -> Qualified (ProperName a) -> Integer -> Expr
321 subclassDictionaryValue dict superclassName index =
323 subclassDictionaryValue dict superclassName index =
322โˆ’ App (Accessor (C.__superclass_ <> showQualified runProperName superclassName <> "_" <> T.pack (show index))
324+ App (Accessor (mkString (C.__superclass_ <> showQualified runProperName superclassName <> "_" <> T.pack (show index)))
323 dict)
325 dict)
324 valUndefined
326 valUndefined
325
327
@@ -387,7 +389,7 @@ matches deps TypeClassDictionaryInScope{..} tys = do
387 sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]
389 sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]
388 sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]
390 sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]
389
391
390โˆ’ go :: [(Text, Type)] -> Type -> [(Text, Type)] -> Type -> (Bool, Matching [Type])
392+ go :: [(Label, Type)] -> Type -> [(Label, Type)] -> Type -> (Bool, Matching [Type])
391 go l (KindedType t1 _) r t2 = go l t1 r t2
393 go l (KindedType t1 _) r t2 = go l t1 r t2
392 go l t1 r (KindedType t2 _) = go l t1 r t2
394 go l t1 r (KindedType t2 _) = go l t1 r t2
393 go [] REmpty [] REmpty = (True, M.empty)
395 go [] REmpty [] REmpty = (True, M.empty)
@@ -429,7 +431,7 @@ matches deps TypeClassDictionaryInScope{..} tys = do
429 sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]
431 sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]
430 in all (uncurry typesAreEqual) int && go sd1 r1' sd2 r2'
432 in all (uncurry typesAreEqual) int && go sd1 r1' sd2 r2'
431 where
433 where
432โˆ’ go :: [(Text, Type)] -> Type -> [(Text, Type)] -> Type -> Bool
434+ go :: [(Label, Type)] -> Type -> [(Label, Type)] -> Type -> Bool
433 go l (KindedType t1 _) r t2 = go l t1 r t2
435 go l (KindedType t1 _) r t2 = go l t1 r t2
434 go l t1 r (KindedType t2 _) = go l t1 r t2
436 go l t1 r (KindedType t2 _) = go l t1 r t2
435 go [] (TUnknown u1) [] (TUnknown u2) | u1 == u2 = True
437 go [] (TUnknown u1) [] (TUnknown u2) | u1 == u2 = True
src/Language/PureScript/TypeChecker/Kinds.hs+1
@@ -229,6 +229,7 @@ infer' other = (, []) <$> go other
229 unifyKinds k k'
229 unifyKinds k k'
230 return k'
230 return k'
231 go TypeWildcard{} = freshKind
231 go TypeWildcard{} = freshKind
232+ go TUnknown{} = freshKind
232 go (TypeLevelString _) = return kindSymbol
233 go (TypeLevelString _) = return kindSymbol
233 go (TypeVar v) = do
234 go (TypeVar v) = do
234 Just moduleName <- checkCurrentModule <$> get
235 Just moduleName <- checkCurrentModule <$> get
src/Language/PureScript/TypeChecker/Types.hs+146โˆ’124
@@ -34,14 +34,14 @@ import Control.Monad.Supply.Class (MonadSupply)
34import Control.Monad.Writer.Class (MonadWriter(..))
34import Control.Monad.Writer.Class (MonadWriter(..))
35
35
36import Data.Bifunctor (bimap)
36import Data.Bifunctor (bimap)
37โˆ’import Data.Either (lefts, rights)
37+import Data.Either (partitionEithers)
38import Data.Functor (($>))
38import Data.Functor (($>))
39import Data.List (transpose, nub, (\\), partition, delete)
39import Data.List (transpose, nub, (\\), partition, delete)
40import Data.Maybe (fromMaybe)
40import Data.Maybe (fromMaybe)
41import Data.Monoid ((<>))
41import Data.Monoid ((<>))
42import qualified Data.Map as M
42import qualified Data.Map as M
43import qualified Data.Set as S
43import qualified Data.Set as S
44โˆ’import Data.Text (Text)
44+import Data.Traversable (for)
45
45
46import Language.PureScript.AST
46import Language.PureScript.AST
47import Language.PureScript.Crash
47import Language.PureScript.Crash
@@ -60,7 +60,8 @@ import Language.PureScript.TypeChecker.Synonyms
60import Language.PureScript.TypeChecker.TypeSearch
60import Language.PureScript.TypeChecker.TypeSearch
61import Language.PureScript.TypeChecker.Unify
61import Language.PureScript.TypeChecker.Unify
62import Language.PureScript.Types
62import Language.PureScript.Types
63โˆ’
63+import Language.PureScript.Label (Label(..))
64+import Language.PureScript.PSString (PSString)
64
65
65data BindingGroupType
66data BindingGroupType
66 = RecursiveBindingGroup
67 = RecursiveBindingGroup
@@ -77,9 +78,9 @@ typesOf
77 -> m [(Ident, (Expr, Type))]
78 -> m [(Ident, (Expr, Type))]
78typesOf bindingGroupType moduleName vals = withFreshSubstitution $ do
79typesOf bindingGroupType moduleName vals = withFreshSubstitution $ do
79 tys <- capturingSubstitution tidyUp $ do
80 tys <- capturingSubstitution tidyUp $ do
80โˆ’ (untyped, typed, dict, untypedDict) <- typeDictionaryForBindingGroup (Just moduleName) vals
81+ SplitBindingGroup untyped typed dict <- typeDictionaryForBindingGroup (Just moduleName) vals
81 ds1 <- parU typed $ \e -> withoutWarnings $ checkTypedBindingGroupElement moduleName e dict
82 ds1 <- parU typed $ \e -> withoutWarnings $ checkTypedBindingGroupElement moduleName e dict
82โˆ’ ds2 <- forM untyped $ \e -> withoutWarnings $ typeForBindingGroupElement e dict untypedDict
83+ ds2 <- forM untyped $ \e -> withoutWarnings $ typeForBindingGroupElement e dict
83 return (map (False, ) ds1 ++ map (True, ) ds2)
84 return (map (False, ) ds1 ++ map (True, ) ds2)
84
85
85 inferred <- forM tys $ \(shouldGeneralize, ((ident, (val, ty)), _)) -> do
86 inferred <- forM tys $ \(shouldGeneralize, ((ident, (val, ty)), _)) -> do
@@ -165,81 +166,101 @@ typesOf bindingGroupType moduleName vals = withFreshSubstitution $ do
165 isHoleError (ErrorMessage _ HoleInferredType{}) = True
166 isHoleError (ErrorMessage _ HoleInferredType{}) = True
166 isHoleError _ = False
167 isHoleError _ = False
167
168
169+-- | A binding group contains multiple value definitions, some of which are typed
170+-- and some which are not.
171+--
172+-- This structure breaks down a binding group into typed and untyped parts.
173+data SplitBindingGroup = SplitBindingGroup
174+ { _splitBindingGroupUntyped :: [(Ident, (Expr, Type))]
175+ -- ^ The untyped expressions
176+ , _splitBindingGroupTyped :: [(Ident, (Expr, Type, Bool))]
177+ -- ^ The typed expressions, along with their type annotations
168โˆ’type TypeData = M.Map (Qualified Ident) (Type, NameKind, NameVisibility)
178+ , _splitBindingGroupNames :: M.Map (Qualified Ident) (Type, NameKind, NameVisibility)
169โˆ’
179+ -- ^ A map containing all expressions and their assigned types (which might be
170โˆ’type UntypedData = [(Ident, Type)]
180+ -- fresh unification variables). These will be added to the 'Environment' after
171โˆ’
181+ -- the binding group is checked, so the value type of the 'Map' is chosen to be
182+ -- compatible with the type of 'bindNames'.
183+ }
184+
185+-- | This function breaks a binding group down into two sets of declarations:
186+-- those which contain type annotations, and those which don't.
187+-- This function also generates fresh unification variables for the types of
188+-- declarations without type annotations, returned in the 'UntypedData' structure.
172typeDictionaryForBindingGroup
189typeDictionaryForBindingGroup
173โˆ’ :: (MonadState CheckState m)
190+ :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
174 => Maybe ModuleName
191 => Maybe ModuleName
175 -> [(Ident, Expr)]
192 -> [(Ident, Expr)]
176โˆ’ -> m ([(Ident, Expr)], [(Ident, (Expr, Type, Bool))], TypeData, UntypedData)
193+ -> m SplitBindingGroup
177typeDictionaryForBindingGroup moduleName vals = do
194typeDictionaryForBindingGroup moduleName vals = do
178โˆ’ let
195+ -- Filter the typed and untyped declarations and make a map of names to typed declarations.
179โˆ’ -- Map each declaration to a name/value pair, with an optional type, if the declaration is typed
196+ -- Replace type wildcards here so that the resulting dictionary of types contains the
180โˆ’ es = map isTyped vals
197+ -- fully expanded types.
181โˆ’ -- Filter the typed and untyped declarations
198+ let (untyped, typed) = partitionEithers (map splitTypeAnnotation vals)
182โˆ’ untyped = lefts es
199+ (typedDict, typed') <- fmap unzip . for typed $ \(ident, (expr, ty, checkType)) -> do
183โˆ’ typed = rights es
200+ ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty
184โˆ’ -- Make a map of names to typed declarations
201+ return ((ident, ty'), (ident, (expr, ty', checkType)))
185โˆ’ typedDict = map (\(ident, (_, ty, _)) -> (ident, ty)) typed
186โˆ’
187โˆ’ -- Create fresh unification variables for the types of untyped declarations
202+ -- Create fresh unification variables for the types of untyped declarations
188โˆ’ untypedNames <- replicateM (length untyped) freshType
203+ (untypedDict, untyped') <- fmap unzip . for untyped $ \(ident, expr) -> do
189โˆ’
204+ ty <- freshType
190โˆ’ let
205+ return ((ident, ty), (ident, (expr, ty)))
191โˆ’ -- Make a map of names to the unification variables of untyped declarations
192โˆ’ untypedDict = zip (map fst untyped) untypedNames
193โˆ’ -- Create the dictionary of all name/type pairs, which will be added to the environment during type checking
206+ -- Create the dictionary of all name/type pairs, which will be added to the
207+ -- environment during type checking
194โˆ’ dict = M.fromList (map (\(ident, ty) -> (Qualified moduleName ident, (ty, Private, Undefined))) $ typedDict ++ untypedDict)
208+ let dict = M.fromList [ (Qualified moduleName ident, (ty, Private, Undefined))
195โˆ’ return (untyped, typed, dict, untypedDict)
209+ | (ident, ty) <- typedDict <> untypedDict
196โˆ’
210+ ]
211+ return (SplitBindingGroup untyped' typed' dict)
212+ where
213+ -- | Check if a value contains a type annotation, and if so, separate it
214+ -- from the value itself.
215+ splitTypeAnnotation :: (Ident, Expr) -> Either (Ident, Expr) (Ident, (Expr, Type, Bool))
216+ splitTypeAnnotation (name, TypedValue checkType value ty) = Right (name, (value, ty, checkType))
217+ splitTypeAnnotation (name, PositionedValue pos c value) =
218+ bimap (second (PositionedValue pos c))
219+ (second (\(e, t, b) -> (PositionedValue pos c e, t, b)))
220+ (splitTypeAnnotation (name, value))
221+ splitTypeAnnotation (name, value) = Left (name, value)
222+
223+-- | Check the type annotation of a typed value in a binding group.
197checkTypedBindingGroupElement
224checkTypedBindingGroupElement
198 :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
225 :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
199 => ModuleName
226 => ModuleName
200 -> (Ident, (Expr, Type, Bool))
227 -> (Ident, (Expr, Type, Bool))
201โˆ’ -> TypeData
228+ -- ^ The identifier we are trying to define, along with the expression and its type annotation
229+ -> M.Map (Qualified Ident) (Type, NameKind, NameVisibility)
230+ -- ^ Names brought into scope in this binding group
202 -> m (Ident, (Expr, Type))
231 -> m (Ident, (Expr, Type))
203โˆ’checkTypedBindingGroupElement mn (ident, (val', ty, checkType)) dict = do
232+checkTypedBindingGroupElement mn (ident, (val, ty, checkType)) dict = do
204โˆ’ -- Replace type wildcards
205โˆ’ ty' <- replaceTypeWildcards ty
206 -- Kind check
233 -- Kind check
207 (kind, args) <- kindOfWithScopedVars ty
234 (kind, args) <- kindOfWithScopedVars ty
208 checkTypeKind ty kind
235 checkTypeKind ty kind
209 -- Check the type with the new names in scope
236 -- Check the type with the new names in scope
210โˆ’ ty'' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty'
211โˆ’ val'' <- if checkType
237+ val' <- if checkType
212โˆ’ then withScopedTypeVars mn args $ bindNames dict $ TypedValue True <$> check val' ty'' <*> pure ty''
238+ then withScopedTypeVars mn args $ bindNames dict $ TypedValue True <$> check val ty <*> pure ty
213โˆ’ else return (TypedValue False val' ty'')
239+ else return (TypedValue False val ty)
214โˆ’ return (ident, (val'', ty''))
240+ return (ident, (val', ty))
215
241
242+-- | Infer a type for a value in a binding group which lacks an annotation.
216typeForBindingGroupElement
243typeForBindingGroupElement
217 :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
244 :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
218โˆ’ => (Ident, Expr)
245+ => (Ident, (Expr, Type))
219โˆ’ -> TypeData
246+ -- ^ The identifier we are trying to define, along with the expression and its assigned type
220โˆ’ -> UntypedData
247+ -- (at this point, this should be a unification variable)
248+ -> M.Map (Qualified Ident) (Type, NameKind, NameVisibility)
249+ -- ^ Names brought into scope in this binding group
221 -> m (Ident, (Expr, Type))
250 -> m (Ident, (Expr, Type))
222โˆ’typeForBindingGroupElement (ident, val) dict untypedDict = do
251+typeForBindingGroupElement (ident, (val, ty)) dict = do
223 -- Infer the type with the new names in scope
252 -- Infer the type with the new names in scope
224โˆ’ TypedValue _ val' ty <- bindNames dict $ infer val
253+ TypedValue _ val' ty' <- bindNames dict $ infer val
225โˆ’ unifyTypes ty $ fromMaybe (internalError "name not found in dictionary") (lookup ident untypedDict)
254+ -- Unify the type with the unification variable we chose for this definition
255+ unifyTypes ty ty'
226โˆ’ return (ident, (TypedValue True val' ty, ty))
256+ return (ident, (TypedValue True val' ty', ty'))
227โˆ’
228โˆ’-- | Check if a value contains a type annotation
229โˆ’isTyped :: (Ident, Expr) -> Either (Ident, Expr) (Ident, (Expr, Type, Bool))
230โˆ’isTyped (name, TypedValue checkType value ty) = Right (name, (value, ty, checkType))
231โˆ’isTyped (name, PositionedValue pos c value) =
232โˆ’ bimap (second (PositionedValue pos c))
233โˆ’ (second (\(e, t, b) -> (PositionedValue pos c e, t, b)))
234โˆ’ (isTyped (name, value))
235โˆ’isTyped (name, value) = Left (name, value)
236
257
237-- | Check the kind of a type, failing if it is not of kind *.
258-- | Check the kind of a type, failing if it is not of kind *.
238โˆ’checkTypeKind ::
259+checkTypeKind
239โˆ’ (MonadError MultipleErrors m) =>
260+ :: MonadError MultipleErrors m
240โˆ’ Type ->
261+ => Type
241โˆ’ Kind ->
262+ -> Kind
242โˆ’ m ()
263+ -> m ()
243checkTypeKind ty kind = guardWith (errorMessage (ExpectedType ty kind)) $ kind == kindType
264checkTypeKind ty kind = guardWith (errorMessage (ExpectedType ty kind)) $ kind == kindType
244
265
245-- | Remove any ForAlls and ConstrainedType constructors in a type by introducing new unknowns
266-- | Remove any ForAlls and ConstrainedType constructors in a type by introducing new unknowns
@@ -247,11 +268,11 @@ checkTypeKind ty kind = guardWith (errorMessage (ExpectedType ty kind)) $ kind =
247--
268--
248-- This is necessary during type checking to avoid unifying a polymorphic type with a
269-- This is necessary during type checking to avoid unifying a polymorphic type with a
249-- unification variable.
270-- unification variable.
250โˆ’instantiatePolyTypeWithUnknowns ::
271+instantiatePolyTypeWithUnknowns
251โˆ’ (MonadState CheckState m, MonadError MultipleErrors m) =>
272+ :: (MonadState CheckState m, MonadError MultipleErrors m)
252โˆ’ Expr ->
273+ => Expr
253โˆ’ Type ->
274+ -> Type
254โˆ’ m (Expr, Type)
275+ -> m (Expr, Type)
255instantiatePolyTypeWithUnknowns val (ForAll ident ty _) = do
276instantiatePolyTypeWithUnknowns val (ForAll ident ty _) = do
256 ty' <- replaceVarWithUnknown ident ty
277 ty' <- replaceVarWithUnknown ident ty
257 instantiatePolyTypeWithUnknowns val ty'
278 instantiatePolyTypeWithUnknowns val ty'
@@ -262,17 +283,17 @@ instantiatePolyTypeWithUnknowns val (ConstrainedType constraints ty) = do
262instantiatePolyTypeWithUnknowns val ty = return (val, ty)
283instantiatePolyTypeWithUnknowns val ty = return (val, ty)
263
284
264-- | Infer a type for a value, rethrowing any error to provide a more useful error message
285-- | Infer a type for a value, rethrowing any error to provide a more useful error message
265โˆ’infer ::
286+infer
266โˆ’ (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
287+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
267โˆ’ Expr ->
288+ => Expr
268โˆ’ m Expr
289+ -> m Expr
269infer val = withErrorMessageHint (ErrorInferringType val) $ infer' val
290infer val = withErrorMessageHint (ErrorInferringType val) $ infer' val
270
291
271-- | Infer a type for a value
292-- | Infer a type for a value
272โˆ’infer' ::
293+infer'
273โˆ’ (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
294+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
274โˆ’ Expr ->
295+ => Expr
275โˆ’ m Expr
296+ -> m Expr
276infer' v@(Literal (NumericLiteral (Left _))) = return $ TypedValue True v tyInt
297infer' v@(Literal (NumericLiteral (Left _))) = return $ TypedValue True v tyInt
277infer' v@(Literal (NumericLiteral (Right _))) = return $ TypedValue True v tyNumber
298infer' v@(Literal (NumericLiteral (Right _))) = return $ TypedValue True v tyNumber
278infer' v@(Literal (StringLiteral _)) = return $ TypedValue True v tyString
299infer' v@(Literal (StringLiteral _)) = return $ TypedValue True v tyString
@@ -289,22 +310,22 @@ infer' (Literal (ArrayLiteral vals)) = do
289infer' (Literal (ObjectLiteral ps)) = do
310infer' (Literal (ObjectLiteral ps)) = do
290 ensureNoDuplicateProperties ps
311 ensureNoDuplicateProperties ps
291 ts <- traverse (infer . snd) ps
312 ts <- traverse (infer . snd) ps
292โˆ’ let fields = zipWith (\name (TypedValue _ _ t) -> (name, t)) (map fst ps) ts
313+ let fields = zipWith (\name (TypedValue _ _ t) -> (Label name, t)) (map fst ps) ts
293 ty = TypeApp tyRecord $ rowFromList (fields, REmpty)
314 ty = TypeApp tyRecord $ rowFromList (fields, REmpty)
294 return $ TypedValue True (Literal (ObjectLiteral (zip (map fst ps) ts))) ty
315 return $ TypedValue True (Literal (ObjectLiteral (zip (map fst ps) ts))) ty
295infer' (ObjectUpdate o ps) = do
316infer' (ObjectUpdate o ps) = do
296 ensureNoDuplicateProperties ps
317 ensureNoDuplicateProperties ps
297 row <- freshType
318 row <- freshType
298 newVals <- zipWith (\(name, _) t -> (name, t)) ps <$> traverse (infer . snd) ps
319 newVals <- zipWith (\(name, _) t -> (name, t)) ps <$> traverse (infer . snd) ps
299โˆ’ let newTys = map (\(name, TypedValue _ _ ty) -> (name, ty)) newVals
320+ let newTys = map (\(name, TypedValue _ _ ty) -> (Label name, ty)) newVals
300โˆ’ oldTys <- zip (map fst ps) <$> replicateM (length ps) freshType
321+ oldTys <- zip (map (Label . fst) ps) <$> replicateM (length ps) freshType
301 let oldTy = TypeApp tyRecord $ rowFromList (oldTys, row)
322 let oldTy = TypeApp tyRecord $ rowFromList (oldTys, row)
302 o' <- TypedValue True <$> check o oldTy <*> pure oldTy
323 o' <- TypedValue True <$> check o oldTy <*> pure oldTy
303 return $ TypedValue True (ObjectUpdate o' newVals) $ TypeApp tyRecord $ rowFromList (newTys, row)
324 return $ TypedValue True (ObjectUpdate o' newVals) $ TypeApp tyRecord $ rowFromList (newTys, row)
304infer' (Accessor prop val) = withErrorMessageHint (ErrorCheckingAccessor val prop) $ do
325infer' (Accessor prop val) = withErrorMessageHint (ErrorCheckingAccessor val prop) $ do
305 field <- freshType
326 field <- freshType
306 rest <- freshType
327 rest <- freshType
307โˆ’ typed <- check val (TypeApp tyRecord (RCons prop field rest))
328+ typed <- check val (TypeApp tyRecord (RCons (Label prop) field rest))
308 return $ TypedValue True (Accessor prop typed) field
329 return $ TypedValue True (Accessor prop typed) field
309infer' (Abs (Left arg) ret) = do
330infer' (Abs (Left arg) ret) = do
310 ty <- freshType
331 ty <- freshType
@@ -369,13 +390,13 @@ infer' (PositionedValue pos c val) = warnAndRethrowWithPositionTC pos $ do
369 return $ TypedValue t (PositionedValue pos c v) ty
390 return $ TypedValue t (PositionedValue pos c v) ty
370infer' v = internalError $ "Invalid argument to infer: " ++ show v
391infer' v = internalError $ "Invalid argument to infer: " ++ show v
371
392
372โˆ’inferLetBinding ::
393+inferLetBinding
373โˆ’ (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
394+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
374โˆ’ [Declaration] ->
395+ => [Declaration]
375โˆ’ [Declaration] ->
396+ -> [Declaration]
376โˆ’ Expr ->
397+ -> Expr
377โˆ’ (Expr -> m Expr) ->
398+ -> (Expr -> m Expr)
378โˆ’ m ([Declaration], Expr)
399+ -> m ([Declaration], Expr)
379inferLetBinding seen [] ret j = (,) seen <$> withBindingGroupVisible (j ret)
400inferLetBinding seen [] ret j = (,) seen <$> withBindingGroupVisible (j ret)
380inferLetBinding seen (ValueDeclaration ident nameKind [] (Right (tv@(TypedValue checkType val ty))) : rest) ret j = do
401inferLetBinding seen (ValueDeclaration ident nameKind [] (Right (tv@(TypedValue checkType val ty))) : rest) ret j = do
381 Just moduleName <- checkCurrentModule <$> get
402 Just moduleName <- checkCurrentModule <$> get
@@ -393,9 +414,9 @@ inferLetBinding seen (ValueDeclaration ident nameKind [] (Right val) : rest) ret
393 bindNames (M.singleton (Qualified Nothing ident) (valTy', nameKind, Defined)) $ inferLetBinding (seen ++ [ValueDeclaration ident nameKind [] (Right val')]) rest ret j
414 bindNames (M.singleton (Qualified Nothing ident) (valTy', nameKind, Defined)) $ inferLetBinding (seen ++ [ValueDeclaration ident nameKind [] (Right val')]) rest ret j
394inferLetBinding seen (BindingGroupDeclaration ds : rest) ret j = do
415inferLetBinding seen (BindingGroupDeclaration ds : rest) ret j = do
395 Just moduleName <- checkCurrentModule <$> get
416 Just moduleName <- checkCurrentModule <$> get
396โˆ’ (untyped, typed, dict, untypedDict) <- typeDictionaryForBindingGroup Nothing (map (\(i, _, v) -> (i, v)) ds)
417+ SplitBindingGroup untyped typed dict <- typeDictionaryForBindingGroup Nothing (map (\(i, _, v) -> (i, v)) ds)
397 ds1' <- parU typed $ \e -> checkTypedBindingGroupElement moduleName e dict
418 ds1' <- parU typed $ \e -> checkTypedBindingGroupElement moduleName e dict
398โˆ’ ds2' <- forM untyped $ \e -> typeForBindingGroupElement e dict untypedDict
419+ ds2' <- forM untyped $ \e -> typeForBindingGroupElement e dict
399 let ds' = [(ident, Private, val') | (ident, (val', _)) <- ds1' ++ ds2']
420 let ds' = [(ident, Private, val') | (ident, (val', _)) <- ds1' ++ ds2']
400 bindNames dict $ do
421 bindNames dict $ do
401 makeBindingGroupVisible
422 makeBindingGroupVisible
@@ -406,11 +427,12 @@ inferLetBinding seen (PositionedDeclaration pos com d : ds) ret j = warnAndRethr
406inferLetBinding _ _ _ _ = internalError "Invalid argument to inferLetBinding"
427inferLetBinding _ _ _ _ = internalError "Invalid argument to inferLetBinding"
407
428
408-- | Infer the types of variables brought into scope by a binder
429-- | Infer the types of variables brought into scope by a binder
409โˆ’inferBinder :: forall m.
430+inferBinder
431+ :: forall m
410โˆ’ (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
432+ . (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
411โˆ’ Type ->
433+ => Type
412โˆ’ Binder ->
434+ -> Binder
413โˆ’ m (M.Map Ident Type)
435+ -> m (M.Map Ident Type)
414inferBinder _ NullBinder = return M.empty
436inferBinder _ NullBinder = return M.empty
415inferBinder val (LiteralBinder (StringLiteral _)) = unifyTypes val tyString >> return M.empty
437inferBinder val (LiteralBinder (StringLiteral _)) = unifyTypes val tyString >> return M.empty
416inferBinder val (LiteralBinder (CharLiteral _)) = unifyTypes val tyChar >> return M.empty
438inferBinder val (LiteralBinder (CharLiteral _)) = unifyTypes val tyChar >> return M.empty
@@ -442,12 +464,12 @@ inferBinder val (LiteralBinder (ObjectLiteral props)) = do
442 unifyTypes val (TypeApp tyRecord row)
464 unifyTypes val (TypeApp tyRecord row)
443 return m1
465 return m1
444 where
466 where
445โˆ’ inferRowProperties :: Type -> Type -> [(Text, Binder)] -> m (M.Map Ident Type)
467+ inferRowProperties :: Type -> Type -> [(PSString, Binder)] -> m (M.Map Ident Type)
446 inferRowProperties nrow row [] = unifyTypes nrow row >> return M.empty
468 inferRowProperties nrow row [] = unifyTypes nrow row >> return M.empty
447 inferRowProperties nrow row ((name, binder):binders) = do
469 inferRowProperties nrow row ((name, binder):binders) = do
448 propTy <- freshType
470 propTy <- freshType
449 m1 <- inferBinder propTy binder
471 m1 <- inferBinder propTy binder
450โˆ’ m2 <- inferRowProperties nrow (RCons name propTy row) binders
472+ m2 <- inferRowProperties nrow (RCons (Label name) propTy row) binders
451 return $ m1 `M.union` m2
473 return $ m1 `M.union` m2
452inferBinder val (LiteralBinder (ArrayLiteral binders)) = do
474inferBinder val (LiteralBinder (ArrayLiteral binders)) = do
453 el <- freshType
475 el <- freshType
@@ -485,11 +507,11 @@ binderRequiresMonotype (PositionedBinder _ _ b) = binderRequiresMonotype b
485binderRequiresMonotype _ = True
507binderRequiresMonotype _ = True
486
508
487-- | Instantiate polytypes only when necessitated by a binder.
509-- | Instantiate polytypes only when necessitated by a binder.
488โˆ’instantiateForBinders ::
510+instantiateForBinders
489โˆ’ (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
511+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
490โˆ’ [Expr] ->
512+ => [Expr]
491โˆ’ [CaseAlternative] ->
513+ -> [CaseAlternative]
492โˆ’ m ([Expr], [Type])
514+ -> m ([Expr], [Type])
493instantiateForBinders vals cas = unzip <$> zipWithM (\val inst -> do
515instantiateForBinders vals cas = unzip <$> zipWithM (\val inst -> do
494 TypedValue _ val' ty <- infer val
516 TypedValue _ val' ty <- infer val
495 if inst
517 if inst
@@ -502,12 +524,12 @@ instantiateForBinders vals cas = unzip <$> zipWithM (\val inst -> do
502-- |
524-- |
503-- Check the types of the return values in a set of binders in a case statement
525-- Check the types of the return values in a set of binders in a case statement
504--
526--
505โˆ’checkBinders ::
527+checkBinders
506โˆ’ (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
528+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
507โˆ’ [Type] ->
529+ => [Type]
508โˆ’ Type ->
530+ -> Type
509โˆ’ [CaseAlternative] ->
531+ -> [CaseAlternative]
510โˆ’ m [CaseAlternative]
532+ -> m [CaseAlternative]
511checkBinders _ _ [] = return []
533checkBinders _ _ [] = return []
512checkBinders nvals ret (CaseAlternative binders result : bs) = do
534checkBinders nvals ret (CaseAlternative binders result : bs) = do
513 guardWith (errorMessage $ OverlappingArgNames Nothing) $
535 guardWith (errorMessage $ OverlappingArgNames Nothing) $
@@ -531,11 +553,11 @@ checkBinders nvals ret (CaseAlternative binders result : bs) = do
531-- |
553-- |
532-- Check the type of a value, rethrowing errors to provide a better error message
554-- Check the type of a value, rethrowing errors to provide a better error message
533--
555--
534โˆ’check ::
556+check
535โˆ’ (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
557+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
536โˆ’ Expr ->
558+ => Expr
537โˆ’ Type ->
559+ -> Type
538โˆ’ m Expr
560+ -> m Expr
539check val ty = withErrorMessageHint (ErrorCheckingType val ty) $ check' val ty
561check val ty = withErrorMessageHint (ErrorCheckingType val ty) $ check' val ty
540
562
541-- |
563-- |
@@ -641,14 +663,14 @@ check' e@(ObjectUpdate obj ps) t@(TypeApp o row) | o == tyRecord = do
641 -- We need to be careful to avoid duplicate labels here.
663 -- We need to be careful to avoid duplicate labels here.
642 -- We check _obj_ against the type _t_ with the types in _ps_ replaced with unknowns.
664 -- We check _obj_ against the type _t_ with the types in _ps_ replaced with unknowns.
643 let (propsToCheck, rest) = rowToList row
665 let (propsToCheck, rest) = rowToList row
644โˆ’ (removedProps, remainingProps) = partition (\(p, _) -> p `elem` map fst ps) propsToCheck
666+ (removedProps, remainingProps) = partition (\(p, _) -> p `elem` map (Label . fst) ps) propsToCheck
645 us <- zip (map fst removedProps) <$> replicateM (length ps) freshType
667 us <- zip (map fst removedProps) <$> replicateM (length ps) freshType
646 obj' <- check obj (TypeApp tyRecord (rowFromList (us ++ remainingProps, rest)))
668 obj' <- check obj (TypeApp tyRecord (rowFromList (us ++ remainingProps, rest)))
647 ps' <- checkProperties e ps row True
669 ps' <- checkProperties e ps row True
648 return $ TypedValue True (ObjectUpdate obj' ps') t
670 return $ TypedValue True (ObjectUpdate obj' ps') t
649check' (Accessor prop val) ty = withErrorMessageHint (ErrorCheckingAccessor val prop) $ do
671check' (Accessor prop val) ty = withErrorMessageHint (ErrorCheckingAccessor val prop) $ do
650 rest <- freshType
672 rest <- freshType
651โˆ’ val' <- check val (TypeApp tyRecord (RCons prop ty rest))
673+ val' <- check val (TypeApp tyRecord (RCons (Label prop) ty rest))
652 return $ TypedValue True (Accessor prop val') ty
674 return $ TypedValue True (Accessor prop val') ty
653check' v@(Constructor c) ty = do
675check' v@(Constructor c) ty = do
654 env <- getEnv
676 env <- getEnv
@@ -678,13 +700,13 @@ check' val ty = do
678--
700--
679-- The @lax@ parameter controls whether or not every record member has to be provided. For object updates, this is not the case.
701-- The @lax@ parameter controls whether or not every record member has to be provided. For object updates, this is not the case.
680--
702--
681โˆ’checkProperties ::
703+checkProperties
682โˆ’ (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
704+ :: (MonadSupply m, MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
683โˆ’ Expr ->
705+ => Expr
684โˆ’ [(Text, Expr)] ->
706+ -> [(PSString, Expr)]
685โˆ’ Type ->
707+ -> Type
686โˆ’ Bool ->
708+ -> Bool
687โˆ’ m [(Text, Expr)]
709+ -> m [(PSString, Expr)]
688checkProperties expr ps row lax = let (ts, r') = rowToList row in go ps ts r' where
710checkProperties expr ps row lax = let (ts, r') = rowToList row in go ps ts r' where
689 go [] [] REmpty = return []
711 go [] [] REmpty = return []
690 go [] [] u@(TUnknown _)
712 go [] [] u@(TUnknown _)
@@ -694,18 +716,18 @@ checkProperties expr ps row lax = let (ts, r') = rowToList row in go ps ts r' wh
694 go [] [] Skolem{} | lax = return []
716 go [] [] Skolem{} | lax = return []
695 go [] ((p, _): _) _ | lax = return []
717 go [] ((p, _): _) _ | lax = return []
696 | otherwise = throwError . errorMessage $ PropertyIsMissing p
718 | otherwise = throwError . errorMessage $ PropertyIsMissing p
697โˆ’ go ((p,_):_) [] REmpty = throwError . errorMessage $ AdditionalProperty p
719+ go ((p,_):_) [] REmpty = throwError . errorMessage $ AdditionalProperty $ Label p
698 go ((p,v):ps') ts r =
720 go ((p,v):ps') ts r =
699โˆ’ case lookup p ts of
721+ case lookup (Label p) ts of
700 Nothing -> do
722 Nothing -> do
701 v'@(TypedValue _ _ ty) <- infer v
723 v'@(TypedValue _ _ ty) <- infer v
702 rest <- freshType
724 rest <- freshType
703โˆ’ unifyTypes r (RCons p ty rest)
725+ unifyTypes r (RCons (Label p) ty rest)
704 ps'' <- go ps' ts rest
726 ps'' <- go ps' ts rest
705 return $ (p, v') : ps''
727 return $ (p, v') : ps''
706 Just ty -> do
728 Just ty -> do
707 v' <- check v ty
729 v' <- check v ty
708โˆ’ ps'' <- go ps' (delete (p, ty) ts) r
730+ ps'' <- go ps' (delete (Label p, ty) ts) r
709 return $ (p, v') : ps''
731 return $ (p, v') : ps''
710 go _ _ _ = throwError . errorMessage $ ExprDoesNotHaveType expr (TypeApp tyRecord row)
732 go _ _ _ = throwError . errorMessage $ ExprDoesNotHaveType expr (TypeApp tyRecord row)
711
733
@@ -771,9 +793,9 @@ checkFunctionApplication' fn u arg = do
771-- |
793-- |
772-- Ensure a set of property names and value does not contain duplicate labels
794-- Ensure a set of property names and value does not contain duplicate labels
773--
795--
774โˆ’ensureNoDuplicateProperties :: (MonadError MultipleErrors m) => [(Text, Expr)] -> m ()
796+ensureNoDuplicateProperties :: (MonadError MultipleErrors m) => [(PSString, Expr)] -> m ()
775ensureNoDuplicateProperties ps =
797ensureNoDuplicateProperties ps =
776 let ls = map fst ps in
798 let ls = map fst ps in
777 case ls \\ nub ls of
799 case ls \\ nub ls of
778โˆ’ l : _ -> throwError . errorMessage $ DuplicateLabel l Nothing
800+ l : _ -> throwError . errorMessage $ DuplicateLabel (Label l) Nothing
779 _ -> return ()
801 _ -> return ()
src/Language/PureScript/TypeChecker/Unify.hs+2โˆ’1
@@ -31,6 +31,7 @@ import Language.PureScript.Crash
31import Language.PureScript.Errors
31import Language.PureScript.Errors
32import Language.PureScript.TypeChecker.Monad
32import Language.PureScript.TypeChecker.Monad
33import Language.PureScript.TypeChecker.Skolems
33import Language.PureScript.TypeChecker.Skolems
34+import Language.PureScript.Label (Label(..))
34import Language.PureScript.Types
35import Language.PureScript.Types
35
36
36-- | Generate a fresh type variable
37-- | Generate a fresh type variable
@@ -139,7 +140,7 @@ unifyRows r1 r2 =
139 forM_ int (uncurry unifyTypes)
140 forM_ int (uncurry unifyTypes)
140 unifyRows' sd1 r1' sd2 r2'
141 unifyRows' sd1 r1' sd2 r2'
141 where
142 where
142โˆ’ unifyRows' :: [(Text, Type)] -> Type -> [(Text, Type)] -> Type -> m ()
143+ unifyRows' :: [(Label, Type)] -> Type -> [(Label, Type)] -> Type -> m ()
143 unifyRows' [] (TUnknown u) sd r = solveType u (rowFromList (sd, r))
144 unifyRows' [] (TUnknown u) sd r = solveType u (rowFromList (sd, r))
144 unifyRows' sd r [] (TUnknown u) = solveType u (rowFromList (sd, r))
145 unifyRows' sd r [] (TUnknown u) = solveType u (rowFromList (sd, r))
145 unifyRows' sd1 (TUnknown u1) sd2 (TUnknown u2) = do
146 unifyRows' sd1 (TUnknown u1) sd2 (TUnknown u2) = do
src/Language/PureScript/Types.hs+6โˆ’4
@@ -20,6 +20,8 @@ import qualified Data.Text as T
20import Language.PureScript.AST.SourcePos
20import Language.PureScript.AST.SourcePos
21import Language.PureScript.Kinds
21import Language.PureScript.Kinds
22import Language.PureScript.Names
22import Language.PureScript.Names
23+import Language.PureScript.Label (Label)
24+import Language.PureScript.PSString (PSString)
23
25
24-- |
26-- |
25-- An identifier for the scope of a skolem variable
27-- An identifier for the scope of a skolem variable
@@ -36,7 +38,7 @@ data Type
36 -- | A named type variable
38 -- | A named type variable
37 | TypeVar Text
39 | TypeVar Text
38 -- | A type-level string
40 -- | A type-level string
39โˆ’ | TypeLevelString Text
41+ | TypeLevelString PSString
40 -- | A type wildcard, as would appear in a partial type synonym
42 -- | A type wildcard, as would appear in a partial type synonym
41 | TypeWildcard SourceSpan
43 | TypeWildcard SourceSpan
42 -- | A type constructor
44 -- | A type constructor
@@ -55,7 +57,7 @@ data Type
55 -- | An empty row
57 -- | An empty row
56 | REmpty
58 | REmpty
57 -- | A non-empty row
59 -- | A non-empty row
58โˆ’ | RCons Text Type Type
60+ | RCons Label Type Type
59 -- | A type with a kind annotation
61 -- | A type with a kind annotation
60 | KindedType Type Kind
62 | KindedType Type Kind
61 -- | A placeholder used in pretty printing
63 -- | A placeholder used in pretty printing
@@ -108,7 +110,7 @@ $(A.deriveJSON A.defaultOptions ''ConstraintData)
108-- |
110-- |
109-- Convert a row to a list of pairs of labels and types
111-- Convert a row to a list of pairs of labels and types
110--
112--
111โˆ’rowToList :: Type -> ([(Text, Type)], Type)
113+rowToList :: Type -> ([(Label, Type)], Type)
112rowToList (RCons name ty row) = let (tys, rest) = rowToList row
114rowToList (RCons name ty row) = let (tys, rest) = rowToList row
113 in ((name, ty):tys, rest)
115 in ((name, ty):tys, rest)
114rowToList r = ([], r)
116rowToList r = ([], r)
@@ -116,7 +118,7 @@ rowToList r = ([], r)
116-- |
118-- |
117-- Convert a list of labels and types to a row
119-- Convert a list of labels and types to a row
118--
120--
119โˆ’rowFromList :: ([(Text, Type)], Type) -> Type
121+rowFromList :: ([(Label, Type)], Type) -> Type
120rowFromList ([], r) = r
122rowFromList ([], r) = r
121rowFromList ((name, t):ts, r) = RCons name t (rowFromList (ts, r))
123rowFromList ((name, t):ts, r) = RCons name t (rowFromList (ts, r))
122
124
tests/Language/PureScript/Ide/Integration.hs+14โˆ’7
@@ -50,12 +50,14 @@ import Data.Maybe (fromJust)
50
50
51import Data.Aeson
51import Data.Aeson
52import Data.Aeson.Types
52import Data.Aeson.Types
53โˆ’import qualified Data.Text as T
53+import qualified Data.Text.Encoding as T
54+import qualified Data.ByteString.Char8 as BS8
55+import qualified Data.ByteString.Lazy.Char8 as BSL8
54import qualified Data.Vector as V
56import qualified Data.Vector as V
55โˆ’import Language.PureScript.Ide.Util
56import qualified Language.PureScript as P
57import qualified Language.PureScript as P
57import System.Directory
58import System.Directory
58import System.FilePath
59import System.FilePath
60+import System.IO
59import System.IO.Error (mkIOError, userErrorType)
61import System.IO.Error (mkIOError, userErrorType)
60import System.Process
62import System.Process
61
63
@@ -124,11 +126,16 @@ fileGlob = "\"src/**/*.purs\""
124-- Integration Testing API
126-- Integration Testing API
125
127
126sendCommand :: Value -> IO Text
128sendCommand :: Value -> IO Text
127โˆ’sendCommand v = toS <$> readCreateProcess
129+sendCommand v = do
130+ (Just hin, Just hout, _, _) <-
128โˆ’ ((shell "psc-ide-client") { std_out=CreatePipe
131+ createProcess ((proc "psc-ide-client" []) {std_in=CreatePipe, std_out=CreatePipe})
129โˆ’ , std_err=CreatePipe
132+
130โˆ’ })
133+ hSetEncoding hin utf8
131โˆ’ (T.unpack (encodeT v))
134+ hSetEncoding hout utf8
135+
136+ BS8.hPutStrLn hin (BSL8.toStrict (encode v))
137+ hFlush hin
138+ T.decodeUtf8 <$> BS8.hGetLine hout
132
139
133quitServer :: IO ()
140quitServer :: IO ()
134quitServer = do
141quitServer = do
tests/Language/PureScript/Ide/MatcherSpec.hs+1โˆ’1
@@ -46,4 +46,4 @@ spec = do
46 it "matches on equality" $ do
46 it "matches on equality" $ do
47 -- ignore any position information
47 -- ignore any position information
48 (m, i, t, _) : _ <- getFlexCompletions "const"
48 (m, i, t, _) : _ <- getFlexCompletions "const"
49โˆ’ (m, i, t) `shouldBe` ("MatcherSpec", "const", "forall a b. a -> b -> a")
49+ (m, i, t) `shouldBe` ("MatcherSpec", "const", "โˆ€ a b. a โ†’ b โ†’ a")
tests/TestDocs.hs+7โˆ’4
@@ -9,14 +9,16 @@ import Prelude ()
9import Prelude.Compat
9import Prelude.Compat
10
10
11import Control.Arrow (first)
11import Control.Arrow (first)
12+import Control.Monad.IO.Class (liftIO)
12
13
13โˆ’import Data.Version (Version(..))
14โˆ’import Data.Monoid
15โˆ’import Data.Maybe (fromMaybe)
16โˆ’import Data.List ((\\))
17import Data.Foldable
14import Data.Foldable
15+import Data.List ((\\))
16+import Data.Maybe (fromMaybe)
17+import Data.Monoid
18import Data.Text (Text)
18import Data.Text (Text)
19import qualified Data.Text as T
19import qualified Data.Text as T
20+import Data.Time.Clock (getCurrentTime)
21+import Data.Version (Version(..))
20import System.Exit
22import System.Exit
21
23
22import qualified Language.PureScript as P
24import qualified Language.PureScript as P
@@ -32,6 +34,7 @@ import TestUtils
32publishOpts :: Publish.PublishOptions
34publishOpts :: Publish.PublishOptions
33publishOpts = Publish.defaultPublishOptions
35publishOpts = Publish.defaultPublishOptions
34 { Publish.publishGetVersion = return testVersion
36 { Publish.publishGetVersion = return testVersion
37+ , Publish.publishGetTagTime = const (liftIO getCurrentTime)
35 , Publish.publishWorkingTreeDirty = return ()
38 , Publish.publishWorkingTreeDirty = return ()
36 }
39 }
37 where testVersion = ("v999.0.0", Version [999,0,0] [])
40 where testVersion = ("v999.0.0", Version [999,0,0] [])
tests/TestPscPublish.hs+3
@@ -4,8 +4,10 @@
4
4
5module TestPscPublish where
5module TestPscPublish where
6
6
7+import Control.Monad.IO.Class (liftIO)
7import System.Exit (exitFailure)
8import System.Exit (exitFailure)
8import Data.ByteString.Lazy (ByteString)
9import Data.ByteString.Lazy (ByteString)
10+import Data.Time.Clock (getCurrentTime)
9import qualified Data.Aeson as A
11import qualified Data.Aeson as A
10import Data.Version
12import Data.Version
11
13
@@ -38,6 +40,7 @@ roundTrip pkg =
38testRunOptions :: PublishOptions
40testRunOptions :: PublishOptions
39testRunOptions = defaultPublishOptions
41testRunOptions = defaultPublishOptions
40 { publishGetVersion = return testVersion
42 { publishGetVersion = return testVersion
43+ , publishGetTagTime = const (liftIO getCurrentTime)
41 , publishWorkingTreeDirty = return ()
44 , publishWorkingTreeDirty = return ()
42 }
45 }
43 where testVersion = ("v999.0.0", Version [999,0,0] [])
46 where testVersion = ("v999.0.0", Version [999,0,0] [])
tests/TestPsci.hs+1โˆ’1
@@ -120,7 +120,7 @@ getPSCiState :: IO PSCiState
120getPSCiState = do
120getPSCiState = do
121 cwd <- getCurrentDirectory
121 cwd <- getCurrentDirectory
122 let supportDir = cwd </> "tests" </> "support" </> "bower_components"
122 let supportDir = cwd </> "tests" </> "support" </> "bower_components"
123โˆ’ let supportFiles ext = Glob.globDir1 (Glob.compile ("purescript-*/**/*." ++ ext)) supportDir
123+ let supportFiles ext = Glob.globDir1 (Glob.compile ("purescript-*/src/**/*." ++ ext)) supportDir
124 pursFiles <- supportFiles "purs"
124 pursFiles <- supportFiles "purs"
125
125
126 modulesOrFirstError <- loadAllModules pursFiles
126 modulesOrFirstError <- loadAllModules pursFiles
tests/TestUtils.hs+19โˆ’1
@@ -69,11 +69,15 @@ supportModules =
69 , "Control.Monad.Eff.Class"
69 , "Control.Monad.Eff.Class"
70 , "Control.Monad.Eff.Console"
70 , "Control.Monad.Eff.Console"
71 , "Control.Monad.Eff.Unsafe"
71 , "Control.Monad.Eff.Unsafe"
72+ , "Control.Monad.Rec.Class"
72 , "Control.Monad.ST"
73 , "Control.Monad.ST"
73 , "Control.MonadPlus"
74 , "Control.MonadPlus"
74 , "Control.MonadZero"
75 , "Control.MonadZero"
75 , "Control.Plus"
76 , "Control.Plus"
76 , "Control.Semigroupoid"
77 , "Control.Semigroupoid"
78+ , "Data.Array"
79+ , "Data.Array.Partial"
80+ , "Data.Array.ST"
77 , "Data.Bifoldable"
81 , "Data.Bifoldable"
78 , "Data.Bifunctor"
82 , "Data.Bifunctor"
79 , "Data.Bifunctor.Clown"
83 , "Data.Bifunctor.Clown"
@@ -86,7 +90,10 @@ supportModules =
86 , "Data.Boolean"
90 , "Data.Boolean"
87 , "Data.BooleanAlgebra"
91 , "Data.BooleanAlgebra"
88 , "Data.Bounded"
92 , "Data.Bounded"
93+ , "Data.Char"
89 , "Data.CommutativeRing"
94 , "Data.CommutativeRing"
95+ , "Data.Either"
96+ , "Data.Either.Nested"
90 , "Data.Eq"
97 , "Data.Eq"
91 , "Data.EuclideanRing"
98 , "Data.EuclideanRing"
92 , "Data.Field"
99 , "Data.Field"
@@ -95,6 +102,7 @@ supportModules =
95 , "Data.Function.Uncurried"
102 , "Data.Function.Uncurried"
96 , "Data.Functor"
103 , "Data.Functor"
97 , "Data.Functor.Invariant"
104 , "Data.Functor.Invariant"
105+ , "Data.Generic"
98 , "Data.Generic.Rep"
106 , "Data.Generic.Rep"
99 , "Data.Generic.Rep.Eq"
107 , "Data.Generic.Rep.Eq"
100 , "Data.Generic.Rep.Monoid"
108 , "Data.Generic.Rep.Monoid"
@@ -102,6 +110,7 @@ supportModules =
102 , "Data.Generic.Rep.Semigroup"
110 , "Data.Generic.Rep.Semigroup"
103 , "Data.Generic.Rep.Show"
111 , "Data.Generic.Rep.Show"
104 , "Data.HeytingAlgebra"
112 , "Data.HeytingAlgebra"
113+ , "Data.Identity"
105 , "Data.Maybe"
114 , "Data.Maybe"
106 , "Data.Maybe.First"
115 , "Data.Maybe.First"
107 , "Data.Maybe.Last"
116 , "Data.Maybe.Last"
@@ -115,6 +124,7 @@ supportModules =
115 , "Data.Monoid.Multiplicative"
124 , "Data.Monoid.Multiplicative"
116 , "Data.NaturalTransformation"
125 , "Data.NaturalTransformation"
117 , "Data.Newtype"
126 , "Data.Newtype"
127+ , "Data.NonEmpty"
118 , "Data.Ord"
128 , "Data.Ord"
119 , "Data.Ord.Unsafe"
129 , "Data.Ord.Unsafe"
120 , "Data.Ordering"
130 , "Data.Ordering"
@@ -122,15 +132,23 @@ supportModules =
122 , "Data.Semigroup"
132 , "Data.Semigroup"
123 , "Data.Semiring"
133 , "Data.Semiring"
124 , "Data.Show"
134 , "Data.Show"
135+ , "Data.String"
136+ , "Data.String.CaseInsensitive"
137+ , "Data.String.Regex"
138+ , "Data.String.Regex.Flags"
139+ , "Data.String.Regex.Unsafe"
140+ , "Data.String.Unsafe"
125 , "Data.Symbol"
141 , "Data.Symbol"
126 , "Data.Traversable"
142 , "Data.Traversable"
143+ , "Data.Tuple"
144+ , "Data.Tuple.Nested"
145+ , "Data.Unfoldable"
127 , "Data.Unit"
146 , "Data.Unit"
128 , "Data.Void"
147 , "Data.Void"
129 , "Partial"
148 , "Partial"
130 , "Partial.Unsafe"
149 , "Partial.Unsafe"
131 , "Prelude"
150 , "Prelude"
132 , "Test.Assert"
151 , "Test.Assert"
133โˆ’ , "Test.Main"
134 , "Type.Data.Ordering"
152 , "Type.Data.Ordering"
135 , "Type.Data.Symbol"
153 , "Type.Data.Symbol"
136 , "Type.Equality"
154 , "Type.Equality"
tests/support/bower.json+1
@@ -9,6 +9,7 @@
9 "purescript-st": "2.0.0",
9 "purescript-st": "2.0.0",
10 "purescript-partial": "1.1.2",
10 "purescript-partial": "1.1.2",
11 "purescript-newtype": "1.1.0",
11 "purescript-newtype": "1.1.0",
12+ "purescript-generics": "3.3.0",
12 "purescript-generics-rep": "4.0.0",
13 "purescript-generics-rep": "4.0.0",
13 "purescript-symbols": "^2.0.0",
14 "purescript-symbols": "^2.0.0",
14 "purescript-typelevel-prelude": "https://github.com/purescript/purescript-typelevel-prelude.git#29a7123a0c29c85d4b923fcf4a7df8e45ebf9bac",
15 "purescript-typelevel-prelude": "https://github.com/purescript/purescript-typelevel-prelude.git#29a7123a0c29c85d4b923fcf4a7df8e45ebf9bac",