git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge remote-tracking branch 'upstream/master' into pure11-0.9
7afff2eAndy Arvanitis
.travis.yml+11−5
@@ -12,20 +12,26 @@ matrix:
12 os: linux
12 os: linux
13 dist: trusty
13 dist: trusty
14 sudo: required
14 sudo: required
15− env: BUILD_TYPE=normal COVERAGE=true DEPLOY=true
15+ env: BUILD_TYPE=normal DEPLOY=true
16+
17+ # - compiler: cc-linux-nightly-normal
18+ # os: linux
19+ # dist: trusty
20+ # sudo: required
21+ # env: BUILD_TYPE=normal STACKAGE_NIGHTLY=true
22+ # allow_failures: true
16
23
17− - compiler: cc-linux-nightly-normal
24+ - compiler: cc-linux-ghc8.0-normal
18 os: linux
25 os: linux
19 dist: trusty
26 dist: trusty
20 sudo: required
27 sudo: required
21− env: BUILD_TYPE=normal STACKAGE_NIGHTLY=true
28+ env: BUILD_TYPE=normal STACK_YAML=stack-ghc-8.0.yaml
22− allow_failures: true
23
29
24 - compiler: cc-linux-lts-sdist
30 - compiler: cc-linux-lts-sdist
25 os: linux
31 os: linux
26 dist: trusty
32 dist: trusty
27 sudo: required
33 sudo: required
28− env: BUILD_TYPE=sdist
34+ env: BUILD_TYPE=sdist COVERAGE=true
29
35
30 - compiler: cc-linux-lts-haddock
36 - compiler: cc-linux-lts-haddock
31 os: linux
37 os: linux
CONTRIBUTORS.md+2
@@ -71,6 +71,8 @@ This file lists the contributors to the PureScript compiler project, and the ter
71- [@zudov](https://github.com/zudov) (Konstantin Zudov) My existing contributions and all future contributions until further notice are Copyright Konstantin Zudov, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
71- [@zudov](https://github.com/zudov) (Konstantin Zudov) My existing contributions and all future contributions until further notice are Copyright Konstantin Zudov, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
72- [@LiamGoodacre](https://github.com/LiamGoodacre) (Liam Goodacre) My existing contributions and all future contributions until further notice are Copyright Liam Goodacre, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
72- [@LiamGoodacre](https://github.com/LiamGoodacre) (Liam Goodacre) My existing contributions and all future contributions until further notice are Copyright Liam Goodacre, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
73- [@bsermons](https://github.com/bsermons) (Brian Sermons) My existing contributions and all future contributions until further notice are Copyright Brian Sermons, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
73- [@bsermons](https://github.com/bsermons) (Brian Sermons) My existing contributions and all future contributions until further notice are Copyright Brian Sermons, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
74+- [@bmjames](https://github.com/bmjames) (Ben James) My existing contributions and all future contributions until further notice are Copyright Ben James, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
75+- - [@felixSchl](https://github.com/felixSchl) (Felix Schlitter) My existing contributions and all future contributions until further notice are Copyright Felix Schlitter, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
74
76
75### Companies
77### Companies
76
78
LICENSE+270−10
@@ -46,6 +46,7 @@ PureScript uses the following Haskell library packages. Their license files foll
46 bytestring-builder
46 bytestring-builder
47 case-insensitive
47 case-insensitive
48 cereal
48 cereal
49+ clock
49 conduit
50 conduit
50 conduit-extra
51 conduit-extra
51 connection
52 connection
@@ -56,8 +57,10 @@ PureScript uses the following Haskell library packages. Their license files foll
56 deepseq
57 deepseq
57 directory
58 directory
58 dlist
59 dlist
60+ easy-file
59 edit-distance
61 edit-distance
60 exceptions
62 exceptions
63+ fail
61 fast-logger
64 fast-logger
62 filepath
65 filepath
63 fsnotify
66 fsnotify
@@ -82,6 +85,7 @@ PureScript uses the following Haskell library packages. Their license files foll
82 network
85 network
83 network-uri
86 network-uri
84 old-locale
87 old-locale
88+ old-time
85 optparse-applicative
89 optparse-applicative
86 parallel
90 parallel
87 parsec
91 parsec
@@ -91,6 +95,7 @@ PureScript uses the following Haskell library packages. Their license files foll
91 pipes-http
95 pipes-http
92 primitive
96 primitive
93 process
97 process
98+ protolude
94 random
99 random
95 regex-base
100 regex-base
96 regex-tdfa
101 regex-tdfa
@@ -105,6 +110,7 @@ PureScript uses the following Haskell library packages. Their license files foll
105 stm
110 stm
106 stm-chans
111 stm-chans
107 streaming-commons
112 streaming-commons
113+ string-conv
108 syb
114 syb
109 tagged
115 tagged
110 template-haskell
116 template-haskell
@@ -117,6 +123,7 @@ PureScript uses the following Haskell library packages. Their license files foll
117 transformers-compat
123 transformers-compat
118 unix
124 unix
119 unix-compat
125 unix-compat
126+ unix-time
120 unordered-containers
127 unordered-containers
121 utf8-string
128 utf8-string
122 vector
129 vector
@@ -955,6 +962,41 @@ cereal LICENSE file:
955 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
962 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
956 POSSIBILITY OF SUCH DAMAGE.
963 POSSIBILITY OF SUCH DAMAGE.
957
964
965+clock LICENSE file:
966+
967+ Copyright (c) 2009-2012, Cetin Sert
968+ Copyright (c) 2010, Eugene Kirpichov
969+
970+ All rights reserved.
971+
972+ Redistribution and use in source and binary forms, with or without
973+ modification, are permitted provided that the following conditions are
974+ met:
975+
976+ * Redistributions of source code must retain the above copyright
977+ notice, this list of conditions and the following disclaimer.
978+
979+ * Redistributions in binary form must reproduce the above
980+ copyright notice, this list of conditions and the following
981+ disclaimer in the documentation and/or other materials provided
982+ with the distribution.
983+
984+ * The names of contributors may not be used to endorse or promote
985+ products derived from this software without specific prior
986+ written permission.
987+
988+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
989+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
990+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
991+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
992+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
993+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
994+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
995+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
996+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
997+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
998+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
999+
958conduit LICENSE file:
1000conduit LICENSE file:
959
1001
960 Copyright (c) 2012 Michael Snoyman, http://www.yesodweb.com/
1002 Copyright (c) 2012 Michael Snoyman, http://www.yesodweb.com/
@@ -1142,16 +1184,16 @@ data-default-class LICENSE file:
1142 may be used to endorse or promote products derived from this software
1184 may be used to endorse or promote products derived from this software
1143 without specific prior written permission.
1185 without specific prior written permission.
1144
1186
1145− THIS SOFTWARE IS PROVIDED BY LUKAS MAI AND CONTRIBUTORS "AS IS" AND ANY
1187+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1146− EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1188+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1147 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1189 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1148− DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
1190+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
1149− DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1191+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1150− (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1192+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1151− LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
1193+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1152− ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1194+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
1153− (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1195+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1154− SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1196+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1155
1197
1156deepseq LICENSE file:
1198deepseq LICENSE file:
1157
1199
@@ -1295,6 +1337,38 @@ dlist LICENSE file:
1295 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1337 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1296 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1338 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1297
1339
1340+easy-file LICENSE file:
1341+
1342+ Copyright (c) 2009, IIJ Innovation Institute Inc.
1343+ All rights reserved.
1344+
1345+ Redistribution and use in source and binary forms, with or without
1346+ modification, are permitted provided that the following conditions
1347+ are met:
1348+
1349+ * Redistributions of source code must retain the above copyright
1350+ notice, this list of conditions and the following disclaimer.
1351+ * Redistributions in binary form must reproduce the above copyright
1352+ notice, this list of conditions and the following disclaimer in
1353+ the documentation and/or other materials provided with the
1354+ distribution.
1355+ * Neither the name of the copyright holders nor the names of its
1356+ contributors may be used to endorse or promote products derived
1357+ from this software without specific prior written permission.
1358+
1359+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1360+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1361+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
1362+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
1363+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
1364+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
1365+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1366+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1367+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1368+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
1369+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1370+ POSSIBILITY OF SUCH DAMAGE.
1371+
1298edit-distance LICENSE file:
1372edit-distance LICENSE file:
1299
1373
1300 Copyright (c) 2008-2013 Maximilian Bolingbroke
1374 Copyright (c) 2008-2013 Maximilian Bolingbroke
@@ -1354,6 +1428,39 @@ exceptions LICENSE file:
1354 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1428 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1355 POSSIBILITY OF SUCH DAMAGE.
1429 POSSIBILITY OF SUCH DAMAGE.
1356
1430
1431+fail LICENSE file:
1432+
1433+ Copyright (c) 2015, David Luposchainsky & Herbert Valerio Riedel
1434+
1435+ All rights reserved.
1436+
1437+ Redistribution and use in source and binary forms, with or without
1438+ modification, are permitted provided that the following conditions are met:
1439+
1440+ * Redistributions of source code must retain the above copyright
1441+ notice, this list of conditions and the following disclaimer.
1442+
1443+ * Redistributions in binary form must reproduce the above
1444+ copyright notice, this list of conditions and the following
1445+ disclaimer in the documentation and/or other materials provided
1446+ with the distribution.
1447+
1448+ * Neither the name of Herbert Valerio Riedel nor the names of other
1449+ contributors may be used to endorse or promote products derived
1450+ from this software without specific prior written permission.
1451+
1452+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1453+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1454+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1455+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1456+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1457+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1458+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1459+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1460+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1461+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1462+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1463+
1357fast-logger LICENSE file:
1464fast-logger LICENSE file:
1358
1465
1359 Copyright (c) 2009, IIJ Innovation Institute Inc.
1466 Copyright (c) 2009, IIJ Innovation Institute Inc.
@@ -2122,6 +2229,72 @@ old-locale LICENSE file:
2122
2229
2123 -----------------------------------------------------------------------------
2230 -----------------------------------------------------------------------------
2124
2231
2232+old-time LICENSE file:
2233+
2234+ This library (libraries/base) is derived from code from two
2235+ sources:
2236+
2237+ * Code from the GHC project which is largely (c) The University of
2238+ Glasgow, and distributable under a BSD-style license (see below),
2239+
2240+ * Code from the Haskell 98 Report which is (c) Simon Peyton Jones
2241+ and freely redistributable (but see the full license for
2242+ restrictions).
2243+
2244+ The full text of these licenses is reproduced below. Both of the
2245+ licenses are BSD-style or compatible.
2246+
2247+ -----------------------------------------------------------------------------
2248+
2249+ The Glasgow Haskell Compiler License
2250+
2251+ Copyright 2004, The University Court of the University of Glasgow.
2252+ All rights reserved.
2253+
2254+ Redistribution and use in source and binary forms, with or without
2255+ modification, are permitted provided that the following conditions are met:
2256+
2257+ - Redistributions of source code must retain the above copyright notice,
2258+ this list of conditions and the following disclaimer.
2259+
2260+ - Redistributions in binary form must reproduce the above copyright notice,
2261+ this list of conditions and the following disclaimer in the documentation
2262+ and/or other materials provided with the distribution.
2263+
2264+ - Neither name of the University nor the names of its contributors may be
2265+ used to endorse or promote products derived from this software without
2266+ specific prior written permission.
2267+
2268+ THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF
2269+ GLASGOW AND THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
2270+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
2271+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2272+ UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS BE LIABLE
2273+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2274+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2275+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2276+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2277+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2278+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2279+ DAMAGE.
2280+
2281+ -----------------------------------------------------------------------------
2282+
2283+ Code derived from the document "Report on the Programming Language
2284+ Haskell 98", is distributed under the following license:
2285+
2286+ Copyright (c) 2002 Simon Peyton Jones
2287+
2288+ The authors intend this Report to belong to the entire Haskell
2289+ community, and so we grant permission to copy and distribute it for
2290+ any purpose, provided that it is reproduced in its entirety,
2291+ including this Notice. Modified versions of this Report may also be
2292+ copied and distributed for any purpose, provided that the modified
2293+ version is clearly presented as such, and that it does not claim to
2294+ be a definition of the Haskell 98 Language.
2295+
2296+ -----------------------------------------------------------------------------
2297+
2125optparse-applicative LICENSE file:
2298optparse-applicative LICENSE file:
2126
2299
2127 Copyright (c) 2012, Paolo Capriotti
2300 Copyright (c) 2012, Paolo Capriotti
@@ -2276,7 +2449,7 @@ pem LICENSE file:
2276
2449
2277pipes LICENSE file:
2450pipes LICENSE file:
2278
2451
2279− Copyright (c) 2012-2014 Gabriel Gonzalez
2452+ Copyright (c) 2012-2016 Gabriel Gonzalez
2280 All rights reserved.
2453 All rights reserved.
2281
2454
2282 Redistribution and use in source and binary forms, with or without modification,
2455 Redistribution and use in source and binary forms, with or without modification,
@@ -2427,6 +2600,28 @@ process LICENSE file:
2427
2600
2428 -----------------------------------------------------------------------------
2601 -----------------------------------------------------------------------------
2429
2602
2603+protolude LICENSE file:
2604+
2605+ Copyright (c) 2016, Stephen Diehl
2606+
2607+ Permission is hereby granted, free of charge, to any person obtaining a copy
2608+ of this software and associated documentation files (the "Software"), to
2609+ deal in the Software without restriction, including without limitation the
2610+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
2611+ sell copies of the Software, and to permit persons to whom the Software is
2612+ furnished to do so, subject to the following conditions:
2613+
2614+ The above copyright notice and this permission notice shall be included in
2615+ all copies or substantial portions of the Software.
2616+
2617+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2618+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2619+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2620+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2621+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2622+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2623+ IN THE SOFTWARE.
2624+
2430random LICENSE file:
2625random LICENSE file:
2431
2626
2432 This library (libraries/base) is derived from code from two
2627 This library (libraries/base) is derived from code from two
@@ -2873,6 +3068,39 @@ streaming-commons LICENSE file:
2873 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3068 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2874 SOFTWARE.
3069 SOFTWARE.
2875
3070
3071+string-conv LICENSE file:
3072+
3073+ Copyright (c) 2012, Ozgun Ataman
3074+
3075+ All rights reserved.
3076+
3077+ Redistribution and use in source and binary forms, with or without
3078+ modification, are permitted provided that the following conditions are met:
3079+
3080+ * Redistributions of source code must retain the above copyright
3081+ notice, this list of conditions and the following disclaimer.
3082+
3083+ * Redistributions in binary form must reproduce the above
3084+ copyright notice, this list of conditions and the following
3085+ disclaimer in the documentation and/or other materials provided
3086+ with the distribution.
3087+
3088+ * Neither the name of Ozgun Ataman nor the names of other
3089+ contributors may be used to endorse or promote products derived
3090+ from this software without specific prior written permission.
3091+
3092+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3093+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3094+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3095+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3096+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3097+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3098+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3099+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3100+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3101+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3102+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3103+
2876syb LICENSE file:
3104syb LICENSE file:
2877
3105
2878 This library (libraries/syb) is derived from code from several
3106 This library (libraries/syb) is derived from code from several
@@ -3289,6 +3517,38 @@ unix-compat LICENSE file:
3289 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3517 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3290 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3518 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3291
3519
3520+unix-time LICENSE file:
3521+
3522+ Copyright (c) 2009, IIJ Innovation Institute Inc.
3523+ All rights reserved.
3524+
3525+ Redistribution and use in source and binary forms, with or without
3526+ modification, are permitted provided that the following conditions
3527+ are met:
3528+
3529+ * Redistributions of source code must retain the above copyright
3530+ notice, this list of conditions and the following disclaimer.
3531+ * Redistributions in binary form must reproduce the above copyright
3532+ notice, this list of conditions and the following disclaimer in
3533+ the documentation and/or other materials provided with the
3534+ distribution.
3535+ * Neither the name of the copyright holders nor the names of its
3536+ contributors may be used to endorse or promote products derived
3537+ from this software without specific prior written permission.
3538+
3539+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3540+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3541+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
3542+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
3543+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
3544+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
3545+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3546+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
3547+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3548+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3549+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3550+ POSSIBILITY OF SUCH DAMAGE.
3551+
3292unordered-containers LICENSE file:
3552unordered-containers LICENSE file:
3293
3553
3294 Copyright (c) 2010, Johan Tibell
3554 Copyright (c) 2010, Johan Tibell
examples/failing/2128-class.pursnew file+5
@@ -0,0 +1,5 @@
1+-- @shouldFailWith ErrorParsingModule
2+module Main where
3+
4+class Foo a where
5+ foo :: a -> !!!
examples/failing/2128-instance.pursnew file+8
@@ -0,0 +1,8 @@
1+-- @shouldFailWith ErrorParsingModule
2+module Main where
3+
4+class Foo a where
5+ foo :: a
6+
7+instance fooInt :: Foo Int where
8+ foo = !!!
examples/failing/DeclConflictClassCtor.pursnew file+6
@@ -0,0 +1,6 @@
1+-- @shouldFailWith DeclConflict
2+module Main where
3+
4+data T = Fail
5+
6+class Fail
examples/failing/DeclConflictClassSynonym.pursnew file+8
@@ -0,0 +1,8 @@
1+-- @shouldFailWith DeclConflict
2+module Main where
3+
4+import Prelude
5+
6+type Fail = Unit
7+
8+class Fail
examples/failing/DeclConflictClassType.pursnew file+6
@@ -0,0 +1,6 @@
1+-- @shouldFailWith DeclConflict
2+module Main where
3+
4+class Fail
5+
6+data Fail
examples/failing/DeclConflictCtorClass.pursnew file+6
@@ -0,0 +1,6 @@
1+-- @shouldFailWith DeclConflict
2+module Main where
3+
4+class Fail
5+
6+data T = Fail
examples/failing/DeclConflictCtorCtor.pursnew file+6
@@ -0,0 +1,6 @@
1+-- @shouldFailWith DeclConflict
2+module Main where
3+
4+data T1 = Fail
5+
6+data T2 = Fail
examples/failing/DeclConflictSynonymClass.pursnew file+8
@@ -0,0 +1,8 @@
1+-- @shouldFailWith DeclConflict
2+module Main where
3+
4+import Prelude
5+
6+class Fail
7+
8+type Fail = Unit
examples/failing/DeclConflictSynonymType.pursnew file+8
@@ -0,0 +1,8 @@
1+-- @shouldFailWith DeclConflict
2+module Main where
3+
4+import Prelude
5+
6+data Fail
7+
8+type Fail = Unit
examples/failing/DeclConflictTypeClass.pursnew file+6
@@ -0,0 +1,6 @@
1+-- @shouldFailWith DeclConflict
2+module Main where
3+
4+class Fail
5+
6+data Fail
examples/failing/DeclConflictTypeSynonym.pursnew file+8
@@ -0,0 +1,8 @@
1+-- @shouldFailWith DeclConflict
2+module Main where
3+
4+import Prelude
5+
6+type Fail = Unit
7+
8+data Fail
examples/failing/DeclConflictTypeType.pursnew file+6
@@ -0,0 +1,6 @@
1+-- @shouldFailWith DeclConflict
2+module Main where
3+
4+data Fail
5+
6+data Fail
examples/failing/ExportConflictClass.pursnew file+5
@@ -0,0 +1,5 @@
1+-- @shouldFailWith ExportConflict
2+module C (module A, module B) where
3+
4+import A as A
5+import B as B
examples/failing/ExportConflictClass/A.pursnew file+3
@@ -0,0 +1,3 @@
1+module A where
2+
3+class X
examples/failing/ExportConflictClass/B.pursnew file+3
@@ -0,0 +1,3 @@
1+module B where
2+
3+class X
examples/failing/ExportConflictCtor.pursnew file+5
@@ -0,0 +1,5 @@
1+-- @shouldFailWith ExportConflict
2+module C (module A, module B) where
3+
4+import A as A
5+import B as B
examples/failing/ExportConflictCtor/A.pursnew file+3
@@ -0,0 +1,3 @@
1+module A where
2+
3+data T1 = X
examples/failing/ExportConflictCtor/B.pursnew file+3
@@ -0,0 +1,3 @@
1+module B where
2+
3+data T2 = X
examples/failing/ExportConflictType.pursnew file+5
@@ -0,0 +1,5 @@
1+-- @shouldFailWith ExportConflict
2+module C (module A, module B) where
3+
4+import A as A
5+import B as B
examples/failing/ExportConflictType/A.pursnew file+3
@@ -0,0 +1,3 @@
1+module A where
2+
3+data T
examples/failing/ExportConflictType/B.pursnew file+3
@@ -0,0 +1,3 @@
1+module B where
2+
3+data T
examples/failing/ExportConflictTypeOp.pursnew file+5
@@ -0,0 +1,5 @@
1+-- @shouldFailWith ExportConflict
2+module C (module A, module B) where
3+
4+import A as A
5+import B as B
examples/failing/ExportConflictTypeOp/A.pursnew file+5
@@ -0,0 +1,5 @@
1+module A where
2+
3+type T1 a b = a -> b
4+
5+infixr 4 type T1 as ??
examples/failing/ExportConflictTypeOp/B.pursnew file+5
@@ -0,0 +1,5 @@
1+module B where
2+
3+type T2 a b = a -> b
4+
5+infixr 4 type T2 as ??
examples/failing/ExportConflictValue.pursnew file+5
@@ -0,0 +1,5 @@
1+-- @shouldFailWith ExportConflict
2+module C (module A, module B) where
3+
4+import A as A
5+import B as B
examples/failing/OverlappingReExport/A.purs → examples/failing/ExportConflictValue/A.pursrenamed+2
@@ -1,2 +1,4 @@
1module A where
1module A where
2+
3+x :: Boolean
2x = true
4x = true
examples/failing/OverlappingReExport/B.purs → examples/failing/ExportConflictValue/B.pursrenamed+2
@@ -1,2 +1,4 @@
1module B where
1module B where
2+
3+x :: Boolean
2x = false
4x = false
examples/failing/ExportConflictValueOp.pursnew file+5
@@ -0,0 +1,5 @@
1+-- @shouldFailWith ExportConflict
2+module C (module A, module B) where
3+
4+import A as A
5+import B as B
examples/failing/ExportConflictValueOp/A.pursnew file+6
@@ -0,0 +1,6 @@
1+module A where
2+
3+f1 :: forall a b. a -> b -> a
4+f1 x _ = x
5+
6+infix 0 f1 as !!
examples/failing/ExportConflictValueOp/B.pursnew file+6
@@ -0,0 +1,6 @@
1+module B where
2+
3+f2 :: forall a b. a -> b -> a
4+f2 x _ = x
5+
6+infix 0 f2 as !!
examples/failing/OverlappingReExport.pursdeleted−5
@@ -1,5 +0,0 @@
1−-- @shouldFailWith DuplicateValueExport
2−module C (module A, module M2) where
3−
4−import A
5−import B as M2
examples/failing/ProgrammableTypeErrors.pursnew file+16
@@ -0,0 +1,16 @@
1+-- @shouldFailWith NoInstanceFound
2+
3+module Main where
4+
5+import Prelude
6+import Control.Monad.Eff (Eff)
7+import Control.Monad.Eff.Console (log)
8+
9+class MyShow a where
10+ myShow :: a -> String
11+
12+instance cannotShowFunctions :: Fail "Cannot show functions" => MyShow (a -> b) where
13+ myShow _ = "unreachable"
14+
15+main :: Eff _ _
16+main = log (myShow (_ + 1))
examples/passing/2172.jsnew file+5
@@ -0,0 +1,5 @@
1+exports['a\''] = 0;
2+exports["\x62\x27"] = 1;
3+// NOTE: I wanted to use "\c'" here, but langauge-javascript doesn't support it...
4+exports["c'"] = 2;
5+exports["\u0064\u0027"] = 3;
examples/passing/2172.pursnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+import Control.Monad.Eff.Console (log)
4+
5+foreign import a' :: Number
6+foreign import b' :: Number
7+foreign import c' :: Number
8+foreign import d' :: Number
9+
10+main = log "Done"
examples/passing/PrimedTypeName.pursnew file+20
@@ -0,0 +1,20 @@
1+module Main (T, T', T'', T''', main) where
2+
3+import Prelude
4+import Control.Monad.Eff.Console (log)
5+
6+data T a = T
7+type T' = T Unit
8+
9+data T'' = TP
10+
11+foreign import data T''' ∷ *
12+
13+instance eqT ∷ Eq T'' where
14+ eq _ _ = true
15+
16+type A' a b = b → a
17+
18+infixr 4 type A' as ↫
19+
20+main = log "Done"
hierarchy/Main.hs+1−1
@@ -65,7 +65,7 @@ compile (HierarchyOptions inputGlob mOutput) = do
65 input <- glob inputGlob
65 input <- glob inputGlob
66 modules <- readInput input
66 modules <- readInput input
67 case modules of
67 case modules of
68− Left errs -> hPutStr stderr (P.prettyPrintMultipleErrors False errs) >> exitFailure
68+ Left errs -> hPutStr stderr (P.prettyPrintMultipleErrors P.defaultPPEOptions errs) >> exitFailure
69 Right ms -> do
69 Right ms -> do
70 for_ ms $ \(P.Module _ _ moduleName decls _) ->
70 for_ ms $ \(P.Module _ _ moduleName decls _) ->
71 let name = runModuleName moduleName
71 let name = runModuleName moduleName
psc-bundle/Main.hs+1−9
@@ -15,7 +15,7 @@ import Control.Monad.Error.Class
15import Control.Monad.Trans.Except
15import Control.Monad.Trans.Except
16import Control.Monad.IO.Class
16import Control.Monad.IO.Class
17
17
18−import System.FilePath (takeFileName, takeDirectory)
18+import System.FilePath (takeDirectory)
19import System.FilePath.Glob (glob)
19import System.FilePath.Glob (glob)
20import System.Exit (exitFailure)
20import System.Exit (exitFailure)
21import System.IO (stderr, stdout, hPutStrLn, hSetEncoding, utf8)
21import System.IO (stderr, stdout, hPutStrLn, hSetEncoding, utf8)
@@ -37,14 +37,6 @@ data Options = Options
37 , optionsNamespace :: String
37 , optionsNamespace :: String
38 } deriving Show
38 } deriving Show
39
39
40−-- | Given a filename, assuming it is in the correct place on disk, infer a ModuleIdentifier.
41−guessModuleIdentifier :: (MonadError ErrorMessage m) => FilePath -> m ModuleIdentifier
42−guessModuleIdentifier filename = ModuleIdentifier (takeFileName (takeDirectory filename)) <$> guessModuleType (takeFileName filename)
43− where
44− guessModuleType "index.js" = pure Regular
45− guessModuleType "foreign.js" = pure Foreign
46− guessModuleType name = throwError $ UnsupportedModulePath name
47−
48-- | The main application function.
40-- | The main application function.
49-- This function parses the input files, performs dead code elimination, filters empty modules
41-- This function parses the input files, performs dead code elimination, filters empty modules
50-- and generates and prints the final Javascript bundle.
42-- and generates and prints the final Javascript bundle.
psc-docs/Main.hs+1−1
@@ -95,7 +95,7 @@ docgen (PSCDocsOptions fmt inputGlob output) = do
95 Right x ->
95 Right x ->
96 return x
96 return x
97 Left err -> do
97 Left err -> do
98− hPutStrLn stderr $ P.prettyPrintMultipleErrors False err
98+ hPutStrLn stderr $ P.prettyPrintMultipleErrors P.defaultPPEOptions err
99 exitFailure
99 exitFailure
100
100
101 takeByName = takeModulesByName D.modName
101 takeByName = takeModulesByName D.modName
psc-ide-client/Main.hs+6−16
@@ -5,16 +5,15 @@ import Prelude ()
5import Prelude.Compat
5import Prelude.Compat
6
6
7import Control.Exception
7import Control.Exception
8−import Data.Text (Text)
9−import qualified Data.Text as T
8+import qualified Data.ByteString.Char8 as BS8
10−import qualified Data.Text.IO as T
9+import qualified Data.Text.IO as T
11−import Data.Version (showVersion)
10+import Data.Version (showVersion)
12import Network
11import Network
13import Options.Applicative
12import Options.Applicative
14import System.Exit
13import System.Exit
15import System.IO
14import System.IO
16
15
17−import qualified Paths_purescript as Paths
16+import qualified Paths_purescript as Paths
18
17
19data Options = Options
18data Options = Options
20 { optionsPort :: PortID
19 { optionsPort :: PortID
@@ -41,16 +40,7 @@ client port = do
41 ("Couldn't connect to psc-ide-server on port: " ++
40 ("Couldn't connect to psc-ide-server on port: " ++
42 show port ++ " Error: " ++ show e) >>
41 show port ++ " Error: " ++ show e) >>
43 exitFailure)
42 exitFailure)
44− cmd <- T.getLine
45− -- Temporary fix for emacs windows bug
46− let cleanedCmd = removeSurroundingTicks cmd
47− --
48− T.hPutStrLn h cleanedCmd
43+ T.hPutStrLn h =<< T.getLine
49− res <- T.hGetLine h
44+ BS8.putStrLn =<< BS8.hGetLine h
50− putStrLn (T.unpack res)
51 hFlush stdout
45 hFlush stdout
52 hClose h
46 hClose h
53−
54−-- TODO: Fix this in the emacs plugin by using a real process over shellcommands
55−removeSurroundingTicks :: Text -> Text
56−removeSurroundingTicks = T.dropWhile (== '\'') . T.dropWhileEnd (== '\'')
psc-ide-server/Main.hs+33−42
@@ -17,22 +17,17 @@
17{-# LANGUAGE OverloadedStrings #-}
17{-# LANGUAGE OverloadedStrings #-}
18{-# LANGUAGE PackageImports #-}
18{-# LANGUAGE PackageImports #-}
19{-# LANGUAGE TemplateHaskell #-}
19{-# LANGUAGE TemplateHaskell #-}
20+{-# LANGUAGE NoImplicitPrelude #-}
20
21
21module Main where
22module Main where
22
23
23−import Prelude ()
24+import Protolude
24−import Prelude.Compat
25
25
26−import Control.Concurrent (forkFinally)
26+import qualified Data.Aeson as Aeson
27import Control.Concurrent.STM
27import Control.Concurrent.STM
28−import Control.Exception (bracketOnError, catchJust)
29−import Control.Monad
30−import Control.Monad.Error.Class
31import "monad-logger" Control.Monad.Logger
28import "monad-logger" Control.Monad.Logger
32−import Control.Monad.Reader
33−import Control.Monad.Trans.Except
34−import qualified Data.Text as T
35import qualified Data.Text.IO as T
29import qualified Data.Text.IO as T
30+import qualified Data.ByteString.Lazy.Char8 as BS8
36import Data.Version (showVersion)
31import Data.Version (showVersion)
37import Language.PureScript.Ide
32import Language.PureScript.Ide
38import Language.PureScript.Ide.Util
33import Language.PureScript.Ide.Util
@@ -43,19 +38,16 @@ import Network hiding (socketPort, accept)
43import Network.BSD (getProtocolNumber)
38import Network.BSD (getProtocolNumber)
44import Network.Socket hiding (PortNumber, Type,
39import Network.Socket hiding (PortNumber, Type,
45 sClose)
40 sClose)
46−import Options.Applicative
41+import Options.Applicative hiding ((<>))
47import System.Directory
42import System.Directory
48import System.FilePath
43import System.FilePath
49−import System.IO
44+import System.IO hiding (putStrLn, print)
50import System.IO.Error (isEOFError)
45import System.IO.Error (isEOFError)
51
46
52import qualified Paths_purescript as Paths
47import qualified Paths_purescript as Paths
53
48
54−-- "Borrowed" from the Idris Compiler
55−-- Copied from upstream impl of listenOn
56−-- bound to localhost interface instead of iNADDR_ANY
57−listenOnLocalhost :: PortID -> IO Socket
49+listenOnLocalhost :: PortNumber -> IO Socket
58−listenOnLocalhost (PortNumber port) = do
50+listenOnLocalhost port = do
59 proto <- getProtocolNumber "tcp"
51 proto <- getProtocolNumber "tcp"
60 localhost <- inet_addr "127.0.0.1"
52 localhost <- inet_addr "127.0.0.1"
61 bracketOnError
53 bracketOnError
@@ -66,59 +58,59 @@ listenOnLocalhost (PortNumber port) = do
66 bindSocket sock (SockAddrInet port localhost)
58 bindSocket sock (SockAddrInet port localhost)
67 listen sock maxListenQueue
59 listen sock maxListenQueue
68 pure sock)
60 pure sock)
69−listenOnLocalhost _ = error "Wrong Porttype"
70
61
71data Options = Options
62data Options = Options
72 { optionsDirectory :: Maybe FilePath
63 { optionsDirectory :: Maybe FilePath
64+ , optionsGlobs :: [FilePath]
73 , optionsOutputPath :: FilePath
65 , optionsOutputPath :: FilePath
74− , optionsPort :: PortID
66+ , optionsPort :: PortNumber
75 , optionsNoWatch :: Bool
67 , optionsNoWatch :: Bool
76 , optionsDebug :: Bool
68 , optionsDebug :: Bool
77 }
69 }
78
70
79main :: IO ()
71main :: IO ()
80main = do
72main = do
81− Options dir outputPath port noWatch debug <- execParser opts
73+ Options dir globs outputPath port noWatch debug <- execParser opts
82 maybe (pure ()) setCurrentDirectory dir
74 maybe (pure ()) setCurrentDirectory dir
83− serverState <- newTVarIO emptyPscIdeState
75+ ideState <- newTVarIO emptyIdeState
84 cwd <- getCurrentDirectory
76 cwd <- getCurrentDirectory
85 let fullOutputPath = cwd </> outputPath
77 let fullOutputPath = cwd </> outputPath
86
78
87− doesDirectoryExist fullOutputPath
79+ unlessM (doesDirectoryExist fullOutputPath) $ do
88− >>= flip unless
89− (do putStrLn ("Your output directory didn't exist. I'll create it at: " <> fullOutputPath)
80+ putStrLn ("Your output directory didn't exist. I'll create it at: " <> fullOutputPath)
90− createDirectory fullOutputPath
81+ createDirectory fullOutputPath
91− putStrLn "This usually means you didn't compile your project yet."
82+ putText "This usually means you didn't compile your project yet."
92− putStrLn "psc-ide needs you to compile your project (for example by running pulp build)")
83+ putText "psc-ide needs you to compile your project (for example by running pulp build)"
93
84
94 unless noWatch $
85 unless noWatch $
95− void (forkFinally (watcher serverState fullOutputPath) print)
86+ void (forkFinally (watcher ideState fullOutputPath) print)
96
87
97− let conf = Configuration {confDebug = debug, confOutputPath = outputPath}
88+ let conf = Configuration {confDebug = debug, confOutputPath = outputPath, confGlobs = globs}
98− env = PscIdeEnvironment {envStateVar = serverState, envConfiguration = conf}
89+ env = IdeEnvironment {ideStateVar = ideState, ideConfiguration = conf}
99 startServer port env
90 startServer port env
100 where
91 where
101 parser =
92 parser =
102 Options
93 Options
103− <$> optional (strOption (long "directory" <> short 'd'))
94+ <$> optional (strOption (long "directory" `mappend` short 'd'))
95+ <*> many (argument str (metavar "Source GLOBS..."))
104− <*> strOption (long "output-directory" <> value "output/")
96+ <*> strOption (long "output-directory" `mappend` value "output/")
105− <*> (PortNumber . fromIntegral <$>
97+ <*> (fromIntegral <$>
106− option auto (long "port" <> short 'p' <> value (4242 :: Integer)))
98+ option auto (long "port" `mappend` short 'p' `mappend` value (4242 :: Integer)))
107 <*> switch (long "no-watch")
99 <*> switch (long "no-watch")
108 <*> switch (long "debug")
100 <*> switch (long "debug")
109 opts = info (version <*> helper <*> parser) mempty
101 opts = info (version <*> helper <*> parser) mempty
110 version = abortOption
102 version = abortOption
111 (InfoMsg (showVersion Paths.version))
103 (InfoMsg (showVersion Paths.version))
112− (long "version" <> help "Show the version number")
104+ (long "version" `mappend` help "Show the version number")
113
105
114−startServer :: PortID -> PscIdeEnvironment -> IO ()
106+startServer :: PortNumber -> IdeEnvironment -> IO ()
115startServer port env = withSocketsDo $ do
107startServer port env = withSocketsDo $ do
116 sock <- listenOnLocalhost port
108 sock <- listenOnLocalhost port
117 runLogger (runReaderT (forever (loop sock)) env)
109 runLogger (runReaderT (forever (loop sock)) env)
118 where
110 where
119− runLogger = runStdoutLoggingT . filterLogger (\_ _ -> confDebug (envConfiguration env))
111+ runLogger = runStdoutLoggingT . filterLogger (\_ _ -> confDebug (ideConfiguration env))
120
112
121− loop :: (PscIde m, MonadLogger m) => Socket -> m ()
113+ loop :: (Ide m, MonadLogger m) => Socket -> m ()
122 loop sock = do
114 loop sock = do
123 accepted <- runExceptT $ acceptCommand sock
115 accepted <- runExceptT $ acceptCommand sock
124 case accepted of
116 case accepted of
@@ -130,9 +122,8 @@ startServer port env = withSocketsDo $ do
130 -- $(logDebug) ("Answer was: " <> T.pack (show result))
122 -- $(logDebug) ("Answer was: " <> T.pack (show result))
131 liftIO (hFlush stdout)
123 liftIO (hFlush stdout)
132 case result of
124 case result of
133− -- What function can I use to clean this up?
134− Right r -> liftIO $ T.hPutStrLn h (encodeT r)
125+ Right r -> liftIO $ BS8.hPutStrLn h (Aeson.encode r)
135− Left err -> liftIO $ T.hPutStrLn h (encodeT err)
126+ Left err -> liftIO $ BS8.hPutStrLn h (Aeson.encode err)
136 Nothing -> do
127 Nothing -> do
137 $(logDebug) ("Parsing the command failed. Command: " <> cmd)
128 $(logDebug) ("Parsing the command failed. Command: " <> cmd)
138 liftIO $ do
129 liftIO $ do
@@ -141,8 +132,8 @@ startServer port env = withSocketsDo $ do
141 liftIO (hClose h)
132 liftIO (hClose h)
142
133
143
134
144−acceptCommand :: (MonadIO m, MonadLogger m, MonadError T.Text m)
135+acceptCommand :: (MonadIO m, MonadLogger m, MonadError Text m)
145− => Socket -> m (T.Text, Handle)
136+ => Socket -> m (Text, Handle)
146acceptCommand sock = do
137acceptCommand sock = do
147 h <- acceptConnection
138 h <- acceptConnection
148 $(logDebug) "Accepted a connection"
139 $(logDebug) "Accepted a connection"
psc-ide-server/PROTOCOL.md+26−9
@@ -14,27 +14,24 @@ to detect all the compiled modules in your project and load them.
14
14
15**Params:**
15**Params:**
16 - `modules :: (optional) [ModuleName]`: A list of modules to load.
16 - `modules :: (optional) [ModuleName]`: A list of modules to load.
17− psc-ide-server will try to parse all the declarations in these modules
17+ psc-ide-server will try to parse all the declarations in these modules
18− - `dependencies :: (optional) [ModuleName]`: A list of modules to load
19− including their dependencies. In contrast to the `module` field, all the
20− imports in these Modules will also be loaded.
21
18
22```json
19```json
23{
20{
24 "command": "load",
21 "command": "load",
25 "params": (optional) {
22 "params": (optional) {
26− "modules": (optional)["Module.Name1", "Module.Name2"],
23+ "modules": (optional)["Module.Name1", "Module.Name2"]
27− "dependencies": (optional)["Module.Name3"]
28 }
24 }
29}
25}
30```
26```
31
27
32**Result:**
28**Result:**
33
29
34−The Load Command returns a string.
30+The Load Command returns a string with a summary about the loading process.
35
31
36### Type
32### Type
37−The `type` command looks up the type for a given identifier.
33+The `type` command looks up the type for a given identifier. It also returns the
34+definition position, if it can be found in the passed source files.
38
35
39**Params:**
36**Params:**
40 - `search :: String`: The identifier to look for. Only matches on equality.
37 - `search :: String`: The identifier to look for. Only matches on equality.
@@ -54,7 +51,27 @@ The `type` command looks up the type for a given identifier.
54```
51```
55
52
56**Result:**
53**Result:**
57−The possible types are returned in the same format as completions
54+The possible types are returned in the same format as completions + eventual position information
55+```json
56+[
57+ {
58+ "module": "Data.Array",
59+ "identifier": "filter",
60+ "type": "forall a. (a -> Boolean) -> Array a -> Array a"
61+ },
62+ {
63+ "module": "Data.Array",
64+ "identifier": "filter",
65+ "type": "forall a. (a -> Boolean) -> Array a -> Array a",
66+ "definedAt":
67+ {
68+ "name": "/path/to/file",
69+ "start": [1, 3],
70+ "end": [3, 1]
71+ }
72+ }
73+]
74+```
58
75
59### Complete
76### Complete
60The `complete` command looks up possible completions/corrections.
77The `complete` command looks up possible completions/corrections.
psc-ide-server/README.md+4−1
@@ -10,7 +10,10 @@ A tool which provides editor support for the PureScript programming language.
10* Vim integration is available here: https://github.com/FrigoEU/psc-ide-vim.
10* Vim integration is available here: https://github.com/FrigoEU/psc-ide-vim.
11
11
12## Running the Server
12## Running the Server
13+
13−Start the server by running the `psc-ide-server` executable.
14+Start the server by running the `psc-ide-server [SOURCEGLOBS]` executable, where
15+`SOURCEGLOBS` are (optional) globs that match your PureScript sourcefiles.
16+
14It supports the following options:
17It supports the following options:
15
18
16- `-p / --port` specify a port. Defaults to 4242
19- `-p / --port` specify a port. Defaults to 4242
psc/Main.hs+6−2
@@ -11,6 +11,7 @@ import Control.Monad
11import Control.Monad.Writer.Strict
11import Control.Monad.Writer.Strict
12
12
13import qualified Data.Aeson as A
13import qualified Data.Aeson as A
14+import Data.Bool (bool)
14import qualified Data.ByteString.Lazy as B
15import qualified Data.ByteString.Lazy as B
15import qualified Data.ByteString.UTF8 as BU8
16import qualified Data.ByteString.UTF8 as BU8
16import qualified Data.Map as M
17import qualified Data.Map as M
@@ -24,6 +25,7 @@ import Options.Applicative as Opts
24
25
25import qualified Paths_purescript as Paths
26import qualified Paths_purescript as Paths
26
27
28+import qualified System.Console.ANSI as ANSI
27import System.Exit (exitSuccess, exitFailure)
29import System.Exit (exitSuccess, exitFailure)
28import System.FilePath.Glob (glob)
30import System.FilePath.Glob (glob)
29import System.IO (hSetEncoding, hPutStrLn, stdout, stderr, utf8)
31import System.IO (hSetEncoding, hPutStrLn, stdout, stderr, utf8)
@@ -40,11 +42,13 @@ data PSCMakeOptions = PSCMakeOptions
40-- | Argumnets: verbose, use JSON, warnings, errors
42-- | Argumnets: verbose, use JSON, warnings, errors
41printWarningsAndErrors :: Bool -> Bool -> P.MultipleErrors -> Either P.MultipleErrors a -> IO ()
43printWarningsAndErrors :: Bool -> Bool -> P.MultipleErrors -> Either P.MultipleErrors a -> IO ()
42printWarningsAndErrors verbose False warnings errors = do
44printWarningsAndErrors verbose False warnings errors = do
45+ cc <- bool Nothing (Just P.defaultCodeColor) <$> ANSI.hSupportsANSI stderr
46+ let ppeOpts = P.defaultPPEOptions { P.ppeCodeColor = cc, P.ppeFull = verbose }
43 when (P.nonEmpty warnings) $
47 when (P.nonEmpty warnings) $
44− hPutStrLn stderr (P.prettyPrintMultipleWarnings verbose warnings)
48+ hPutStrLn stderr (P.prettyPrintMultipleWarnings ppeOpts warnings)
45 case errors of
49 case errors of
46 Left errs -> do
50 Left errs -> do
47− hPutStrLn stderr (P.prettyPrintMultipleErrors verbose errs)
51+ hPutStrLn stderr (P.prettyPrintMultipleErrors ppeOpts errs)
48 exitFailure
52 exitFailure
49 Right _ -> return ()
53 Right _ -> return ()
50printWarningsAndErrors verbose True warnings errors = do
54printWarningsAndErrors verbose True warnings errors = do
psci/Main.hs+259−27
@@ -1,9 +1,13 @@
1{-# LANGUAGE DataKinds #-}
1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DoAndIfThenElse #-}
2{-# LANGUAGE DoAndIfThenElse #-}
3+{-# LANGUAGE GADTs #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE OverloadedStrings #-}
7+{-# LANGUAGE PatternGuards #-}
5{-# LANGUAGE RecordWildCards #-}
8{-# LANGUAGE RecordWildCards #-}
6{-# LANGUAGE ScopedTypeVariables #-}
9{-# LANGUAGE ScopedTypeVariables #-}
10+{-# LANGUAGE TemplateHaskell #-}
7{-# LANGUAGE TupleSections #-}
11{-# LANGUAGE TupleSections #-}
8
12
9module Main (main) where
13module Main (main) where
@@ -11,10 +15,22 @@ module Main (main) where
11import Prelude ()
15import Prelude ()
12import Prelude.Compat
16import Prelude.Compat
13
17
18+import Data.FileEmbed (embedStringFile)
14import Data.Monoid ((<>))
19import Data.Monoid ((<>))
20+import Data.String (IsString(..))
21+import Data.Text (Text, unpack)
22+import Data.Traversable (for)
15import Data.Version (showVersion)
23import Data.Version (showVersion)
16
24
17−import Control.Applicative (many)
25+import Control.Applicative (many, (<|>))
26+import Control.Concurrent (forkIO)
27+import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar,
28+ tryPutMVar)
29+import Control.Concurrent.STM (TVar, atomically, newTVarIO, writeTVar,
30+ readTVarIO,
31+ TChan, newBroadcastTChanIO, dupTChan,
32+ readTChan, writeTChan)
33+import Control.Exception (fromException)
18import Control.Monad
34import Control.Monad
19import Control.Monad.IO.Class (liftIO)
35import Control.Monad.IO.Class (liftIO)
20import Control.Monad.Trans.Class
36import Control.Monad.Trans.Class
@@ -23,21 +39,33 @@ import Control.Monad.Trans.State.Strict (StateT, evalStateT)
23import Control.Monad.Trans.Reader (ReaderT, runReaderT)
39import Control.Monad.Trans.Reader (ReaderT, runReaderT)
24
40
25import qualified Language.PureScript as P
41import qualified Language.PureScript as P
42+import qualified Language.PureScript.Bundle as Bundle
26import Language.PureScript.Interactive
43import Language.PureScript.Interactive
27
44
45+import Network.HTTP.Types.Header (hContentType, hCacheControl,
46+ hPragma, hExpires)
47+import Network.HTTP.Types.Status (status200, status404, status503)
48+import qualified Network.Wai as Wai
49+import qualified Network.Wai.Handler.Warp as Warp
50+import qualified Network.Wai.Handler.WebSockets as WS
51+import qualified Network.WebSockets as WS
52+
28import qualified Options.Applicative as Opts
53import qualified Options.Applicative as Opts
29
54
30import qualified Paths_purescript as Paths
55import qualified Paths_purescript as Paths
31
56
32import System.Console.Haskeline
57import System.Console.Haskeline
58+import System.IO.UTF8 (readUTF8File)
33import System.Exit
59import System.Exit
60+import System.FilePath ((</>))
34import System.FilePath.Glob (glob)
61import System.FilePath.Glob (glob)
62+import System.Process (readProcessWithExitCode)
35
63
36-- | Command line options
64-- | Command line options
37data PSCiOptions = PSCiOptions
65data PSCiOptions = PSCiOptions
38 { psciMultiLineMode :: Bool
66 { psciMultiLineMode :: Bool
39 , psciInputFile :: [FilePath]
67 , psciInputFile :: [FilePath]
40− , psciInputNodeFlags :: [String]
68+ , psciBackend :: Backend
41 }
69 }
42
70
43multiLineMode :: Opts.Parser Bool
71multiLineMode :: Opts.Parser Bool
@@ -60,10 +88,21 @@ nodeFlagsFlag = Opts.option parser $
60 where
88 where
61 parser = words <$> Opts.str
89 parser = words <$> Opts.str
62
90
91+port :: Opts.Parser Int
92+port = Opts.option Opts.auto $
93+ Opts.long "port"
94+ <> Opts.short 'p'
95+ <> Opts.help "The web server port"
96+
97+backend :: Opts.Parser Backend
98+backend =
99+ (browserBackend <$> port)
100+ <|> (nodeBackend <$> nodeFlagsFlag)
101+
63psciOptions :: Opts.Parser PSCiOptions
102psciOptions :: Opts.Parser PSCiOptions
64psciOptions = PSCiOptions <$> multiLineMode
103psciOptions = PSCiOptions <$> multiLineMode
65 <*> many inputFile
104 <*> many inputFile
66− <*> nodeFlagsFlag
105+ <*> backend
67
106
68version :: Opts.Parser (a -> a)
107version :: Opts.Parser (a -> a)
69version = Opts.abortOption (Opts.InfoMsg (showVersion Paths.version)) $
108version = Opts.abortOption (Opts.InfoMsg (showVersion Paths.version)) $
@@ -92,6 +131,195 @@ getCommand singleLineMode = handleInterrupt (return (Right Nothing)) $ do
92 go :: [String] -> InputT m String
131 go :: [String] -> InputT m String
93 go ls = maybe (return . unlines $ reverse ls) (go . (:ls)) =<< getInputLine " "
132 go ls = maybe (return . unlines $ reverse ls) (go . (:ls)) =<< getInputLine " "
94
133
134+-- | Make a JavaScript bundle for the browser.
135+bundle :: IO (Either Bundle.ErrorMessage String)
136+bundle = runExceptT $ do
137+ inputFiles <- liftIO (glob (".psci_modules" </> "node_modules" </> "*" </> "*.js"))
138+ input <- for inputFiles $ \filename -> do
139+ js <- liftIO (readUTF8File filename)
140+ mid <- Bundle.guessModuleIdentifier filename
141+ length js `seq` return (mid, js)
142+ Bundle.bundle input [] Nothing "PSCI"
143+
144+indexJS :: IsString string => string
145+indexJS = $(embedStringFile "psci/static/index.js")
146+
147+indexPage :: IsString string => string
148+indexPage = $(embedStringFile "psci/static/index.html")
149+
150+-- | All of the functions required to implement a PSCi backend
151+data Backend = forall state. Backend
152+ { _backendSetup :: IO state
153+ -- ^ Initialize, and call the continuation when the backend is ready
154+ , _backendEval :: state -> String -> IO ()
155+ -- ^ Evaluate JavaScript code
156+ , _backendReload :: state -> IO ()
157+ -- ^ Reload the compiled code
158+ , _backendShutdown :: state -> IO ()
159+ -- ^ Shut down the backend
160+ }
161+
162+-- | Commands which can be sent to the browser
163+data BrowserCommand
164+ = Eval (MVar String)
165+ -- ^ Evaluate the latest JS
166+ | Reload
167+ -- ^ Reload the page
168+
169+-- | State for the browser backend
170+data BrowserState = BrowserState
171+ { browserCommands :: TChan BrowserCommand
172+ -- ^ A channel which receives data when the compiled JS has
173+ -- been updated
174+ , browserShutdownNotice :: MVar ()
175+ -- ^ An MVar which becomes full when the server should shut down
176+ , browserIndexJS :: TVar (Maybe String)
177+ -- ^ A TVar holding the latest compiled JS
178+ , browserBundleJS :: TVar (Maybe String)
179+ -- ^ A TVar holding the latest bundled JS
180+ }
181+
182+browserBackend :: Int -> Backend
183+browserBackend serverPort = Backend setup evaluate reload shutdown
184+ where
185+ setup :: IO BrowserState
186+ setup = do
187+ shutdownVar <- newEmptyMVar
188+ cmdChan <- newBroadcastTChanIO
189+ indexJs <- newTVarIO Nothing
190+ bundleJs <- newTVarIO Nothing
191+
192+ let
193+ handleWebsocket :: WS.PendingConnection -> IO ()
194+ handleWebsocket pending = do
195+ conn <- WS.acceptRequest pending
196+ -- Fork a thread to keep the connection alive
197+ WS.forkPingThread conn 10
198+ -- Clone the command channel
199+ cmdChanCopy <- atomically $ dupTChan cmdChan
200+ -- Listen for commands
201+ forever $ do
202+ cmd <- atomically $ readTChan cmdChanCopy
203+ case cmd of
204+ Eval resultVar -> void $ do
205+ WS.sendTextData conn ("eval" :: Text)
206+ result <- WS.receiveData conn
207+ -- With many connected clients, all but one of
208+ -- these attempts will fail.
209+ tryPutMVar resultVar (unpack result)
210+ Reload -> do
211+ WS.sendTextData conn ("reload" :: Text)
212+
213+ shutdownHandler :: IO () -> IO ()
214+ shutdownHandler stopServer = void . forkIO $ do
215+ () <- takeMVar shutdownVar
216+ stopServer
217+
218+ onException :: Maybe Wai.Request -> SomeException -> IO ()
219+ onException req ex
220+ | Just (_ :: WS.ConnectionException) <- fromException ex
221+ = return () -- ignore websocket disconnects
222+ | otherwise = Warp.defaultOnException req ex
223+
224+ staticServer :: Wai.Application
225+ staticServer req respond =
226+ case Wai.pathInfo req of
227+ [] ->
228+ respond $ Wai.responseLBS status200
229+ [(hContentType, "text/html")]
230+ indexPage
231+ ["js", "index.js"] ->
232+ respond $ Wai.responseLBS status200
233+ [(hContentType, "application/javascript")]
234+ indexJS
235+ ["js", "latest.js"] -> do
236+ may <- readTVarIO indexJs
237+ case may of
238+ Nothing ->
239+ respond $ Wai.responseLBS status503 [] "Service not available"
240+ Just js ->
241+ respond $ Wai.responseLBS status200
242+ [ (hContentType, "application/javascript")
243+ , (hCacheControl, "no-cache, no-store, must-revalidate")
244+ , (hPragma, "no-cache")
245+ , (hExpires, "0")
246+ ]
247+ (fromString js)
248+ ["js", "bundle.js"] -> do
249+ may <- readTVarIO bundleJs
250+ case may of
251+ Nothing ->
252+ respond $ Wai.responseLBS status503 [] "Service not available"
253+ Just js ->
254+ respond $ Wai.responseLBS status200
255+ [ (hContentType, "application/javascript")]
256+ (fromString js)
257+ _ -> respond $ Wai.responseLBS status404 [] "Not found"
258+
259+ let browserState = BrowserState cmdChan shutdownVar indexJs bundleJs
260+ createBundle browserState
261+
262+ putStrLn $ "Serving http://localhost:" <> show serverPort <> "/. Waiting for connections..."
263+ _ <- forkIO $ Warp.runSettings ( Warp.setInstallShutdownHandler shutdownHandler
264+ . Warp.setPort serverPort
265+ . Warp.setOnException onException
266+ $ Warp.defaultSettings
267+ ) $
268+ WS.websocketsOr WS.defaultConnectionOptions
269+ handleWebsocket
270+ staticServer
271+ return browserState
272+
273+ createBundle :: BrowserState -> IO ()
274+ createBundle state = do
275+ putStrLn "Bundling Javascript..."
276+ ejs <- bundle
277+ case ejs of
278+ Left err -> do
279+ putStrLn (unlines (Bundle.printErrorMessage err))
280+ exitFailure
281+ Right js -> do
282+ atomically $ writeTVar (browserBundleJS state) (Just js)
283+
284+ reload :: BrowserState -> IO ()
285+ reload state = do
286+ createBundle state
287+ atomically $ writeTChan (browserCommands state) Reload
288+
289+ shutdown :: BrowserState -> IO ()
290+ shutdown state = putMVar (browserShutdownNotice state) ()
291+
292+ evaluate :: BrowserState -> String -> IO ()
293+ evaluate state js = liftIO $ do
294+ resultVar <- newEmptyMVar
295+ atomically $ do
296+ writeTVar (browserIndexJS state) (Just js)
297+ writeTChan (browserCommands state) (Eval resultVar)
298+ result <- takeMVar resultVar
299+ putStrLn result
300+
301+nodeBackend :: [String] -> Backend
302+nodeBackend nodeArgs = Backend setup eval reload shutdown
303+ where
304+ setup :: IO ()
305+ setup = return ()
306+
307+ eval :: () -> String -> IO ()
308+ eval _ _ = do
309+ writeFile indexFile "require('$PSCI')['$main']();"
310+ process <- findNodeProcess
311+ result <- traverse (\node -> readProcessWithExitCode node (nodeArgs ++ [indexFile]) "") process
312+ case result of
313+ Just (ExitSuccess, out, _) -> putStrLn out
314+ Just (ExitFailure _, _, err) -> putStrLn err
315+ Nothing -> putStrLn "Couldn't find node.js"
316+
317+ reload :: () -> IO ()
318+ reload _ = return ()
319+
320+ shutdown :: () -> IO ()
321+ shutdown _ = return ()
322+
95-- | Get command line options and drop into the REPL
323-- | Get command line options and drop into the REPL
96main :: IO ()
324main :: IO ()
97main = getOpt >>= loop
325main = getOpt >>= loop
@@ -106,27 +334,31 @@ main = getOpt >>= loop
106 exitFailure
334 exitFailure
107 (externs, env) <- ExceptT . runMake . make $ modules
335 (externs, env) <- ExceptT . runMake . make $ modules
108 return (modules, externs, env)
336 return (modules, externs, env)
337+ case psciBackend of
338+ Backend setup eval reload (shutdown :: state -> IO ()) -> do
109− case e of
339+ case e of
110− Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> exitFailure
340+ Left errs -> putStrLn (P.prettyPrintMultipleErrors P.defaultPPEOptions errs) >> exitFailure
111− Right (modules, externs, env) -> do
341+ Right (modules, externs, env) -> do
112− historyFilename <- getHistoryFilename
342+ historyFilename <- getHistoryFilename
113− let settings = defaultSettings { historyFile = Just historyFilename }
343+ let settings = defaultSettings { historyFile = Just historyFilename }
114− initialState = PSCiState [] [] (zip (map snd modules) externs)
344+ initialState = PSCiState [] [] (zip (map snd modules) externs)
115− config = PSCiConfig inputFiles psciInputNodeFlags env
345+ config = PSCiConfig inputFiles env
116− runner = flip runReaderT config
346+ runner = flip runReaderT config
117− . flip evalStateT initialState
347+ . flip evalStateT initialState
118− . runInputT (setComplete completion settings)
348+ . runInputT (setComplete completion settings)
119− putStrLn prologueMessage
349+
120− runner go
121− where
122− go :: InputT (StateT PSCiState (ReaderT PSCiConfig IO)) ()
350+ go :: state -> InputT (StateT PSCiState (ReaderT PSCiConfig IO)) ()
123− go = do
351+ go state = do
124− c <- getCommand (not psciMultiLineMode)
352+ c <- getCommand (not psciMultiLineMode)
125− case c of
353+ case c of
126− Left err -> outputStrLn err >> go
354+ Left err -> outputStrLn err >> go state
127− Right Nothing -> go
355+ Right Nothing -> go state
356+ Right (Just QuitPSCi) -> do
128− Right (Just QuitPSCi) -> outputStrLn quitMessage
357+ outputStrLn quitMessage
358+ liftIO $ shutdown state
129− Right (Just c') -> do
359+ Right (Just c') -> do
130− handleInterrupt (outputStrLn "Interrupted.")
360+ handleInterrupt (outputStrLn "Interrupted.")
131− (withInterrupt (lift (handleCommand c')))
361+ (withInterrupt (lift (handleCommand (liftIO . eval state) (liftIO (reload state)) c')))
132− go
362+ go state
363+ putStrLn prologueMessage
364+ setup >>= runner . go
psci/static/index.htmlnew file+10
@@ -0,0 +1,10 @@
1+<!DOCTYPE html>
2+<html>
3+<head>
4+ <title>PureScript Interactive</title>
5+ <script src='js/bundle.js'></script>
6+ <script src='js/index.js'></script>
7+</head>
8+<body>
9+</body>
10+</html>
psci/static/index.jsnew file+63
@@ -0,0 +1,63 @@
1+var get = function get(uri, callback, onError) {
2+ var request = new XMLHttpRequest();
3+ request.addEventListener('load', function() {
4+ callback(request.responseText);
5+ });
6+ request.addEventListener('error', onError);
7+ request.open('GET', uri);
8+ request.send();
9+};
10+var evaluate = function evaluate(js) {
11+ var buffer = [];
12+ // Save the old console.log function
13+ var oldLog = console.log;
14+ console.log = function(s) {
15+ // Push log output into a temporary buffer
16+ // which will be returned to PSCi.
17+ buffer.push(s);
18+ };
19+ // Replace any require(...) statements with lookups on the PSCI object.
20+ var replaced = js.replace(/require\("[^"]*"\)/g, function(s) {
21+ return "PSCI['" + s.substring(12, s.length - 2) + "']";
22+ });
23+ // Wrap the module and evaluate it.
24+ var wrapped =
25+ [ 'var module = {};'
26+ , '(function(module) {'
27+ , replaced
28+ , '})(module);'
29+ , 'return module.exports["$main"] && module.exports["$main"]();'
30+ ].join('\n');
31+ new Function(wrapped)();
32+ // Restore console.log
33+ console.log = oldLog;
34+ return buffer.join('\n');
35+};
36+window.onload = function() {
37+ var socket = new WebSocket('ws://0.0.0.0:' + location.port);
38+ var evalNext = function reload() {
39+ get('js/latest.js', function(response) {
40+ try {
41+ var result = evaluate(response);
42+ socket.send(result);
43+ } catch (ex) {
44+ socket.send(ex.stack);
45+ }
46+ }, function(err) {
47+ socket.send('Error sending JavaScript');
48+ });
49+ };
50+ socket.onopen = function() {
51+ console.log('Connected');
52+ socket.onmessage = function(event) {
53+ switch (event.data) {
54+ case 'eval':
55+ evalNext();
56+ break;
57+ case 'reload':
58+ location.reload();
59+ break;
60+ }
61+ };
62+ };
63+};
purescript.cabal+43−15
@@ -1,5 +1,5 @@
1name: purescript
1name: purescript
2−version: 0.9.0
2+version: 0.9.2
3cabal-version: >=1.8
3cabal-version: >=1.8
4build-type: Simple
4build-type: Simple
5license: MIT
5license: MIT
@@ -20,6 +20,7 @@ author: Phil Freeman <paf31@cantab.net>,
20tested-with: GHC==7.10.3
20tested-with: GHC==7.10.3
21
21
22extra-source-files: examples/passing/*.purs
22extra-source-files: examples/passing/*.purs
23+ , examples/passing/*.js
23 , examples/passing/2018/*.purs
24 , examples/passing/2018/*.purs
24 , examples/passing/2138/*.purs
25 , examples/passing/2138/*.purs
25 , examples/passing/ClassRefSyntax/*.purs
26 , examples/passing/ClassRefSyntax/*.purs
@@ -59,6 +60,12 @@ extra-source-files: examples/passing/*.purs
59 , examples/failing/ConflictingImports2/*.purs
60 , examples/failing/ConflictingImports2/*.purs
60 , examples/failing/ConflictingQualifiedImports/*.purs
61 , examples/failing/ConflictingQualifiedImports/*.purs
61 , examples/failing/ConflictingQualifiedImports2/*.purs
62 , examples/failing/ConflictingQualifiedImports2/*.purs
63+ , examples/failing/ExportConflictClass/*.purs
64+ , examples/failing/ExportConflictCtor/*.purs
65+ , examples/failing/ExportConflictType/*.purs
66+ , examples/failing/ExportConflictTypeOp/*.purs
67+ , examples/failing/ExportConflictValue/*.purs
68+ , examples/failing/ExportConflictValueOp/*.purs
62 , examples/failing/ExportExplicit1/*.purs
69 , examples/failing/ExportExplicit1/*.purs
63 , examples/failing/ExportExplicit3/*.purs
70 , examples/failing/ExportExplicit3/*.purs
64 , examples/failing/ImportExplicit/*.purs
71 , examples/failing/ImportExplicit/*.purs
@@ -67,12 +74,13 @@ extra-source-files: examples/passing/*.purs
67 , examples/failing/ImportModule/*.purs
74 , examples/failing/ImportModule/*.purs
68 , examples/failing/InstanceExport/*.purs
75 , examples/failing/InstanceExport/*.purs
69 , examples/failing/OrphanInstance/*.purs
76 , examples/failing/OrphanInstance/*.purs
70− , examples/failing/OverlappingReExport/*.purs
71 , examples/warning/*.purs
77 , examples/warning/*.purs
72 , examples/warning/*.js
78 , examples/warning/*.js
73 , examples/docs/bower_components/purescript-prelude/src/*.purs
79 , examples/docs/bower_components/purescript-prelude/src/*.purs
74 , examples/docs/bower.json
80 , examples/docs/bower.json
75 , examples/docs/src/*.purs
81 , examples/docs/src/*.purs
82+ , psci/static/index.html
83+ , psci/static/index.js
76 , tests/support/package.json
84 , tests/support/package.json
77 , tests/support/bower.json
85 , tests/support/bower.json
78 , tests/support/setup-win.cmd
86 , tests/support/setup-win.cmd
@@ -95,11 +103,13 @@ library
95 build-depends: base >=4.8 && <5,
103 build-depends: base >=4.8 && <5,
96 aeson >= 0.8 && < 0.12,
104 aeson >= 0.8 && < 0.12,
97 aeson-better-errors >= 0.8,
105 aeson-better-errors >= 0.8,
106+ ansi-terminal >= 0.6.2 && < 0.7,
98 base-compat >=0.6.0,
107 base-compat >=0.6.0,
99 bower-json >= 0.8,
108 bower-json >= 0.8,
100 boxes >= 0.1.4 && < 0.2.0,
109 boxes >= 0.1.4 && < 0.2.0,
101 bytestring -any,
110 bytestring -any,
102 containers -any,
111 containers -any,
112+ clock -any,
103 directory >= 1.2,
113 directory >= 1.2,
104 dlist -any,
114 dlist -any,
105 edit-distance -any,
115 edit-distance -any,
@@ -116,9 +126,10 @@ library
116 parallel >= 3.2 && < 3.3,
126 parallel >= 3.2 && < 3.3,
117 parsec >=3.1.10,
127 parsec >=3.1.10,
118 pattern-arrows >= 0.0.2 && < 0.1,
128 pattern-arrows >= 0.0.2 && < 0.1,
119− pipes >= 4.0.0 && < 4.2.0,
129+ pipes >= 4.0.0 && < 4.3.0,
120 pipes-http -any,
130 pipes-http -any,
121 process >= 1.2.0 && < 1.5,
131 process >= 1.2.0 && < 1.5,
132+ protolude >= 0.1.5,
122 regex-tdfa -any,
133 regex-tdfa -any,
123 safe >= 0.3.9 && < 0.4,
134 safe >= 0.3.9 && < 0.4,
124 semigroups >= 0.16.2 && < 0.19,
135 semigroups >= 0.16.2 && < 0.19,
@@ -260,22 +271,23 @@ library
260 Language.PureScript.Publish.BoxesHelpers
271 Language.PureScript.Publish.BoxesHelpers
261
272
262 Language.PureScript.Ide
273 Language.PureScript.Ide
274+ Language.PureScript.Ide.CaseSplit
263 Language.PureScript.Ide.Command
275 Language.PureScript.Ide.Command
276+ Language.PureScript.Ide.Completion
277+ Language.PureScript.Ide.Conversions
264 Language.PureScript.Ide.Externs
278 Language.PureScript.Ide.Externs
265 Language.PureScript.Ide.Error
279 Language.PureScript.Ide.Error
266− Language.PureScript.Ide.Pursuit
280+ Language.PureScript.Ide.Imports
267− Language.PureScript.Ide.Completion
268− Language.PureScript.Ide.Matcher
269 Language.PureScript.Ide.Filter
281 Language.PureScript.Ide.Filter
270− Language.PureScript.Ide.Types
282+ Language.PureScript.Ide.Matcher
271− Language.PureScript.Ide.State
283+ Language.PureScript.Ide.Pursuit
272− Language.PureScript.Ide.CaseSplit
284+ Language.PureScript.Ide.Rebuild
273− Language.PureScript.Ide.SourceFile
274− Language.PureScript.Ide.Watcher
275 Language.PureScript.Ide.Reexports
285 Language.PureScript.Ide.Reexports
276− Language.PureScript.Ide.Imports
286+ Language.PureScript.Ide.SourceFile
287+ Language.PureScript.Ide.State
288+ Language.PureScript.Ide.Types
277 Language.PureScript.Ide.Util
289 Language.PureScript.Ide.Util
278− Language.PureScript.Ide.Rebuild
290+ Language.PureScript.Ide.Watcher
279
291
280 Language.PureScript.Interactive
292 Language.PureScript.Interactive
281 Language.PureScript.Interactive.Types
293 Language.PureScript.Interactive.Types
@@ -319,6 +331,7 @@ executable psc
319 build-depends: base >=4 && <5,
331 build-depends: base >=4 && <5,
320 purescript -any,
332 purescript -any,
321 aeson >= 0.8 && < 0.12,
333 aeson >= 0.8 && < 0.12,
334+ ansi-terminal >= 0.6.2 && < 0.7,
322 base-compat >=0.6.0,
335 base-compat >=0.6.0,
323 bytestring -any,
336 bytestring -any,
324 containers -any,
337 containers -any,
@@ -343,18 +356,27 @@ executable psci
343 purescript -any,
356 purescript -any,
344 base-compat >=0.6.0,
357 base-compat >=0.6.0,
345 boxes >= 0.1.4 && < 0.2.0,
358 boxes >= 0.1.4 && < 0.2.0,
359+ bytestring -any,
346 containers -any,
360 containers -any,
347 directory -any,
361 directory -any,
348 filepath -any,
362 filepath -any,
363+ file-embed -any,
349 Glob -any,
364 Glob -any,
350 haskeline >= 0.7.0.0,
365 haskeline >= 0.7.0.0,
366+ http-types == 0.9.*,
351 mtl -any,
367 mtl -any,
352 optparse-applicative >= 0.12.1,
368 optparse-applicative >= 0.12.1,
353 parsec -any,
369 parsec -any,
354 process -any,
370 process -any,
371+ stm >= 0.2.4.0,
372+ text -any,
355 time -any,
373 time -any,
356 transformers -any,
374 transformers -any,
357− transformers-compat -any
375+ transformers-compat -any,
376+ wai == 3.*,
377+ wai-websockets == 3.*,
378+ warp == 3.*,
379+ websockets >= 0.9 && <0.10
358 main-is: Main.hs
380 main-is: Main.hs
359 buildable: True
381 buildable: True
360 hs-source-dirs: psci
382 hs-source-dirs: psci
@@ -433,6 +455,8 @@ executable psc-ide-server
433 other-modules: Paths_purescript
455 other-modules: Paths_purescript
434 other-extensions:
456 other-extensions:
435 build-depends: base >=4 && <5,
457 build-depends: base >=4 && <5,
458+ aeson >= 0.8 && < 0.12,
459+ bytestring -any,
436 purescript -any,
460 purescript -any,
437 base-compat >=0.6.0,
461 base-compat >=0.6.0,
438 directory -any,
462 directory -any,
@@ -441,6 +465,7 @@ executable psc-ide-server
441 mtl -any,
465 mtl -any,
442 network -any,
466 network -any,
443 optparse-applicative >= 0.12.1,
467 optparse-applicative >= 0.12.1,
468+ protolude >= 0.1.5,
444 stm -any,
469 stm -any,
445 text -any,
470 text -any,
446 transformers -any,
471 transformers -any,
@@ -454,6 +479,7 @@ executable psc-ide-client
454 other-extensions:
479 other-extensions:
455 build-depends: base >=4 && <5,
480 build-depends: base >=4 && <5,
456 base-compat >=0.6.0,
481 base-compat >=0.6.0,
482+ bytestring -any,
457 mtl -any,
483 mtl -any,
458 network -any,
484 network -any,
459 optparse-applicative >= 0.12.1,
485 optparse-applicative >= 0.12.1,
@@ -506,6 +532,7 @@ test-suite tests
506 optparse-applicative -any,
532 optparse-applicative -any,
507 parsec -any,
533 parsec -any,
508 process -any,
534 process -any,
535+ protolude >= 0.1.5,
509 silently -any,
536 silently -any,
510 stm -any,
537 stm -any,
511 text -any,
538 text -any,
@@ -531,7 +558,8 @@ test-suite tests
531 Language.PureScript.Ide.MatcherSpec
558 Language.PureScript.Ide.MatcherSpec
532 Language.PureScript.Ide.RebuildSpec
559 Language.PureScript.Ide.RebuildSpec
533 Language.PureScript.Ide.ReexportsSpec
560 Language.PureScript.Ide.ReexportsSpec
534− Language.PureScript.IdeSpec
561+ Language.PureScript.Ide.SourceFile.IntegrationSpec
562+ Language.PureScript.Ide.SourceFileSpec
535 buildable: True
563 buildable: True
536 hs-source-dirs: tests
564 hs-source-dirs: tests
537
565
src/Language/PureScript/AST/Declarations.hs+15−6
@@ -80,19 +80,25 @@ data DeclarationRef
80 --
80 --
81 | ModuleRef ModuleName
81 | ModuleRef ModuleName
82 -- |
82 -- |
83+ -- A value re-exported from another module. These will be inserted during
84+ -- elaboration in name desugaring.
85+ --
86+ | ReExportRef ModuleName DeclarationRef
87+ -- |
83 -- A declaration reference with source position information
88 -- A declaration reference with source position information
84 --
89 --
85 | PositionedDeclarationRef SourceSpan [Comment] DeclarationRef
90 | PositionedDeclarationRef SourceSpan [Comment] DeclarationRef
86 deriving (Show, Read)
91 deriving (Show, Read)
87
92
88instance Eq DeclarationRef where
93instance Eq DeclarationRef where
89− (TypeRef name dctors) == (TypeRef name' dctors') = name == name' && dctors == dctors'
94+ (TypeRef name dctors) == (TypeRef name' dctors') = name == name' && dctors == dctors'
90− (TypeOpRef name) == (TypeOpRef name') = name == name'
95+ (TypeOpRef name) == (TypeOpRef name') = name == name'
91− (ValueRef name) == (ValueRef name') = name == name'
96+ (ValueRef name) == (ValueRef name') = name == name'
92− (ValueOpRef name) == (ValueOpRef name') = name == name'
97+ (ValueOpRef name) == (ValueOpRef name') = name == name'
93− (TypeClassRef name) == (TypeClassRef name') = name == name'
98+ (TypeClassRef name) == (TypeClassRef name') = name == name'
94 (TypeInstanceRef name) == (TypeInstanceRef name') = name == name'
99 (TypeInstanceRef name) == (TypeInstanceRef name') = name == name'
95− (ModuleRef name) == (ModuleRef name') = name == name'
100+ (ModuleRef name) == (ModuleRef name') = name == name'
101+ (ReExportRef mn ref) == (ReExportRef mn' ref') = mn == mn' && ref == ref'
96 (PositionedDeclarationRef _ _ r) == r' = r == r'
102 (PositionedDeclarationRef _ _ r) == r' = r == r'
97 r == (PositionedDeclarationRef _ _ r') = r == r'
103 r == (PositionedDeclarationRef _ _ r') = r == r'
98 _ == _ = False
104 _ == _ = False
@@ -218,7 +224,10 @@ data ValueFixity = ValueFixity Fixity (Qualified (Either Ident (ProperName 'Cons
218data TypeFixity = TypeFixity Fixity (Qualified (ProperName 'TypeName)) (OpName 'TypeOpName)
224data TypeFixity = TypeFixity Fixity (Qualified (ProperName 'TypeName)) (OpName 'TypeOpName)
219 deriving (Eq, Ord, Show, Read)
225 deriving (Eq, Ord, Show, Read)
220
226
227+pattern ValueFixityDeclaration :: Fixity -> Qualified (Either Ident (ProperName 'ConstructorName)) -> OpName 'ValueOpName -> Declaration
221pattern ValueFixityDeclaration fixity name op = FixityDeclaration (Left (ValueFixity fixity name op))
228pattern ValueFixityDeclaration fixity name op = FixityDeclaration (Left (ValueFixity fixity name op))
229+
230+pattern TypeFixityDeclaration :: Fixity -> Qualified (ProperName 'TypeName) -> OpName 'TypeOpName -> Declaration
222pattern TypeFixityDeclaration fixity name op = FixityDeclaration (Right (TypeFixity fixity name op))
231pattern TypeFixityDeclaration fixity name op = FixityDeclaration (Right (TypeFixity fixity name op))
223
232
224-- | The members of a type class instance declaration
233-- | The members of a type class instance declaration
src/Language/PureScript/Bundle.hs+39−4
@@ -6,6 +6,7 @@
6-- and generates the final Javascript bundle.
6-- and generates the final Javascript bundle.
7module Language.PureScript.Bundle
7module Language.PureScript.Bundle
8 ( bundle
8 ( bundle
9+ , guessModuleIdentifier
9 , ModuleIdentifier(..)
10 , ModuleIdentifier(..)
10 , moduleName
11 , moduleName
11 , ModuleType(..)
12 , ModuleType(..)
@@ -19,6 +20,7 @@ import Prelude.Compat
19import Control.Monad
20import Control.Monad
20import Control.Monad.Error.Class
21import Control.Monad.Error.Class
21
22
23+import Data.Char (chr, digitToInt)
22import Data.Generics (everything, everywhere, mkQ, mkT)
24import Data.Generics (everything, everywhere, mkQ, mkT)
23import Data.Graph
25import Data.Graph
24import Data.List (nub, stripPrefix)
26import Data.List (nub, stripPrefix)
@@ -31,6 +33,8 @@ import Language.JavaScript.Parser.AST
31
33
32import qualified Paths_purescript as Paths
34import qualified Paths_purescript as Paths
33
35
36+import System.FilePath (takeFileName, takeDirectory)
37+
34-- | The type of error messages. We separate generation and rendering of errors using a data
38-- | The type of error messages. We separate generation and rendering of errors using a data
35-- type, in case we need to match on error types later.
39-- type, in case we need to match on error types later.
36data ErrorMessage
40data ErrorMessage
@@ -57,6 +61,14 @@ data ModuleIdentifier = ModuleIdentifier String ModuleType deriving (Show, Read,
57moduleName :: ModuleIdentifier -> String
61moduleName :: ModuleIdentifier -> String
58moduleName (ModuleIdentifier name _) = name
62moduleName (ModuleIdentifier name _) = name
59
63
64+-- | Given a filename, assuming it is in the correct place on disk, infer a ModuleIdentifier.
65+guessModuleIdentifier :: MonadError ErrorMessage m => FilePath -> m ModuleIdentifier
66+guessModuleIdentifier filename = ModuleIdentifier (takeFileName (takeDirectory filename)) <$> guessModuleType (takeFileName filename)
67+ where
68+ guessModuleType "index.js" = pure Regular
69+ guessModuleType "foreign.js" = pure Foreign
70+ guessModuleType name = throwError $ UnsupportedModulePath name
71+
60-- | A piece of code is identified by its module and its name. These keys are used to label vertices
72-- | A piece of code is identified by its module and its name. These keys are used to label vertices
61-- in the dependency graph.
73-- in the dependency graph.
62type Key = (ModuleIdentifier, String)
74type Key = (ModuleIdentifier, String)
@@ -186,11 +198,34 @@ withDeps (Module modulePath es) = Module modulePath (map expandDeps es)
186
198
187-- String literals include the quote chars
199-- String literals include the quote chars
188fromStringLiteral :: JSExpression -> Maybe String
200fromStringLiteral :: JSExpression -> Maybe String
189−fromStringLiteral (JSStringLiteral _ str) = Just $ trimStringQuotes str
201+fromStringLiteral (JSStringLiteral _ str) = Just $ strValue str
190fromStringLiteral _ = Nothing
202fromStringLiteral _ = Nothing
191
203
192−trimStringQuotes :: String -> String
204+strValue :: String -> String
193−trimStringQuotes str = reverse $ drop 1 $ reverse $ drop 1 $ str
205+strValue str = go $ drop 1 str
206+ where
207+ go ('\\' : 'b' : xs) = '\b' : go xs
208+ go ('\\' : 'f' : xs) = '\f' : go xs
209+ go ('\\' : 'n' : xs) = '\n' : go xs
210+ go ('\\' : 'r' : xs) = '\r' : go xs
211+ go ('\\' : 't' : xs) = '\t' : go xs
212+ go ('\\' : 'v' : xs) = '\v' : go xs
213+ go ('\\' : '0' : xs) = '\0' : go xs
214+ go ('\\' : 'x' : a : b : xs) = chr (a' + b') : go xs
215+ where
216+ a' = 16 * digitToInt a
217+ b' = digitToInt b
218+ go ('\\' : 'u' : a : b : c : d : xs) = chr (a' + b' + c' + d') : go xs
219+ where
220+ a' = 16 * 16 * 16 * digitToInt a
221+ b' = 16 * 16 * digitToInt b
222+ c' = 16 * digitToInt c
223+ d' = digitToInt d
224+ go ('\\' : x : xs) = x : go xs
225+ go "\"" = ""
226+ go "'" = ""
227+ go (x : xs) = x : go xs
228+ go "" = ""
194
229
195commaList :: JSCommaList a -> [a]
230commaList :: JSCommaList a -> [a]
196commaList JSLNil = []
231commaList JSLNil = []
@@ -332,7 +367,7 @@ matchExportsAssignment stmt
332 = Nothing
367 = Nothing
333
368
334extractLabel :: JSPropertyName -> Maybe String
369extractLabel :: JSPropertyName -> Maybe String
335−extractLabel (JSPropertyString _ nm) = Just (trimStringQuotes nm)
370+extractLabel (JSPropertyString _ nm) = Just $ strValue nm
336extractLabel (JSPropertyIdent _ nm) = Just nm
371extractLabel (JSPropertyIdent _ nm) = Just nm
337extractLabel _ = Nothing
372extractLabel _ = Nothing
338
373
src/Language/PureScript/CodeGen/JS/Optimizer.hs+2−2
@@ -39,12 +39,12 @@ import qualified Language.PureScript.Constants as C
39-- |
39-- |
40-- Apply a series of optimizer passes to simplified Javascript code
40-- Apply a series of optimizer passes to simplified Javascript code
41--
41--
42−optimize :: (Monad m, MonadReader Options m, MonadSupply m) => JS -> m JS
42+optimize :: (MonadReader Options m, MonadSupply m) => JS -> m JS
43optimize js = do
43optimize js = do
44 noOpt <- asks optionsNoOptimizations
44 noOpt <- asks optionsNoOptimizations
45 if noOpt then return js else optimize' js
45 if noOpt then return js else optimize' js
46
46
47−optimize' :: (Monad m, MonadReader Options m, MonadSupply m) => JS -> m JS
47+optimize' :: (MonadReader Options m, MonadSupply m) => JS -> m JS
48optimize' js = do
48optimize' js = do
49 opts <- ask
49 opts <- ask
50 js' <- untilFixedPoint (inlineFnComposition . tidyUp . applyAll
50 js' <- untilFixedPoint (inlineFnComposition . tidyUp . applyAll
src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs+1−1
@@ -216,7 +216,7 @@ inlineCommonOperators = applyAll $
216
216
217 isNFn :: String -> Int -> JS -> Bool
217 isNFn :: String -> Int -> JS -> Bool
218 isNFn prefix n (JSVar _ name) = name == (prefix ++ show n)
218 isNFn prefix n (JSVar _ name) = name == (prefix ++ show n)
219− isNFn prefix n (JSAccessor _ name (JSVar _ dataFunction)) | dataFunction == C.dataFunction = name == (prefix ++ show n)
219+ isNFn prefix n (JSAccessor _ name (JSVar _ dataFunctionUncurried)) | dataFunctionUncurried == C.dataFunctionUncurried = name == (prefix ++ show n)
220 isNFn _ _ _ = False
220 isNFn _ _ _ = False
221
221
222 runFn :: Int -> JS -> JS
222 runFn :: Int -> JS -> JS
src/Language/PureScript/Constants.hs+6
@@ -327,6 +327,9 @@ partial = "Partial"
327pattern Partial :: Qualified (ProperName 'ClassName)
327pattern Partial :: Qualified (ProperName 'ClassName)
328pattern Partial = Qualified (Just (ModuleName [ProperName "Prim"])) (ProperName "Partial")
328pattern Partial = Qualified (Just (ModuleName [ProperName "Prim"])) (ProperName "Partial")
329
329
330+pattern Fail :: Qualified (ProperName 'ClassName)
331+pattern Fail = Qualified (Just (ModuleName [ProperName "Prim"])) (ProperName "Fail")
332+
330-- Code Generation
333-- Code Generation
331
334
332__superclass_ :: String
335__superclass_ :: String
@@ -388,5 +391,8 @@ dataEuclideanRing = "Data_EuclideanRing"
388dataFunction :: String
391dataFunction :: String
389dataFunction = "Data_Function"
392dataFunction = "Data_Function"
390
393
394+dataFunctionUncurried :: String
395+dataFunctionUncurried = "Data_Function_Uncurried"
396+
391dataIntBits :: String
397dataIntBits :: String
392dataIntBits = "Data_Int_Bits"
398dataIntBits = "Data_Int_Bits"
src/Language/PureScript/Docs/ParseAndBookmark.hs+1−1
@@ -44,7 +44,7 @@ parseAndBookmark inputFiles depsFiles = do
44 addBookmarks <$> parseFiles (inputFiles' ++ depsFiles')
44 addBookmarks <$> parseFiles (inputFiles' ++ depsFiles')
45
45
46parseFiles ::
46parseFiles ::
47− (MonadError P.MultipleErrors m, MonadIO m) =>
47+ (MonadError P.MultipleErrors m) =>
48 [(FileInfo, FilePath)]
48 [(FileInfo, FilePath)]
49 -> m [(FileInfo, P.Module)]
49 -> m [(FileInfo, P.Module)]
50parseFiles =
50parseFiles =
src/Language/PureScript/Environment.hs+4−1
@@ -240,6 +240,7 @@ primTypes =
240 , (primName "Int", (Star, ExternData))
240 , (primName "Int", (Star, ExternData))
241 , (primName "Boolean", (Star, ExternData))
241 , (primName "Boolean", (Star, ExternData))
242 , (primName "Partial", (Star, ExternData))
242 , (primName "Partial", (Star, ExternData))
243+ , (primName "Fail", (FunKind Symbol Star, ExternData))
243 ]
244 ]
244
245
245-- |
246-- |
@@ -249,7 +250,9 @@ primTypes =
249primClasses :: M.Map (Qualified (ProperName 'ClassName)) ([(String, Maybe Kind)], [(Ident, Type)], [Constraint])
250primClasses :: M.Map (Qualified (ProperName 'ClassName)) ([(String, Maybe Kind)], [(Ident, Type)], [Constraint])
250primClasses =
251primClasses =
251 M.fromList
252 M.fromList
252− [ (primName "Partial", ([], [], [])) ]
253+ [ (primName "Partial", ([], [], []))
254+ , (primName "Fail", ([("message", Just Symbol)], [], []))
255+ ]
253
256
254-- |
257-- |
255-- Finds information about data constructors from the current environment.
258-- Finds information about data constructors from the current environment.
src/Language/PureScript/Errors.hs+285−226
@@ -15,7 +15,7 @@ import Data.Char (isSpace)
15import Data.Either (lefts, rights)
15import Data.Either (lefts, rights)
16import Data.Foldable (fold)
16import Data.Foldable (fold)
17import Data.List (intercalate, transpose, nub, nubBy, sortBy, partition)
17import Data.List (intercalate, transpose, nub, nubBy, sortBy, partition)
18−import Data.Maybe (maybeToList)
18+import Data.Maybe (maybeToList, fromMaybe, mapMaybe)
19import Data.Ord (comparing)
19import Data.Ord (comparing)
20import qualified Data.Map as M
20import qualified Data.Map as M
21
21
@@ -26,9 +26,12 @@ import Language.PureScript.Names
26import Language.PureScript.Pretty
26import Language.PureScript.Pretty
27import Language.PureScript.Traversals
27import Language.PureScript.Traversals
28import Language.PureScript.Types
28import Language.PureScript.Types
29+import Language.PureScript.Pretty.Common (endWith)
29import qualified Language.PureScript.Bundle as Bundle
30import qualified Language.PureScript.Bundle as Bundle
30import qualified Language.PureScript.Constants as C
31import qualified Language.PureScript.Constants as C
31
32
33+import qualified System.Console.ANSI as ANSI
34+
32import qualified Text.Parsec as P
35import qualified Text.Parsec as P
33import qualified Text.Parsec.Error as PE
36import qualified Text.Parsec.Error as PE
34import qualified Text.PrettyPrint.Boxes as Box
37import qualified Text.PrettyPrint.Boxes as Box
@@ -62,17 +65,9 @@ data SimpleErrorMessage
62 | UnknownExportDataConstructor (ProperName 'TypeName) (ProperName 'ConstructorName)
65 | UnknownExportDataConstructor (ProperName 'TypeName) (ProperName 'ConstructorName)
63 | ScopeConflict Name [ModuleName]
66 | ScopeConflict Name [ModuleName]
64 | ScopeShadowing Name (Maybe ModuleName) [ModuleName]
67 | ScopeShadowing Name (Maybe ModuleName) [ModuleName]
65− | ConflictingTypeDecls (ProperName 'TypeName)
68+ | DeclConflict Name Name
66− | ConflictingCtorDecls (ProperName 'ConstructorName)
69+ | ExportConflict (Qualified Name) (Qualified Name)
67− | TypeConflictsWithClass (ProperName 'TypeName)
68− | CtorConflictsWithClass (ProperName 'ConstructorName)
69− | ClassConflictsWithType (ProperName 'ClassName)
70− | ClassConflictsWithCtor (ProperName 'ClassName)
71 | DuplicateModuleName ModuleName
70 | DuplicateModuleName ModuleName
72− | DuplicateClassExport (ProperName 'ClassName)
73− | DuplicateValueExport Ident
74− | DuplicateValueOpExport (OpName 'ValueOpName)
75− | DuplicateTypeOpExport (OpName 'TypeOpName)
76 | DuplicateTypeArgument String
71 | DuplicateTypeArgument String
77 | InvalidDoBind
72 | InvalidDoBind
78 | InvalidDoLet
73 | InvalidDoLet
@@ -231,17 +226,9 @@ errorCode em = case unwrapErrorMessage em of
231 UnknownExportDataConstructor{} -> "UnknownExportDataConstructor"
226 UnknownExportDataConstructor{} -> "UnknownExportDataConstructor"
232 ScopeConflict{} -> "ScopeConflict"
227 ScopeConflict{} -> "ScopeConflict"
233 ScopeShadowing{} -> "ScopeShadowing"
228 ScopeShadowing{} -> "ScopeShadowing"
234− ConflictingTypeDecls{} -> "ConflictingTypeDecls"
229+ DeclConflict{} -> "DeclConflict"
235− ConflictingCtorDecls{} -> "ConflictingCtorDecls"
230+ ExportConflict{} -> "ExportConflict"
236− TypeConflictsWithClass{} -> "TypeConflictsWithClass"
237− CtorConflictsWithClass{} -> "CtorConflictsWithClass"
238− ClassConflictsWithType{} -> "ClassConflictsWithType"
239− ClassConflictsWithCtor{} -> "ClassConflictsWithCtor"
240 DuplicateModuleName{} -> "DuplicateModuleName"
231 DuplicateModuleName{} -> "DuplicateModuleName"
241− DuplicateClassExport{} -> "DuplicateClassExport"
242− DuplicateValueExport{} -> "DuplicateValueExport"
243− DuplicateValueOpExport{} -> "DuplicateValueOpExport"
244− DuplicateTypeOpExport{} -> "DuplicateTypeOpExport"
245 DuplicateTypeArgument{} -> "DuplicateTypeArgument"
232 DuplicateTypeArgument{} -> "DuplicateTypeArgument"
246 InvalidDoBind -> "InvalidDoBind"
233 InvalidDoBind -> "InvalidDoBind"
247 InvalidDoLet -> "InvalidDoLet"
234 InvalidDoLet -> "InvalidDoLet"
@@ -435,7 +422,7 @@ errorSuggestion err = case err of
435
422
436 importSuggestion :: ModuleName -> [ DeclarationRef ] -> Maybe ModuleName -> String
423 importSuggestion :: ModuleName -> [ DeclarationRef ] -> Maybe ModuleName -> String
437 importSuggestion mn refs qual =
424 importSuggestion mn refs qual =
438− "import " ++ runModuleName mn ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ")" ++ qstr qual
425+ "import " ++ runModuleName mn ++ " (" ++ intercalate ", " (mapMaybe prettyPrintRef refs) ++ ")" ++ qstr qual
439
426
440 qstr :: Maybe ModuleName -> String
427 qstr :: Maybe ModuleName -> String
441 qstr (Just mn) = " as " ++ runModuleName mn
428 qstr (Just mn) = " as " ++ runModuleName mn
@@ -457,15 +444,65 @@ showSuggestion suggestion = case errorSuggestion suggestion of
457 Just (ErrorSuggestion x) -> x
444 Just (ErrorSuggestion x) -> x
458 _ -> ""
445 _ -> ""
459
446
447+ansiColor :: (ANSI.ColorIntensity, ANSI.Color) -> String
448+ansiColor (intesity, color) =
449+ ANSI.setSGRCode [ANSI.SetColor ANSI.Foreground intesity color]
450+
451+ansiColorReset :: String
452+ansiColorReset =
453+ ANSI.setSGRCode [ANSI.Reset]
454+
455+colorCode :: Maybe (ANSI.ColorIntensity, ANSI.Color) -> String -> String
456+colorCode codeColor code = case codeColor of
457+ Nothing -> code
458+ Just cc -> concat [ansiColor cc, code, ansiColorReset]
459+
460+colorCodeBox :: Maybe (ANSI.ColorIntensity, ANSI.Color) -> Box.Box -> Box.Box
461+colorCodeBox codeColor b = case codeColor of
462+ Nothing -> b
463+ Just cc
464+ | Box.rows b == 1 ->
465+ Box.text (ansiColor cc) Box.<> b `endWith` Box.text ansiColorReset
466+
467+ | otherwise -> Box.hcat Box.left -- making two boxes, one for each side of the box so that it will set each row it's own color and will reset it afterwards
468+ [ Box.vcat Box.top $ replicate (Box.rows b) $ Box.text $ ansiColor cc
469+ , b
470+ , Box.vcat Box.top $ replicate (Box.rows b) $ Box.text ansiColorReset
471+ ]
472+
473+
474+-- | Default color intesity and color for code
475+defaultCodeColor :: (ANSI.ColorIntensity, ANSI.Color)
476+defaultCodeColor = (ANSI.Dull, ANSI.Yellow)
477+
478+-- | `prettyPrintSingleError` Options
479+data PPEOptions = PPEOptions
480+ { ppeCodeColor :: Maybe (ANSI.ColorIntensity, ANSI.Color) -- ^ Color code with this color... or not
481+ , ppeFull :: Bool -- ^ Should write a full error message?
482+ , ppeLevel :: Level -- ^ Should this report an error or a warning?
483+ , ppeShowWiki :: Bool -- ^ Should show a link to error message's wiki page?
484+ }
485+
486+-- | Default options for PPEOptions
487+defaultPPEOptions :: PPEOptions
488+defaultPPEOptions = PPEOptions
489+ { ppeCodeColor = Just defaultCodeColor
490+ , ppeFull = False
491+ , ppeLevel = Error
492+ , ppeShowWiki = True
493+ }
494+
495+
460-- |
496-- |
461-- Pretty print a single error, simplifying if necessary
497-- Pretty print a single error, simplifying if necessary
462--
498--
463−prettyPrintSingleError :: Bool -> Level -> Bool -> ErrorMessage -> Box.Box
499+prettyPrintSingleError :: PPEOptions -> ErrorMessage -> Box.Box
464−prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap $ do
500+prettyPrintSingleError (PPEOptions codeColor full level showWiki) e = flip evalState defaultUnknownMap $ do
465 em <- onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
501 em <- onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
466 um <- get
502 um <- get
467 return (prettyPrintErrorMessage um em)
503 return (prettyPrintErrorMessage um em)
468 where
504 where
505+ (markCode, markCodeBox) = (colorCode &&& colorCodeBox) codeColor
469
506
470 -- Pretty print an ErrorMessage
507 -- Pretty print an ErrorMessage
471 prettyPrintErrorMessage :: TypeMap -> ErrorMessage -> Box.Box
508 prettyPrintErrorMessage :: TypeMap -> ErrorMessage -> Box.Box
@@ -474,9 +511,10 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
474 [ foldr renderHint (indent (renderSimpleErrorMessage simple)) hints
511 [ foldr renderHint (indent (renderSimpleErrorMessage simple)) hints
475 ] ++
512 ] ++
476 maybe [] (return . Box.moveDown 1) typeInformation ++
513 maybe [] (return . Box.moveDown 1) typeInformation ++
514+ [ Box.moveDown 1 $ paras
477− [ Box.moveDown 1 $ paras [ line $ "See " ++ wikiUri e ++ " for more information, "
515+ [ line $ "See " ++ wikiUri e ++ " for more information, "
478− , line $ "or to contribute content related to this " ++ levelText ++ "."
516+ , line $ "or to contribute content related to this " ++ levelText ++ "."
479− ]
517+ ]
480 | showWiki
518 | showWiki
481 ]
519 ]
482 where
520 where
@@ -491,11 +529,11 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
491 skolemInfo :: (String, Int, Maybe SourceSpan) -> Box.Box
529 skolemInfo :: (String, Int, Maybe SourceSpan) -> Box.Box
492 skolemInfo (name, s, ss) =
530 skolemInfo (name, s, ss) =
493 paras $
531 paras $
494− line (name ++ show s ++ " is a rigid type variable")
532+ line (markCode (name ++ show s) ++ " is a rigid type variable")
495 : foldMap (return . line . (" bound at " ++) . displayStartEndPos) ss
533 : foldMap (return . line . (" bound at " ++) . displayStartEndPos) ss
496
534
497 unknownInfo :: Int -> Box.Box
535 unknownInfo :: Int -> Box.Box
498− unknownInfo u = line $ "t" ++ show u ++ " is an unknown type"
536+ unknownInfo u = line $ markCode ("t" ++ show u) ++ " is an unknown type"
499
537
500 renderSimpleErrorMessage :: SimpleErrorMessage -> Box.Box
538 renderSimpleErrorMessage :: SimpleErrorMessage -> Box.Box
501 renderSimpleErrorMessage (CannotGetFileInfo path) =
539 renderSimpleErrorMessage (CannotGetFileInfo path) =
@@ -520,29 +558,29 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
520 , prettyPrintParseError err
558 , prettyPrintParseError err
521 ]
559 ]
522 renderSimpleErrorMessage (MissingFFIModule mn) =
560 renderSimpleErrorMessage (MissingFFIModule mn) =
523− line $ "The foreign module implementation for module " ++ runModuleName mn ++ " is missing."
561+ line $ "The foreign module implementation for module " ++ markCode (runModuleName mn) ++ " is missing."
524 renderSimpleErrorMessage (UnnecessaryFFIModule mn path) =
562 renderSimpleErrorMessage (UnnecessaryFFIModule mn path) =
525− paras [ line $ "An unnecessary foreign module implementation was provided for module " ++ runModuleName mn ++ ": "
563+ paras [ line $ "An unnecessary foreign module implementation was provided for module " ++ markCode (runModuleName mn) ++ ": "
526 , indent . line $ path
564 , indent . line $ path
527− , line $ "Module " ++ runModuleName mn ++ " does not contain any foreign import declarations, so a foreign module is not necessary."
565+ , line $ "Module " ++ markCode (runModuleName mn) ++ " does not contain any foreign import declarations, so a foreign module is not necessary."
528 ]
566 ]
529 renderSimpleErrorMessage (MissingFFIImplementations mn idents) =
567 renderSimpleErrorMessage (MissingFFIImplementations mn idents) =
530− paras [ line $ "The following values are not defined in the foreign module for module " ++ runModuleName mn ++ ": "
568+ paras [ line $ "The following values are not defined in the foreign module for module " ++ markCode (runModuleName mn) ++ ": "
531 , indent . paras $ map (line . runIdent) idents
569 , indent . paras $ map (line . runIdent) idents
532 ]
570 ]
533 renderSimpleErrorMessage (UnusedFFIImplementations mn idents) =
571 renderSimpleErrorMessage (UnusedFFIImplementations mn idents) =
534− paras [ line $ "The following definitions in the foreign module for module " ++ runModuleName mn ++ " are unused: "
572+ paras [ line $ "The following definitions in the foreign module for module " ++ markCode (runModuleName mn) ++ " are unused: "
535 , indent . paras $ map (line . runIdent) idents
573 , indent . paras $ map (line . runIdent) idents
536 ]
574 ]
537 renderSimpleErrorMessage (InvalidFFIIdentifier mn ident) =
575 renderSimpleErrorMessage (InvalidFFIIdentifier mn ident) =
538− paras [ line $ "In the FFI module for " ++ runModuleName mn ++ ":"
576+ paras [ line $ "In the FFI module for " ++ markCode (runModuleName mn) ++ ":"
539 , indent . paras $
577 , indent . paras $
540− [ line $ "The identifier `" ++ ident ++ "` is not valid in PureScript."
578+ [ line $ "The identifier " ++ markCode ident ++ " is not valid in PureScript."
541 , line "Note that exported identifiers in FFI modules must be valid PureScript identifiers."
579 , line "Note that exported identifiers in FFI modules must be valid PureScript identifiers."
542 ]
580 ]
543 ]
581 ]
544 renderSimpleErrorMessage (MultipleFFIModules mn paths) =
582 renderSimpleErrorMessage (MultipleFFIModules mn paths) =
545− paras [ line $ "Multiple foreign module implementations have been provided for module " ++ runModuleName mn ++ ": "
583+ paras [ line $ "Multiple foreign module implementations have been provided for module " ++ markCode (runModuleName mn) ++ ": "
546 , indent . paras $ map line paths
584 , indent . paras $ map line paths
547 ]
585 ]
548 renderSimpleErrorMessage InvalidDoBind =
586 renderSimpleErrorMessage InvalidDoBind =
@@ -553,94 +591,78 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
553 line "The same name was used more than once in a let binding."
591 line "The same name was used more than once in a let binding."
554 renderSimpleErrorMessage (InfiniteType ty) =
592 renderSimpleErrorMessage (InfiniteType ty) =
555 paras [ line "An infinite type was inferred for an expression: "
593 paras [ line "An infinite type was inferred for an expression: "
556− , indent $ typeAsBox ty
594+ , markCodeBox $ indent $ typeAsBox ty
557 ]
595 ]
558 renderSimpleErrorMessage (InfiniteKind ki) =
596 renderSimpleErrorMessage (InfiniteKind ki) =
559 paras [ line "An infinite kind was inferred for a type: "
597 paras [ line "An infinite kind was inferred for a type: "
560− , indent $ line $ prettyPrintKind ki
598+ , indent $ line $ markCode $ prettyPrintKind ki
561 ]
599 ]
562 renderSimpleErrorMessage (MultipleValueOpFixities op) =
600 renderSimpleErrorMessage (MultipleValueOpFixities op) =
563− line $ "There are multiple fixity/precedence declarations for operator " ++ showOp op
601+ line $ "There are multiple fixity/precedence declarations for operator " ++ markCode (showOp op)
564 renderSimpleErrorMessage (MultipleTypeOpFixities op) =
602 renderSimpleErrorMessage (MultipleTypeOpFixities op) =
565− line $ "There are multiple fixity/precedence declarations for type operator " ++ showOp op
603+ line $ "There are multiple fixity/precedence declarations for type operator " ++ markCode (showOp op)
566 renderSimpleErrorMessage (OrphanTypeDeclaration nm) =
604 renderSimpleErrorMessage (OrphanTypeDeclaration nm) =
567− line $ "The type declaration for " ++ showIdent nm ++ " should be followed by its definition."
605+ line $ "The type declaration for " ++ markCode (showIdent nm) ++ " should be followed by its definition."
568 renderSimpleErrorMessage (RedefinedModule name filenames) =
606 renderSimpleErrorMessage (RedefinedModule name filenames) =
569− paras [ line ("The module " ++ runModuleName name ++ " has been defined multiple times:")
607+ paras [ line ("The module " ++ markCode (runModuleName name) ++ " has been defined multiple times:")
570 , indent . paras $ map (line . displaySourceSpan) filenames
608 , indent . paras $ map (line . displaySourceSpan) filenames
571 ]
609 ]
572 renderSimpleErrorMessage (RedefinedIdent name) =
610 renderSimpleErrorMessage (RedefinedIdent name) =
573− line $ "The value " ++ showIdent name ++ " has been defined multiple times"
611+ line $ "The value " ++ markCode (showIdent name) ++ " has been defined multiple times"
574 renderSimpleErrorMessage (UnknownName name) =
612 renderSimpleErrorMessage (UnknownName name) =
575 line $ "Unknown " ++ printName name
613 line $ "Unknown " ++ printName name
576 renderSimpleErrorMessage (UnknownImport mn name) =
614 renderSimpleErrorMessage (UnknownImport mn name) =
577− paras [ line $ "Cannot import " ++ printName (Qualified Nothing name) ++ " from module " ++ runModuleName mn
615+ paras [ line $ "Cannot import " ++ printName (Qualified Nothing name) ++ " from module " ++ markCode (runModuleName mn)
578 , line "It either does not exist or the module does not export it."
616 , line "It either does not exist or the module does not export it."
579 ]
617 ]
580 renderSimpleErrorMessage (UnknownImportDataConstructor mn tcon dcon) =
618 renderSimpleErrorMessage (UnknownImportDataConstructor mn tcon dcon) =
581− line $ "Module " ++ runModuleName mn ++ " does not export data constructor " ++ runProperName dcon ++ " for type " ++ runProperName tcon
619+ line $ "Module " ++ runModuleName mn ++ " does not export data constructor " ++ markCode (runProperName dcon) ++ " for type " ++ markCode (runProperName tcon)
582 renderSimpleErrorMessage (UnknownExport name) =
620 renderSimpleErrorMessage (UnknownExport name) =
583 line $ "Cannot export unknown " ++ printName (Qualified Nothing name)
621 line $ "Cannot export unknown " ++ printName (Qualified Nothing name)
584 renderSimpleErrorMessage (UnknownExportDataConstructor tcon dcon) =
622 renderSimpleErrorMessage (UnknownExportDataConstructor tcon dcon) =
585− line $ "Cannot export data constructor " ++ runProperName dcon ++ " for type " ++ runProperName tcon ++ ", as it has not been declared."
623+ line $ "Cannot export data constructor " ++ markCode (runProperName dcon) ++ " for type " ++ markCode (runProperName tcon) ++ ", as it has not been declared."
586 renderSimpleErrorMessage (ScopeConflict nm ms) =
624 renderSimpleErrorMessage (ScopeConflict nm ms) =
587 paras [ line $ "Conflicting definitions are in scope for " ++ printName (Qualified Nothing nm) ++ " from the following modules:"
625 paras [ line $ "Conflicting definitions are in scope for " ++ printName (Qualified Nothing nm) ++ " from the following modules:"
588− , indent $ paras $ map (line . runModuleName) ms
626+ , indent $ paras $ map (line . markCode . runModuleName) ms
589 ]
627 ]
590 renderSimpleErrorMessage (ScopeShadowing nm exmn ms) =
628 renderSimpleErrorMessage (ScopeShadowing nm exmn ms) =
591 paras [ line $ "Shadowed definitions are in scope for " ++ printName (Qualified Nothing nm) ++ " from the following open imports:"
629 paras [ line $ "Shadowed definitions are in scope for " ++ printName (Qualified Nothing nm) ++ " from the following open imports:"
592− , indent $ paras $ map (line . ("import " ++) . runModuleName) ms
630+ , indent $ paras $ map (line . markCode . ("import " ++) . runModuleName) ms
593 , line $ "These will be ignored and the " ++ case exmn of
631 , line $ "These will be ignored and the " ++ case exmn of
594− Just exmn' -> "declaration from " ++ runModuleName exmn' ++ " will be used."
632+ Just exmn' -> "declaration from " ++ markCode (runModuleName exmn') ++ " will be used."
595 Nothing -> "local declaration will be used."
633 Nothing -> "local declaration will be used."
596 ]
634 ]
597− renderSimpleErrorMessage (ConflictingTypeDecls nm) =
635+ renderSimpleErrorMessage (DeclConflict new existing) =
598− line $ "Conflicting type declarations for " ++ runProperName nm
636+ line $ "Declaration for " ++ printName (Qualified Nothing new) ++ " conflicts with an existing " ++ nameType existing ++ " of the same name."
599− renderSimpleErrorMessage (ConflictingCtorDecls nm) =
600− line $ "Conflicting data constructor declarations for " ++ runProperName nm
601− renderSimpleErrorMessage (TypeConflictsWithClass nm) =
602− line $ "Type " ++ runProperName nm ++ " conflicts with a type class declaration with the same name."
603− renderSimpleErrorMessage (CtorConflictsWithClass nm) =
604− line $ "Data constructor " ++ runProperName nm ++ " conflicts with a type class declaration with the same name."
605− renderSimpleErrorMessage (ClassConflictsWithType nm) =
637+ renderSimpleErrorMessage (ExportConflict new existing) =
606− line $ "Type class " ++ runProperName nm ++ " conflicts with a type declaration with the same name."
638+ line $ "Export for " ++ printName new ++ " conflicts with " ++ runName existing
607− renderSimpleErrorMessage (ClassConflictsWithCtor nm) =
608− line $ "Type class " ++ runProperName nm ++ " conflicts with a data constructor declaration with the same name."
609 renderSimpleErrorMessage (DuplicateModuleName mn) =
639 renderSimpleErrorMessage (DuplicateModuleName mn) =
610− line $ "Module " ++ runModuleName mn ++ " has been defined multiple times."
640+ line $ "Module " ++ markCode (runModuleName mn) ++ " has been defined multiple times."
611− renderSimpleErrorMessage (DuplicateClassExport nm) =
612− line $ "Duplicate export declaration for type class " ++ runProperName nm
613− renderSimpleErrorMessage (DuplicateValueExport nm) =
614− line $ "Duplicate export declaration for value " ++ showIdent nm
615− renderSimpleErrorMessage (DuplicateValueOpExport op) =
616− line $ "Duplicate export declaration for operator " ++ showOp op
617− renderSimpleErrorMessage (DuplicateTypeOpExport op) =
618− line $ "Duplicate export declaration for type operator " ++ showOp op
619 renderSimpleErrorMessage (CycleInDeclaration nm) =
641 renderSimpleErrorMessage (CycleInDeclaration nm) =
620− line $ "The value of " ++ showIdent nm ++ " is undefined here, so this reference is not allowed."
642+ line $ "The value of " ++ markCode (showIdent nm) ++ " is undefined here, so this reference is not allowed."
621 renderSimpleErrorMessage (CycleInModules mns) =
643 renderSimpleErrorMessage (CycleInModules mns) =
622 paras [ line "There is a cycle in module dependencies in these modules: "
644 paras [ line "There is a cycle in module dependencies in these modules: "
623− , indent $ paras (map (line . runModuleName) mns)
645+ , indent $ paras (map (line . markCode . runModuleName) mns)
624 ]
646 ]
625 renderSimpleErrorMessage (CycleInTypeSynonym name) =
647 renderSimpleErrorMessage (CycleInTypeSynonym name) =
626 paras [ line $ case name of
648 paras [ line $ case name of
627− Just pn -> "A cycle appears in the definition of type synonym " ++ runProperName pn
649+ Just pn -> "A cycle appears in the definition of type synonym " ++ markCode (runProperName pn)
628 Nothing -> "A cycle appears in a set of type synonym definitions."
650 Nothing -> "A cycle appears in a set of type synonym definitions."
629 , line "Cycles are disallowed because they can lead to loops in the type checker."
651 , line "Cycles are disallowed because they can lead to loops in the type checker."
630 , line "Consider using a 'newtype' instead."
652 , line "Consider using a 'newtype' instead."
631 ]
653 ]
632 renderSimpleErrorMessage (NameIsUndefined ident) =
654 renderSimpleErrorMessage (NameIsUndefined ident) =
633− line $ "Value " ++ showIdent ident ++ " is undefined."
655+ line $ "Value " ++ markCode (showIdent ident) ++ " is undefined."
634 renderSimpleErrorMessage (UndefinedTypeVariable name) =
656 renderSimpleErrorMessage (UndefinedTypeVariable name) =
635− line $ "Type variable " ++ runProperName name ++ " is undefined."
657+ line $ "Type variable " ++ markCode (runProperName name) ++ " is undefined."
636 renderSimpleErrorMessage (PartiallyAppliedSynonym name) =
658 renderSimpleErrorMessage (PartiallyAppliedSynonym name) =
637− paras [ line $ "Type synonym " ++ showQualified runProperName name ++ " is partially applied."
659+ paras [ line $ "Type synonym " ++ markCode (showQualified runProperName name) ++ " is partially applied."
638 , line "Type synonyms must be applied to all of their type arguments."
660 , line "Type synonyms must be applied to all of their type arguments."
639 ]
661 ]
640 renderSimpleErrorMessage (EscapedSkolem binding) =
662 renderSimpleErrorMessage (EscapedSkolem binding) =
641 paras $ [ line "A type variable has escaped its scope." ]
663 paras $ [ line "A type variable has escaped its scope." ]
642 <> foldMap (\expr -> [ line "Relevant expression: "
664 <> foldMap (\expr -> [ line "Relevant expression: "
643− , indent $ prettyPrintValue valueDepth expr
665+ , markCodeBox $ indent $ prettyPrintValue valueDepth expr
644 ]) binding
666 ]) binding
645 renderSimpleErrorMessage (TypesDoNotUnify u1 u2)
667 renderSimpleErrorMessage (TypesDoNotUnify u1 u2)
646 = let (sorted1, sorted2) = sortRows u1 u2
668 = let (sorted1, sorted2) = sortRows u1 u2
@@ -662,34 +684,39 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
662 , rowFromList (sortBy (comparing fst) sd2 ++ map (fst &&& snd . snd) common, r2)
684 , rowFromList (sortBy (comparing fst) sd2 ++ map (fst &&& snd . snd) common, r2)
663 )
685 )
664 in paras [ line "Could not match type"
686 in paras [ line "Could not match type"
665− , indent $ typeAsBox sorted1
687+ , markCodeBox $ indent $ typeAsBox sorted1
666 , line "with type"
688 , line "with type"
667− , indent $ typeAsBox sorted2
689+ , markCodeBox $ indent $ typeAsBox sorted2
668 ]
690 ]
669
691
670 renderSimpleErrorMessage (KindsDoNotUnify k1 k2) =
692 renderSimpleErrorMessage (KindsDoNotUnify k1 k2) =
671 paras [ line "Could not match kind"
693 paras [ line "Could not match kind"
672− , indent $ line $ prettyPrintKind k1
694+ , indent $ line $ markCode $ prettyPrintKind k1
673 , line "with kind"
695 , line "with kind"
674− , indent $ line $ prettyPrintKind k2
696+ , indent $ line $ markCode $ prettyPrintKind k2
675 ]
697 ]
676 renderSimpleErrorMessage (ConstrainedTypeUnified t1 t2) =
698 renderSimpleErrorMessage (ConstrainedTypeUnified t1 t2) =
677 paras [ line "Could not match constrained type"
699 paras [ line "Could not match constrained type"
678− , indent $ typeAsBox t1
700+ , markCodeBox $ indent $ typeAsBox t1
679 , line "with type"
701 , line "with type"
680− , indent $ typeAsBox t2
702+ , markCodeBox $ indent $ typeAsBox t2
681 ]
703 ]
682 renderSimpleErrorMessage (OverlappingInstances nm ts (d : ds)) =
704 renderSimpleErrorMessage (OverlappingInstances nm ts (d : ds)) =
683 paras [ line "Overlapping type class instances found for"
705 paras [ line "Overlapping type class instances found for"
706+ , markCodeBox $ indent $ Box.hsep 1 Box.left
684− , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
707+ [ line (showQualified runProperName nm)
685− , Box.vcat Box.left (map typeAtomAsBox ts)
708+ , Box.vcat Box.left (map typeAtomAsBox ts)
686− ]
709+ ]
687 , line "The following instances were found:"
710 , line "The following instances were found:"
688 , indent $ paras (line (showQualified showIdent d ++ " (chosen)") : map (line . showQualified showIdent) ds)
711 , indent $ paras (line (showQualified showIdent d ++ " (chosen)") : map (line . showQualified showIdent) ds)
689 , line "Overlapping type class instances can lead to different behavior based on the order of module imports, and for that reason are not recommended."
712 , line "Overlapping type class instances can lead to different behavior based on the order of module imports, and for that reason are not recommended."
690 , line "They may be disallowed completely in a future version of the compiler."
713 , line "They may be disallowed completely in a future version of the compiler."
691 ]
714 ]
692 renderSimpleErrorMessage OverlappingInstances{} = internalError "OverlappingInstances: empty instance list"
715 renderSimpleErrorMessage OverlappingInstances{} = internalError "OverlappingInstances: empty instance list"
716+ renderSimpleErrorMessage (NoInstanceFound (Constraint C.Fail [ TypeLevelString message ] _)) =
717+ paras [ line "A custom type error occurred while solving type class constraints:"
718+ , indent . paras . map line . lines $ message
719+ ]
693 renderSimpleErrorMessage (NoInstanceFound (Constraint C.Partial
720 renderSimpleErrorMessage (NoInstanceFound (Constraint C.Partial
694 _
721 _
695 (Just (PartialConstraintData bs b)))) =
722 (Just (PartialConstraintData bs b)))) =
@@ -697,15 +724,16 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
697 , line "The following additional cases are required to cover all inputs:\n"
724 , line "The following additional cases are required to cover all inputs:\n"
698 , indent $ paras $
725 , indent $ paras $
699 Box.hsep 1 Box.left
726 Box.hsep 1 Box.left
700− (map (paras . map line) (transpose bs))
727+ (map (paras . map (line . markCode)) (transpose bs))
701 : [line "..." | not b]
728 : [line "..." | not b]
702 , line "Alternatively, add a Partial constraint to the type of the enclosing value."
729 , line "Alternatively, add a Partial constraint to the type of the enclosing value."
703 ]
730 ]
704 renderSimpleErrorMessage (NoInstanceFound (Constraint nm ts _)) =
731 renderSimpleErrorMessage (NoInstanceFound (Constraint nm ts _)) =
705 paras [ line "No type class instance was found for"
732 paras [ line "No type class instance was found for"
733+ , markCodeBox $ indent $ Box.hsep 1 Box.left
706− , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
734+ [ line (showQualified runProperName nm)
707− , Box.vcat Box.left (map typeAtomAsBox ts)
735+ , Box.vcat Box.left (map typeAtomAsBox ts)
708− ]
736+ ]
709 , paras [ line "The instance head contains unknown type variables. Consider adding a type annotation."
737 , paras [ line "The instance head contains unknown type variables. Consider adding a type annotation."
710 | any containsUnknowns ts
738 | any containsUnknowns ts
711 ]
739 ]
@@ -718,125 +746,128 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
718 go _ = False
746 go _ = False
719 renderSimpleErrorMessage (PossiblyInfiniteInstance nm ts) =
747 renderSimpleErrorMessage (PossiblyInfiniteInstance nm ts) =
720 paras [ line "Type class instance for"
748 paras [ line "Type class instance for"
749+ , markCodeBox $ indent $ Box.hsep 1 Box.left
721− , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
750+ [ line (showQualified runProperName nm)
722− , Box.vcat Box.left (map typeAtomAsBox ts)
751+ , Box.vcat Box.left (map typeAtomAsBox ts)
723− ]
752+ ]
724 , line "is possibly infinite."
753 , line "is possibly infinite."
725 ]
754 ]
726 renderSimpleErrorMessage (CannotDerive nm ts) =
755 renderSimpleErrorMessage (CannotDerive nm ts) =
727 paras [ line "Cannot derive a type class instance for"
756 paras [ line "Cannot derive a type class instance for"
757+ , markCodeBox $ indent $ Box.hsep 1 Box.left
728− , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
758+ [ line (showQualified runProperName nm)
729− , Box.vcat Box.left (map typeAtomAsBox ts)
759+ , Box.vcat Box.left (map typeAtomAsBox ts)
730− ]
760+ ]
731 ]
761 ]
732 renderSimpleErrorMessage (CannotFindDerivingType nm) =
762 renderSimpleErrorMessage (CannotFindDerivingType nm) =
733− line $ "Cannot derive a type class instance, because the type declaration for " ++ runProperName nm ++ " could not be found."
763+ line $ "Cannot derive a type class instance, because the type declaration for " ++ markCode (runProperName nm) ++ " could not be found."
734 renderSimpleErrorMessage (DuplicateLabel l expr) =
764 renderSimpleErrorMessage (DuplicateLabel l expr) =
735− paras $ [ line $ "Label " ++ show l ++ " appears more than once in a row type." ]
765+ paras $ [ line $ "Label " ++ markCode l ++ " appears more than once in a row type." ]
736 <> foldMap (\expr' -> [ line "Relevant expression: "
766 <> foldMap (\expr' -> [ line "Relevant expression: "
737− , indent $ prettyPrintValue valueDepth expr'
767+ , markCodeBox $ indent $ prettyPrintValue valueDepth expr'
738 ]) expr
768 ]) expr
739 renderSimpleErrorMessage (DuplicateTypeArgument name) =
769 renderSimpleErrorMessage (DuplicateTypeArgument name) =
740− line $ "Type argument " ++ show name ++ " appears more than once."
770+ line $ "Type argument " ++ markCode name ++ " appears more than once."
741 renderSimpleErrorMessage (DuplicateValueDeclaration nm) =
771 renderSimpleErrorMessage (DuplicateValueDeclaration nm) =
742− line $ "Multiple value declarations exist for " ++ showIdent nm ++ "."
772+ line $ "Multiple value declarations exist for " ++ markCode (showIdent nm) ++ "."
743 renderSimpleErrorMessage (ArgListLengthsDiffer ident) =
773 renderSimpleErrorMessage (ArgListLengthsDiffer ident) =
744− line $ "Argument list lengths differ in declaration " ++ showIdent ident
774+ line $ "Argument list lengths differ in declaration " ++ markCode (showIdent ident)
745 renderSimpleErrorMessage (OverlappingArgNames ident) =
775 renderSimpleErrorMessage (OverlappingArgNames ident) =
746 line $ "Overlapping names in function/binder" ++ foldMap ((" in declaration " ++) . showIdent) ident
776 line $ "Overlapping names in function/binder" ++ foldMap ((" in declaration " ++) . showIdent) ident
747 renderSimpleErrorMessage (MissingClassMember ident) =
777 renderSimpleErrorMessage (MissingClassMember ident) =
748− line $ "Type class member " ++ showIdent ident ++ " has not been implemented."
778+ line $ "Type class member " ++ markCode (showIdent ident) ++ " has not been implemented."
749 renderSimpleErrorMessage (ExtraneousClassMember ident className) =
779 renderSimpleErrorMessage (ExtraneousClassMember ident className) =
750− line $ showIdent ident ++ " is not a member of type class " ++ showQualified runProperName className
780+ line $ "" ++ markCode (showIdent ident) ++ " is not a member of type class " ++ markCode (showQualified runProperName className)
751 renderSimpleErrorMessage (ExpectedType ty kind) =
781 renderSimpleErrorMessage (ExpectedType ty kind) =
752− paras [ line "In a type-annotated expression x :: t, the type t must have kind *."
782+ paras [ line $ "In a type-annotated expression " ++ markCode "x :: t" ++ ", the type " ++ markCode "t" ++ " must have kind " ++ markCode "*" ++ "."
753 , line "The error arises from the type"
783 , line "The error arises from the type"
754− , indent $ typeAsBox ty
784+ , markCodeBox $ indent $ typeAsBox ty
755 , line "having the kind"
785 , line "having the kind"
756− , indent $ line $ prettyPrintKind kind
786+ , indent $ line $ markCode $ prettyPrintKind kind
757 , line "instead."
787 , line "instead."
758 ]
788 ]
759 renderSimpleErrorMessage (IncorrectConstructorArity nm) =
789 renderSimpleErrorMessage (IncorrectConstructorArity nm) =
760− line $ "Data constructor " ++ showQualified runProperName nm ++ " was given the wrong number of arguments in a case expression."
790+ line $ "Data constructor " ++ markCode (showQualified runProperName nm) ++ " was given the wrong number of arguments in a case expression."
761 renderSimpleErrorMessage (ExprDoesNotHaveType expr ty) =
791 renderSimpleErrorMessage (ExprDoesNotHaveType expr ty) =
762 paras [ line "Expression"
792 paras [ line "Expression"
763− , indent $ prettyPrintValue valueDepth expr
793+ , markCodeBox $ indent $ prettyPrintValue valueDepth expr
764 , line "does not have type"
794 , line "does not have type"
765− , indent $ typeAsBox ty
795+ , markCodeBox $ indent $ typeAsBox ty
766 ]
796 ]
767 renderSimpleErrorMessage (PropertyIsMissing prop) =
797 renderSimpleErrorMessage (PropertyIsMissing prop) =
768− line $ "Type of expression lacks required label " ++ show prop ++ "."
798+ line $ "Type of expression lacks required label " ++ markCode prop ++ "."
769 renderSimpleErrorMessage (AdditionalProperty prop) =
799 renderSimpleErrorMessage (AdditionalProperty prop) =
770− line $ "Type of expression contains additional label " ++ show prop ++ "."
800+ line $ "Type of expression contains additional label " ++ markCode prop ++ "."
771 renderSimpleErrorMessage (CannotApplyFunction fn arg) =
801 renderSimpleErrorMessage (CannotApplyFunction fn arg) =
772 paras [ line "A function of type"
802 paras [ line "A function of type"
773− , indent $ typeAsBox fn
803+ , markCodeBox $ indent $ typeAsBox fn
774 , line "can not be applied to the argument"
804 , line "can not be applied to the argument"
775− , indent $ prettyPrintValue valueDepth arg
805+ , markCodeBox $ indent $ prettyPrintValue valueDepth arg
776 ]
806 ]
777 renderSimpleErrorMessage TypeSynonymInstance =
807 renderSimpleErrorMessage TypeSynonymInstance =
778 line "Type class instances for type synonyms are disallowed."
808 line "Type class instances for type synonyms are disallowed."
779 renderSimpleErrorMessage (OrphanInstance nm cnm ts) =
809 renderSimpleErrorMessage (OrphanInstance nm cnm ts) =
780− paras [ line $ "Type class instance " ++ showIdent nm ++ " for "
810+ paras [ line $ "Type class instance " ++ markCode (showIdent nm) ++ " for "
811+ , markCodeBox $ indent $ Box.hsep 1 Box.left
781− , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName cnm)
812+ [ line (showQualified runProperName cnm)
782− , Box.vcat Box.left (map typeAtomAsBox ts)
813+ , Box.vcat Box.left (map typeAtomAsBox ts)
783− ]
814+ ]
784 , line "is an orphan instance."
815 , line "is an orphan instance."
785 , line "An orphan instance is an instance which is defined in neither the class module nor the data type module."
816 , line "An orphan instance is an instance which is defined in neither the class module nor the data type module."
786 , line "Consider moving the instance, if possible, or using a newtype wrapper."
817 , line "Consider moving the instance, if possible, or using a newtype wrapper."
787 ]
818 ]
788 renderSimpleErrorMessage (InvalidNewtype name) =
819 renderSimpleErrorMessage (InvalidNewtype name) =
789− paras [ line $ "Newtype " ++ runProperName name ++ " is invalid."
820+ paras [ line $ "Newtype " ++ markCode (runProperName name) ++ " is invalid."
790 , line "Newtypes must define a single constructor with a single argument."
821 , line "Newtypes must define a single constructor with a single argument."
791 ]
822 ]
792 renderSimpleErrorMessage (InvalidInstanceHead ty) =
823 renderSimpleErrorMessage (InvalidInstanceHead ty) =
793 paras [ line "Type class instance head is invalid due to use of type"
824 paras [ line "Type class instance head is invalid due to use of type"
794− , indent $ typeAsBox ty
825+ , markCodeBox $ indent $ typeAsBox ty
795 , line "All types appearing in instance declarations must be of the form T a_1 .. a_n, where each type a_i is of the same form."
826 , line "All types appearing in instance declarations must be of the form T a_1 .. a_n, where each type a_i is of the same form."
796 ]
827 ]
797 renderSimpleErrorMessage (TransitiveExportError x ys) =
828 renderSimpleErrorMessage (TransitiveExportError x ys) =
798− paras [ line $ "An export for " ++ prettyPrintExport x ++ " requires the following to also be exported: "
829+ paras [ line $ "An export for " ++ markCode (prettyPrintExport x) ++ " requires the following to also be exported: "
799− , indent $ paras $ map (line . prettyPrintExport) ys
830+ , indent $ paras $ map (line . markCode . prettyPrintExport) ys
800 ]
831 ]
801 renderSimpleErrorMessage (TransitiveDctorExportError x ctor) =
832 renderSimpleErrorMessage (TransitiveDctorExportError x ctor) =
802− paras [ line $ "An export for " ++ prettyPrintExport x ++ " requires the following data constructor to also be exported: "
833+ paras [ line $ "An export for " ++ markCode (prettyPrintExport x) ++ " requires the following data constructor to also be exported: "
803− , indent $ line $ runProperName ctor
834+ , indent $ line $ markCode $ runProperName ctor
804 ]
835 ]
805 renderSimpleErrorMessage (ShadowedName nm) =
836 renderSimpleErrorMessage (ShadowedName nm) =
806− line $ "Name '" ++ showIdent nm ++ "' was shadowed."
837+ line $ "Name " ++ markCode (showIdent nm) ++ " was shadowed."
807 renderSimpleErrorMessage (ShadowedTypeVar tv) =
838 renderSimpleErrorMessage (ShadowedTypeVar tv) =
808− line $ "Type variable '" ++ tv ++ "' was shadowed."
839+ line $ "Type variable " ++ markCode tv ++ " was shadowed."
809 renderSimpleErrorMessage (UnusedTypeVar tv) =
840 renderSimpleErrorMessage (UnusedTypeVar tv) =
810− line $ "Type variable '" ++ tv ++ "' was declared but not used."
841+ line $ "Type variable " ++ markCode tv ++ " was declared but not used."
811 renderSimpleErrorMessage (MisleadingEmptyTypeImport mn name) =
842 renderSimpleErrorMessage (MisleadingEmptyTypeImport mn name) =
812− line $ "Importing type " ++ runProperName name ++ "(..) from " ++ runModuleName mn ++ " is misleading as it has no exported data constructors."
843+ line $ "Importing type " ++ markCode (runProperName name ++ "(..)") ++ " from " ++ markCode (runModuleName mn) ++ " is misleading as it has no exported data constructors."
813 renderSimpleErrorMessage (ImportHidingModule name) =
844 renderSimpleErrorMessage (ImportHidingModule name) =
814− paras [ line "'hiding' imports cannot be used to hide modules."
845+ paras [ line "hiding imports cannot be used to hide modules."
815− , line $ "An attempt was made to hide the import of " ++ runModuleName name
846+ , line $ "An attempt was made to hide the import of " ++ markCode (runModuleName name)
816 ]
847 ]
817 renderSimpleErrorMessage (WildcardInferredType ty) =
848 renderSimpleErrorMessage (WildcardInferredType ty) =
818 paras [ line "Wildcard type definition has the inferred type "
849 paras [ line "Wildcard type definition has the inferred type "
819− , indent $ typeAsBox ty
850+ , markCodeBox $ indent $ typeAsBox ty
820 ]
851 ]
821 renderSimpleErrorMessage (HoleInferredType name ty env) =
852 renderSimpleErrorMessage (HoleInferredType name ty env) =
822− paras $ [ line $ "Hole '" ++ name ++ "' has the inferred type "
853+ paras $ [ line $ "Hole '" ++ markCode name ++ "' has the inferred type "
823− , indent $ typeAsBox ty
854+ , markCodeBox $ indent $ typeAsBox ty
824 ] ++ if null env then [] else envInfo
855 ] ++ if null env then [] else envInfo
825 where
856 where
826 envInfo :: [Box.Box]
857 envInfo :: [Box.Box]
827 envInfo = [ line "in the following context:"
858 envInfo = [ line "in the following context:"
828 , indent $ paras
859 , indent $ paras
829 [ Box.hcat Box.left [ Box.text (showIdent ident <> " :: ")
860 [ Box.hcat Box.left [ Box.text (showIdent ident <> " :: ")
830− , typeAsBox ty'
861+ , markCodeBox $ typeAsBox ty'
831 ]
862 ]
832 | (ident, ty') <- take 5 env
863 | (ident, ty') <- take 5 env
833 ]
864 ]
834 ]
865 ]
835 renderSimpleErrorMessage (MissingTypeDeclaration ident ty) =
866 renderSimpleErrorMessage (MissingTypeDeclaration ident ty) =
836− paras [ line $ "No type declaration was provided for the top-level declaration of " ++ showIdent ident ++ "."
867+ paras [ line $ "No type declaration was provided for the top-level declaration of " ++ markCode (showIdent ident) ++ "."
837 , line "It is good practice to provide type declarations as a form of documentation."
868 , line "It is good practice to provide type declarations as a form of documentation."
838− , line $ "The inferred type of " ++ showIdent ident ++ " was:"
869+ , line $ "The inferred type of " ++ markCode (showIdent ident) ++ " was:"
839− , indent $ typeAsBox ty
870+ , markCodeBox $ indent $ typeAsBox ty
840 ]
871 ]
841 renderSimpleErrorMessage (OverlappingPattern bs b) =
872 renderSimpleErrorMessage (OverlappingPattern bs b) =
842 paras $ [ line "A case expression contains unreachable cases:\n"
873 paras $ [ line "A case expression contains unreachable cases:\n"
@@ -848,26 +879,26 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
848 , line "You may want to decompose your data types into smaller types."
879 , line "You may want to decompose your data types into smaller types."
849 ]
880 ]
850 renderSimpleErrorMessage (UnusedImport name) =
881 renderSimpleErrorMessage (UnusedImport name) =
851− line $ "The import of module " ++ runModuleName name ++ " is redundant"
882+ line $ "The import of module " ++ markCode (runModuleName name) ++ " is redundant"
852
883
853 renderSimpleErrorMessage msg@(UnusedExplicitImport mn names _ _) =
884 renderSimpleErrorMessage msg@(UnusedExplicitImport mn names _ _) =
854− paras [ line $ "The import of module " ++ runModuleName mn ++ " contains the following unused references:"
885+ paras [ line $ "The import of module " ++ markCode (runModuleName mn) ++ " contains the following unused references:"
855 , indent $ paras $ map line names
886 , indent $ paras $ map line names
856 , line "It could be replaced with:"
887 , line "It could be replaced with:"
857− , indent $ line $ showSuggestion msg ]
888+ , indent $ line $ markCode $ showSuggestion msg ]
858
889
859 renderSimpleErrorMessage (UnusedDctorImport name) =
890 renderSimpleErrorMessage (UnusedDctorImport name) =
860− line $ "The import of type " ++ runProperName name ++ " includes data constructors but only the type is used"
891+ line $ "The import of type " ++ markCode (runProperName name) ++ " includes data constructors but only the type is used"
861
892
862 renderSimpleErrorMessage (UnusedDctorExplicitImport name names) =
893 renderSimpleErrorMessage (UnusedDctorExplicitImport name names) =
863− paras [ line $ "The import of type " ++ runProperName name ++ " includes the following unused data constructors:"
894+ paras [ line $ "The import of type " ++ markCode (runProperName name) ++ " includes the following unused data constructors:"
864− , indent $ paras $ map (line .runProperName) names ]
895+ , indent $ paras $ map (line . markCode . runProperName) names ]
865
896
866 renderSimpleErrorMessage (DuplicateSelectiveImport name) =
897 renderSimpleErrorMessage (DuplicateSelectiveImport name) =
867− line $ "There is an existing import of " ++ runModuleName name ++ ", consider merging the import lists"
898+ line $ "There is an existing import of " ++ markCode (runModuleName name) ++ ", consider merging the import lists"
868
899
869 renderSimpleErrorMessage (DuplicateImport name imp qual) =
900 renderSimpleErrorMessage (DuplicateImport name imp qual) =
870− line $ "Duplicate import of " ++ prettyPrintImport name imp qual
901+ line $ "Duplicate import of " ++ markCode (prettyPrintImport name imp qual)
871
902
872 renderSimpleErrorMessage (DuplicateImportRef name) =
903 renderSimpleErrorMessage (DuplicateImportRef name) =
873 line $ "Import list contains multiple references to " ++ printName (Qualified Nothing name)
904 line $ "Import list contains multiple references to " ++ printName (Qualified Nothing name)
@@ -876,23 +907,23 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
876 line $ "Export list contains multiple references to " ++ printName (Qualified Nothing name)
907 line $ "Export list contains multiple references to " ++ printName (Qualified Nothing name)
877
908
878 renderSimpleErrorMessage (IntOutOfRange value backend lo hi) =
909 renderSimpleErrorMessage (IntOutOfRange value backend lo hi) =
879− paras [ line $ "Integer value " ++ show value ++ " is out of range for the " ++ backend ++ " backend."
910+ paras [ line $ "Integer value " ++ markCode (show value) ++ " is out of range for the " ++ backend ++ " backend."
880− , line $ "Acceptable values fall within the range " ++ show lo ++ " to " ++ show hi ++ " (inclusive)." ]
911+ , line $ "Acceptable values fall within the range " ++ markCode (show lo) ++ " to " ++ markCode (show hi) ++ " (inclusive)." ]
881
912
882 renderSimpleErrorMessage msg@(ImplicitQualifiedImport importedModule asModule _) =
913 renderSimpleErrorMessage msg@(ImplicitQualifiedImport importedModule asModule _) =
883− paras [ line $ "Module " ++ runModuleName importedModule ++ " was imported as " ++ runModuleName asModule ++ " with unspecified imports."
914+ paras [ line $ "Module " ++ markCode (runModuleName importedModule) ++ " was imported as " ++ markCode (runModuleName asModule) ++ " with unspecified imports."
884− , line $ "As there are multiple modules being imported as " ++ runModuleName asModule ++ ", consider using the explicit form:"
915+ , line $ "As there are multiple modules being imported as " ++ markCode (runModuleName asModule) ++ ", consider using the explicit form:"
885− , indent $ line $ showSuggestion msg
916+ , indent $ line $ markCode $ showSuggestion msg
886 ]
917 ]
887
918
888 renderSimpleErrorMessage msg@(ImplicitImport mn _) =
919 renderSimpleErrorMessage msg@(ImplicitImport mn _) =
889− paras [ line $ "Module " ++ runModuleName mn ++ " has unspecified imports, consider using the explicit form: "
920+ paras [ line $ "Module " ++ markCode (runModuleName mn) ++ " has unspecified imports, consider using the explicit form: "
890− , indent $ line $ showSuggestion msg
921+ , indent $ line $ markCode $ showSuggestion msg
891 ]
922 ]
892
923
893 renderSimpleErrorMessage msg@(HidingImport mn _) =
924 renderSimpleErrorMessage msg@(HidingImport mn _) =
894− paras [ line $ "Module " ++ runModuleName mn ++ " has unspecified imports, consider using the inclusive form: "
925+ paras [ line $ "Module " ++ markCode (runModuleName mn) ++ " has unspecified imports, consider using the inclusive form: "
895− , indent $ line $ showSuggestion msg
926+ , indent $ line $ markCode $ showSuggestion msg
896 ]
927 ]
897
928
898 renderSimpleErrorMessage (CaseBinderLengthDiffers l bs) =
929 renderSimpleErrorMessage (CaseBinderLengthDiffers l bs) =
@@ -905,7 +936,7 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
905 line "An anonymous function argument appears in an invalid context."
936 line "An anonymous function argument appears in an invalid context."
906
937
907 renderSimpleErrorMessage (InvalidOperatorInBinder op fn) =
938 renderSimpleErrorMessage (InvalidOperatorInBinder op fn) =
908− paras [ line $ "Operator " ++ showQualified showOp op ++ " cannot be used in a pattern as it is an alias for function " ++ showQualified showIdent fn ++ "."
939+ paras [ line $ "Operator " ++ markCode (showQualified showOp op) ++ " cannot be used in a pattern as it is an alias for function " ++ showQualified showIdent fn ++ "."
909 , line "Only aliases for data constructors may be used in patterns."
940 , line "Only aliases for data constructors may be used in patterns."
910 ]
941 ]
911
942
@@ -913,9 +944,9 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
913 line "The require-path option is deprecated and will be removed in PureScript 0.9."
944 line "The require-path option is deprecated and will be removed in PureScript 0.9."
914
945
915 renderSimpleErrorMessage (CannotGeneralizeRecursiveFunction ident ty) =
946 renderSimpleErrorMessage (CannotGeneralizeRecursiveFunction ident ty) =
916− paras [ line $ "Unable to generalize the type of the recursive function " ++ showIdent ident ++ "."
947+ paras [ line $ "Unable to generalize the type of the recursive function " ++ markCode (showIdent ident) ++ "."
917− , line $ "The inferred type of " ++ showIdent ident ++ " was:"
948+ , line $ "The inferred type of " ++ markCode (showIdent ident) ++ " was:"
918− , indent $ typeAsBox ty
949+ , markCodeBox $ indent $ typeAsBox ty
919 , line "Try adding a type signature."
950 , line "Try adding a type signature."
920 ]
951 ]
921
952
@@ -923,42 +954,43 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
923 renderHint (ErrorUnifyingTypes t1 t2) detail =
954 renderHint (ErrorUnifyingTypes t1 t2) detail =
924 paras [ detail
955 paras [ detail
925 , Box.hsep 1 Box.top [ line "while trying to match type"
956 , Box.hsep 1 Box.top [ line "while trying to match type"
926− , typeAsBox t1
957+ , markCodeBox $ typeAsBox t1
927 ]
958 ]
928 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "with type"
959 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "with type"
929− , typeAsBox t2
960+ , markCodeBox $ typeAsBox t2
930 ]
961 ]
931 ]
962 ]
932 renderHint (ErrorInExpression expr) detail =
963 renderHint (ErrorInExpression expr) detail =
933 paras [ detail
964 paras [ detail
934 , Box.hsep 1 Box.top [ Box.text "in the expression"
965 , Box.hsep 1 Box.top [ Box.text "in the expression"
935− , prettyPrintValue valueDepth expr
966+ , markCodeBox $ markCodeBox $ prettyPrintValue valueDepth expr
936 ]
967 ]
937 ]
968 ]
938 renderHint (ErrorInModule mn) detail =
969 renderHint (ErrorInModule mn) detail =
939− paras [ line $ "in module " ++ runModuleName mn
970+ paras [ line $ "in module " ++ markCode (runModuleName mn)
940 , detail
971 , detail
941 ]
972 ]
942 renderHint (ErrorInSubsumption t1 t2) detail =
973 renderHint (ErrorInSubsumption t1 t2) detail =
943 paras [ detail
974 paras [ detail
944 , Box.hsep 1 Box.top [ line "while checking that type"
975 , Box.hsep 1 Box.top [ line "while checking that type"
945− , typeAsBox t1
976+ , markCodeBox $ typeAsBox t1
946 ]
977 ]
947 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "is at least as general as type"
978 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "is at least as general as type"
948− , typeAsBox t2
979+ , markCodeBox $ typeAsBox t2
949 ]
980 ]
950 ]
981 ]
951 renderHint (ErrorInInstance nm ts) detail =
982 renderHint (ErrorInInstance nm ts) detail =
952 paras [ detail
983 paras [ detail
953− , Box.hsep 1 Box.top [ line "in type class instance"
984+ , line "in type class instance"
985+ , markCodeBox $ indent $ Box.hsep 1 Box.top
954− , line (showQualified runProperName nm)
986+ [ line $ showQualified runProperName nm
955− , Box.vcat Box.left (map typeAtomAsBox ts)
987+ , Box.vcat Box.left (map typeAtomAsBox ts)
956− ]
988+ ]
957 ]
989 ]
958 renderHint (ErrorCheckingKind ty) detail =
990 renderHint (ErrorCheckingKind ty) detail =
959 paras [ detail
991 paras [ detail
960 , Box.hsep 1 Box.top [ line "while checking the kind of"
992 , Box.hsep 1 Box.top [ line "while checking the kind of"
961− , typeAsBox ty
993+ , markCodeBox $ typeAsBox ty
962 ]
994 ]
963 ]
995 ]
964 renderHint ErrorCheckingGuard detail =
996 renderHint ErrorCheckingGuard detail =
@@ -968,43 +1000,43 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
968 renderHint (ErrorInferringType expr) detail =
1000 renderHint (ErrorInferringType expr) detail =
969 paras [ detail
1001 paras [ detail
970 , Box.hsep 1 Box.top [ line "while inferring the type of"
1002 , Box.hsep 1 Box.top [ line "while inferring the type of"
971− , prettyPrintValue valueDepth expr
1003+ , markCodeBox $ prettyPrintValue valueDepth expr
972 ]
1004 ]
973 ]
1005 ]
974 renderHint (ErrorCheckingType expr ty) detail =
1006 renderHint (ErrorCheckingType expr ty) detail =
975 paras [ detail
1007 paras [ detail
976 , Box.hsep 1 Box.top [ line "while checking that expression"
1008 , Box.hsep 1 Box.top [ line "while checking that expression"
977− , prettyPrintValue valueDepth expr
1009+ , markCodeBox $ prettyPrintValue valueDepth expr
978 ]
1010 ]
979 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "has type"
1011 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "has type"
980− , typeAsBox ty
1012+ , markCodeBox $ typeAsBox ty
981 ]
1013 ]
982 ]
1014 ]
983 renderHint (ErrorCheckingAccessor expr prop) detail =
1015 renderHint (ErrorCheckingAccessor expr prop) detail =
984 paras [ detail
1016 paras [ detail
985 , Box.hsep 1 Box.top [ line "while checking type of property accessor"
1017 , Box.hsep 1 Box.top [ line "while checking type of property accessor"
986− , prettyPrintValue valueDepth (Accessor prop expr)
1018+ , markCodeBox $ prettyPrintValue valueDepth (Accessor prop expr)
987 ]
1019 ]
988 ]
1020 ]
989 renderHint (ErrorInApplication f t a) detail =
1021 renderHint (ErrorInApplication f t a) detail =
990 paras [ detail
1022 paras [ detail
991 , Box.hsep 1 Box.top [ line "while applying a function"
1023 , Box.hsep 1 Box.top [ line "while applying a function"
992− , prettyPrintValue valueDepth f
1024+ , markCodeBox $ prettyPrintValue valueDepth f
993 ]
1025 ]
994 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "of type"
1026 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "of type"
995− , typeAsBox t
1027+ , markCodeBox $ typeAsBox t
996 ]
1028 ]
997 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "to argument"
1029 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "to argument"
998− , prettyPrintValue valueDepth a
1030+ , markCodeBox $ prettyPrintValue valueDepth a
999 ]
1031 ]
1000 ]
1032 ]
1001 renderHint (ErrorInDataConstructor nm) detail =
1033 renderHint (ErrorInDataConstructor nm) detail =
1002 paras [ detail
1034 paras [ detail
1003− , line $ "in data constructor " ++ runProperName nm
1035+ , line $ "in data constructor " ++ markCode (runProperName nm)
1004 ]
1036 ]
1005 renderHint (ErrorInTypeConstructor nm) detail =
1037 renderHint (ErrorInTypeConstructor nm) detail =
1006 paras [ detail
1038 paras [ detail
1007− , line $ "in type constructor " ++ runProperName nm
1039+ , line $ "in type constructor " ++ markCode (runProperName nm)
1008 ]
1040 ]
1009 renderHint (ErrorInBindingGroup nms) detail =
1041 renderHint (ErrorInBindingGroup nms) detail =
1010 paras [ detail
1042 paras [ detail
@@ -1016,19 +1048,19 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
1016 ]
1048 ]
1017 renderHint (ErrorInTypeSynonym name) detail =
1049 renderHint (ErrorInTypeSynonym name) detail =
1018 paras [ detail
1050 paras [ detail
1019− , line $ "in type synonym " ++ runProperName name
1051+ , line $ "in type synonym " ++ markCode (runProperName name)
1020 ]
1052 ]
1021 renderHint (ErrorInValueDeclaration n) detail =
1053 renderHint (ErrorInValueDeclaration n) detail =
1022 paras [ detail
1054 paras [ detail
1023− , line $ "in value declaration " ++ showIdent n
1055+ , line $ "in value declaration " ++ markCode (showIdent n)
1024 ]
1056 ]
1025 renderHint (ErrorInTypeDeclaration n) detail =
1057 renderHint (ErrorInTypeDeclaration n) detail =
1026 paras [ detail
1058 paras [ detail
1027− , line $ "in type declaration for " ++ showIdent n
1059+ , line $ "in type declaration for " ++ markCode (showIdent n)
1028 ]
1060 ]
1029 renderHint (ErrorInForeignImport nm) detail =
1061 renderHint (ErrorInForeignImport nm) detail =
1030 paras [ detail
1062 paras [ detail
1031− , line $ "in foreign import " ++ showIdent nm
1063+ , line $ "in foreign import " ++ markCode (showIdent nm)
1032 ]
1064 ]
1033 renderHint (PositionedError srcSpan) detail =
1065 renderHint (PositionedError srcSpan) detail =
1034 paras [ line $ "at " ++ displaySourceSpan srcSpan
1066 paras [ line $ "at " ++ displaySourceSpan srcSpan
@@ -1036,22 +1068,34 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
1036 ]
1068 ]
1037
1069
1038 printName :: Qualified Name -> String
1070 printName :: Qualified Name -> String
1039− printName (Qualified mn (IdentName name)) =
1071+ printName qn = nameType (disqualify qn) ++ " " ++ markCode (runName qn)
1040− "value " ++ showQualified showIdent (Qualified mn name)
1072+
1041− printName (Qualified mn (ValOpName op)) =
1073+ nameType :: Name -> String
1042− "operator " ++ showQualified showOp (Qualified mn op)
1074+ nameType (IdentName _) = "value"
1043− printName (Qualified mn (TyName name)) =
1075+ nameType (ValOpName _) = "operator"
1044− "type " ++ showQualified runProperName (Qualified mn name)
1076+ nameType (TyName _) = "type"
1045− printName (Qualified mn (TyOpName op)) =
1077+ nameType (TyOpName _) = "type operator"
1046− "type operator " ++ showQualified showOp (Qualified mn op)
1078+ nameType (DctorName _) = "data constructor"
1047− printName (Qualified mn (DctorName name)) =
1079+ nameType (TyClassName _) = "type class"
1048− "data constructor " ++ showQualified runProperName (Qualified mn name)
1080+ nameType (ModName _) = "module"
1049− printName (Qualified mn (TyClassName name)) =
1081+
1050− "type class " ++ showQualified runProperName (Qualified mn name)
1082+ runName :: Qualified Name -> String
1051− printName (Qualified Nothing (ModName name)) =
1083+ runName (Qualified mn (IdentName name)) =
1084+ showQualified showIdent (Qualified mn name)
1085+ runName (Qualified mn (ValOpName op)) =
1086+ showQualified showOp (Qualified mn op)
1087+ runName (Qualified mn (TyName name)) =
1088+ showQualified runProperName (Qualified mn name)
1089+ runName (Qualified mn (TyOpName op)) =
1090+ showQualified showOp (Qualified mn op)
1091+ runName (Qualified mn (DctorName name)) =
1092+ showQualified runProperName (Qualified mn name)
1093+ runName (Qualified mn (TyClassName name)) =
1094+ showQualified runProperName (Qualified mn name)
1095+ runName (Qualified Nothing (ModName name)) =
1052− "module " ++ runModuleName name
1096+ runModuleName name
1053− printName (Qualified _ ModName{}) =
1097+ runName (Qualified _ ModName{}) =
1054− internalError "qualified ModName in printName"
1098+ internalError "qualified ModName in runName"
1055
1099
1056 valueDepth :: Int
1100 valueDepth :: Int
1057 valueDepth | full = 1000
1101 valueDepth | full = 1000
@@ -1119,57 +1163,72 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
1119-- Pretty print and export declaration
1163-- Pretty print and export declaration
1120prettyPrintExport :: DeclarationRef -> String
1164prettyPrintExport :: DeclarationRef -> String
1121prettyPrintExport (TypeRef pn _) = runProperName pn
1165prettyPrintExport (TypeRef pn _) = runProperName pn
1122−prettyPrintExport ref = prettyPrintRef ref
1166+prettyPrintExport ref =
1167+ fromMaybe
1168+ (internalError "prettyPrintRef returned Nothing in prettyPrintExport")
1169+ (prettyPrintRef ref)
1123
1170
1124prettyPrintImport :: ModuleName -> ImportDeclarationType -> Maybe ModuleName -> String
1171prettyPrintImport :: ModuleName -> ImportDeclarationType -> Maybe ModuleName -> String
1125prettyPrintImport mn idt qual =
1172prettyPrintImport mn idt qual =
1126 let i = case idt of
1173 let i = case idt of
1127 Implicit -> runModuleName mn
1174 Implicit -> runModuleName mn
1128− Explicit refs -> runModuleName mn ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ")"
1175+ Explicit refs -> runModuleName mn ++ " (" ++ intercalate ", " (mapMaybe prettyPrintRef refs) ++ ")"
1129− Hiding refs -> runModuleName mn ++ " hiding (" ++ intercalate "," (map prettyPrintRef refs) ++ ")"
1176+ Hiding refs -> runModuleName mn ++ " hiding (" ++ intercalate "," (mapMaybe prettyPrintRef refs) ++ ")"
1130 in i ++ maybe "" (\q -> " as " ++ runModuleName q) qual
1177 in i ++ maybe "" (\q -> " as " ++ runModuleName q) qual
1131
1178
1132−prettyPrintRef :: DeclarationRef -> String
1179+prettyPrintRef :: DeclarationRef -> Maybe String
1133−prettyPrintRef (TypeRef pn Nothing) = runProperName pn ++ "(..)"
1180+prettyPrintRef (TypeRef pn Nothing) =
1181+ Just $ runProperName pn ++ "(..)"
1134−prettyPrintRef (TypeRef pn (Just [])) = runProperName pn
1182+prettyPrintRef (TypeRef pn (Just [])) =
1183+ Just $ runProperName pn
1184+prettyPrintRef (TypeRef pn (Just dctors)) =
1135−prettyPrintRef (TypeRef pn (Just dctors)) = runProperName pn ++ "(" ++ intercalate ", " (map runProperName dctors) ++ ")"
1185+ Just $ runProperName pn ++ "(" ++ intercalate ", " (map runProperName dctors) ++ ")"
1136−prettyPrintRef (TypeOpRef op) = "type " ++ showOp op
1186+prettyPrintRef (TypeOpRef op) =
1187+ Just $ "type " ++ showOp op
1137−prettyPrintRef (ValueRef ident) = showIdent ident
1188+prettyPrintRef (ValueRef ident) =
1189+ Just $ showIdent ident
1138−prettyPrintRef (ValueOpRef op) = showOp op
1190+prettyPrintRef (ValueOpRef op) =
1191+ Just $ showOp op
1139−prettyPrintRef (TypeClassRef pn) = "class " ++ runProperName pn
1192+prettyPrintRef (TypeClassRef pn) =
1193+ Just $ "class " ++ runProperName pn
1140−prettyPrintRef (TypeInstanceRef ident) = showIdent ident
1194+prettyPrintRef (TypeInstanceRef ident) =
1195+ Just $ showIdent ident
1141−prettyPrintRef (ModuleRef name) = "module " ++ runModuleName name
1196+prettyPrintRef (ModuleRef name) =
1197+ Just $ "module " ++ runModuleName name
1198+prettyPrintRef (ReExportRef _ _) =
1199+ Nothing
1142−prettyPrintRef (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref
1200+prettyPrintRef (PositionedDeclarationRef _ _ ref) =
1201+ prettyPrintRef ref
1143
1202
1144-- |
1203-- |
1145-- Pretty print multiple errors
1204-- Pretty print multiple errors
1146--
1205--
1147−prettyPrintMultipleErrors :: Bool -> MultipleErrors -> String
1206+prettyPrintMultipleErrors :: PPEOptions -> MultipleErrors -> String
1148−prettyPrintMultipleErrors full = unlines . map renderBox . prettyPrintMultipleErrorsBox full
1207+prettyPrintMultipleErrors ppeOptions = unlines . map renderBox . prettyPrintMultipleErrorsBox ppeOptions
1149
1208
1150-- |
1209-- |
1151-- Pretty print multiple warnings
1210-- Pretty print multiple warnings
1152--
1211--
1153−prettyPrintMultipleWarnings :: Bool -> MultipleErrors -> String
1212+prettyPrintMultipleWarnings :: PPEOptions -> MultipleErrors -> String
1154−prettyPrintMultipleWarnings full = unlines . map renderBox . prettyPrintMultipleWarningsBox full
1213+prettyPrintMultipleWarnings ppeOptions = unlines . map renderBox . prettyPrintMultipleWarningsBox ppeOptions
1155
1214
1156-- | Pretty print warnings as a Box
1215-- | Pretty print warnings as a Box
1157−prettyPrintMultipleWarningsBox :: Bool -> MultipleErrors -> [Box.Box]
1216+prettyPrintMultipleWarningsBox :: PPEOptions -> MultipleErrors -> [Box.Box]
1158−prettyPrintMultipleWarningsBox = prettyPrintMultipleErrorsWith Warning "Warning found:" "Warning"
1217+prettyPrintMultipleWarningsBox ppeOptions = prettyPrintMultipleErrorsWith (ppeOptions { ppeLevel = Warning }) "Warning found:" "Warning"
1159
1218
1160-- | Pretty print errors as a Box
1219-- | Pretty print errors as a Box
1161−prettyPrintMultipleErrorsBox :: Bool -> MultipleErrors -> [Box.Box]
1220+prettyPrintMultipleErrorsBox :: PPEOptions -> MultipleErrors -> [Box.Box]
1162−prettyPrintMultipleErrorsBox = prettyPrintMultipleErrorsWith Error "Error found:" "Error"
1221+prettyPrintMultipleErrorsBox ppeOptions = prettyPrintMultipleErrorsWith (ppeOptions { ppeLevel = Error }) "Error found:" "Error"
1163
1222
1164−prettyPrintMultipleErrorsWith :: Level -> String -> String -> Bool -> MultipleErrors -> [Box.Box]
1223+prettyPrintMultipleErrorsWith :: PPEOptions -> String -> String -> MultipleErrors -> [Box.Box]
1165−prettyPrintMultipleErrorsWith level intro _ full (MultipleErrors [e]) =
1224+prettyPrintMultipleErrorsWith ppeOptions intro _ (MultipleErrors [e]) =
1166− let result = prettyPrintSingleError full level True e
1225+ let result = prettyPrintSingleError ppeOptions e
1167 in [ Box.vcat Box.left [ Box.text intro
1226 in [ Box.vcat Box.left [ Box.text intro
1168 , result
1227 , result
1169 ]
1228 ]
1170 ]
1229 ]
1171−prettyPrintMultipleErrorsWith level _ intro full (MultipleErrors es) =
1230+prettyPrintMultipleErrorsWith ppeOptions _ intro (MultipleErrors es) =
1172− let result = map (prettyPrintSingleError full level True) es
1231+ let result = map (prettyPrintSingleError ppeOptions) es
1173 in concat $ zipWith withIntro [1 :: Int ..] result
1232 in concat $ zipWith withIntro [1 :: Int ..] result
1174 where
1233 where
1175 withIntro i err = [ Box.text (intro ++ " " ++ show i ++ " of " ++ show (length es) ++ ":")
1234 withIntro i err = [ Box.text (intro ++ " " ++ show i ++ " of " ++ show (length es) ++ ":")
src/Language/PureScript/Errors/JSON.hs+1−1
@@ -47,7 +47,7 @@ toJSONErrors verbose level = map (toJSONError verbose level) . P.runMultipleErro
47toJSONError :: Bool -> P.Level -> P.ErrorMessage -> JSONError
47toJSONError :: Bool -> P.Level -> P.ErrorMessage -> JSONError
48toJSONError verbose level e =
48toJSONError verbose level e =
49 JSONError (toErrorPosition <$> sspan)
49 JSONError (toErrorPosition <$> sspan)
50− (P.renderBox (P.prettyPrintSingleError verbose level False (P.stripModuleAndSpan e)))
50+ (P.renderBox (P.prettyPrintSingleError (P.PPEOptions Nothing verbose level False) (P.stripModuleAndSpan e)))
51 (P.errorCode e)
51 (P.errorCode e)
52 (P.wikiUri e)
52 (P.wikiUri e)
53 (P.spanName <$> sspan)
53 (P.spanName <$> sspan)
src/Language/PureScript/Ide.hs+129−178
@@ -18,24 +18,11 @@
18
18
19module Language.PureScript.Ide
19module Language.PureScript.Ide
20 ( handleCommand
20 ( handleCommand
21− -- for tests
22− , printModules
23 ) where
21 ) where
24
22
25−import Prelude ()
23+import Protolude
26−import Prelude.Compat
27
24
28−import Control.Monad (unless)
29−import Control.Monad.Error.Class
30−import Control.Monad.IO.Class
31import "monad-logger" Control.Monad.Logger
25import "monad-logger" Control.Monad.Logger
32−import Control.Monad.Reader.Class
33−import Data.Foldable
34−import qualified Data.Map.Lazy as M
35−import Data.Maybe (catMaybes, mapMaybe)
36−import Data.Monoid
37−import Data.Text (Text)
38−import qualified Data.Text as T
39import qualified Language.PureScript as P
26import qualified Language.PureScript as P
40import qualified Language.PureScript.Ide.CaseSplit as CS
27import qualified Language.PureScript.Ide.CaseSplit as CS
41import Language.PureScript.Ide.Command
28import Language.PureScript.Ide.Command
@@ -47,199 +34,163 @@ import Language.PureScript.Ide.Imports hiding (Import)
47import Language.PureScript.Ide.Matcher
34import Language.PureScript.Ide.Matcher
48import Language.PureScript.Ide.Pursuit
35import Language.PureScript.Ide.Pursuit
49import Language.PureScript.Ide.Rebuild
36import Language.PureScript.Ide.Rebuild
50−import Language.PureScript.Ide.Reexports
51import Language.PureScript.Ide.SourceFile
37import Language.PureScript.Ide.SourceFile
52import Language.PureScript.Ide.State
38import Language.PureScript.Ide.State
53import Language.PureScript.Ide.Types
39import Language.PureScript.Ide.Types
54import Language.PureScript.Ide.Util
40import Language.PureScript.Ide.Util
55import System.Directory
41import System.Directory
56−import System.Exit
57import System.FilePath
42import System.FilePath
43+import System.FilePath.Glob
58
44
45+-- | Accepts a Commmand and runs it against psc-ide's State. This is the main
46+-- entry point for the server.
59−handleCommand :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
47+handleCommand :: (Ide m, MonadLogger m, MonadError PscIdeError m) =>
60 Command -> m Success
48 Command -> m Success
61−handleCommand (Load [] []) = loadAllModules
49+handleCommand c = case c of
50+ Load [] ->
51+ findAvailableExterns >>= loadModules
62−handleCommand (Load modules deps) =
52+ Load modules ->
63− loadModulesAndDeps modules deps
53+ loadModules modules
64−handleCommand (Type search filters currentModule) =
54+ Type search filters currentModule ->
65− findType search filters currentModule
55+ findType search filters currentModule
66−handleCommand (Complete filters matcher currentModule) =
56+ Complete filters matcher currentModule ->
67− findCompletions filters matcher currentModule
57+ findCompletions filters matcher currentModule
68−handleCommand (Pursuit query Package) =
58+ Pursuit query Package ->
69− findPursuitPackages query
59+ findPursuitPackages query
70−handleCommand (Pursuit query Identifier) =
60+ Pursuit query Identifier ->
71− findPursuitCompletions query
61+ findPursuitCompletions query
72−handleCommand (List LoadedModules) =
62+ List LoadedModules ->
73− printModules
63+ printModules
74−handleCommand (List AvailableModules) =
64+ List AvailableModules ->
75− listAvailableModules
65+ listAvailableModules
76−handleCommand (List (Imports fp)) =
66+ List (Imports fp) ->
77− importsForFile fp
67+ ImportList <$> getImportsForFile fp
78−handleCommand (CaseSplit l b e wca t) =
68+ CaseSplit l b e wca t ->
79− caseSplit l b e wca t
69+ caseSplit l b e wca t
80−handleCommand (AddClause l wca) =
70+ AddClause l wca ->
81− pure $ addClause l wca
71+ MultilineTextResult <$> CS.addClause l wca
82−handleCommand (Import fp outfp _ (AddImplicitImport mn)) = do
72+ Import fp outfp _ (AddImplicitImport mn) -> do
83− rs <- addImplicitImport fp mn
73+ rs <- addImplicitImport fp mn
84− answerRequest outfp rs
74+ answerRequest outfp rs
85−handleCommand (Import fp outfp filters (AddImportForIdentifier ident)) = do
75+ Import fp outfp filters (AddImportForIdentifier ident) -> do
86− rs <- addImportForIdentifier fp ident filters
76+ rs <- addImportForIdentifier fp ident filters
87− case rs of
77+ case rs of
88− Right rs' -> answerRequest outfp rs'
78+ Right rs' -> answerRequest outfp rs'
79+ Left question ->
89− Left question -> pure $ CompletionResult (mapMaybe completionFromMatch question)
80+ pure (CompletionResult (map completionFromMatch question))
90−handleCommand (Rebuild file) =
81+ Rebuild file ->
91− rebuildFile file
82+ rebuildFile file
92−handleCommand Cwd =
83+ Cwd ->
93− TextResult . T.pack <$> liftIO getCurrentDirectory
84+ TextResult . toS <$> liftIO getCurrentDirectory
85+ Reset ->
94−handleCommand Reset = resetPscIdeState *> pure (TextResult "State has been reset.")
86+ resetIdeState $> TextResult "State has been reset."
87+ Quit ->
95−handleCommand Quit = liftIO exitSuccess
88+ liftIO exitSuccess
96−
89+
97−findCompletions :: (PscIde m, MonadLogger m) =>
90+findCompletions :: Ide m =>
98− [Filter] -> Matcher -> Maybe P.ModuleName -> m Success
91+ [Filter] -> Matcher IdeDeclaration -> Maybe P.ModuleName -> m Success
99findCompletions filters matcher currentModule = do
92findCompletions filters matcher currentModule = do
100− modules <- getAllModulesWithReexportsAndCache currentModule
93+ modules <- getAllModules currentModule
101− pure . CompletionResult . mapMaybe completionFromMatch . getCompletions filters matcher $ modules
94+ pure . CompletionResult . map completionFromMatch . getCompletions filters matcher $ modules
102
95
103−findType :: (PscIde m, MonadLogger m) =>
96+findType :: Ide m =>
104− DeclIdent -> [Filter] -> Maybe P.ModuleName -> m Success
97+ Text -> [Filter] -> Maybe P.ModuleName -> m Success
105findType search filters currentModule = do
98findType search filters currentModule = do
106− modules <- getAllModulesWithReexportsAndCache currentModule
99+ modules <- getAllModules currentModule
107− pure . CompletionResult . mapMaybe completionFromMatch . getExactMatches search filters $ modules
100+ pure . InfoResult . map infoFromMatch . getExactMatches search filters $ modules
108
101
109−findPursuitCompletions :: (MonadIO m, MonadLogger m) =>
102+findPursuitCompletions :: MonadIO m =>
110 PursuitQuery -> m Success
103 PursuitQuery -> m Success
111findPursuitCompletions (PursuitQuery q) =
104findPursuitCompletions (PursuitQuery q) =
112 PursuitResult <$> liftIO (searchPursuitForDeclarations q)
105 PursuitResult <$> liftIO (searchPursuitForDeclarations q)
113
106
114−findPursuitPackages :: (MonadIO m, MonadLogger m) =>
107+findPursuitPackages :: MonadIO m =>
115 PursuitQuery -> m Success
108 PursuitQuery -> m Success
116findPursuitPackages (PursuitQuery q) =
109findPursuitPackages (PursuitQuery q) =
117 PursuitResult <$> liftIO (findPackagesForModuleIdent q)
110 PursuitResult <$> liftIO (findPackagesForModuleIdent q)
118
111
119−loadExtern :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
112+printModules :: Ide m => m Success
120− FilePath -> m ()
113+printModules = ModuleList . map runModuleNameT <$> getLoadedModulenames
121−loadExtern fp = do
122− m <- readExternFile fp
123− insertModule m
124
114
125−printModules :: (PscIde m) => m Success
115+outputDirectory :: Ide m => m FilePath
126−printModules = printModules' . pscIdeStateModules <$> getPscIdeState
116+outputDirectory = do
127−
117+ outputPath <- confOutputPath . ideConfiguration <$> ask
128−printModules' :: M.Map ModuleIdent [ExternDecl] -> Success
118+ cwd <- liftIO getCurrentDirectory
129−printModules' = ModuleList . M.keys
119+ pure (cwd </> outputPath)
130
120
131−listAvailableModules :: PscIde m => m Success
121+listAvailableModules :: Ide m => m Success
132listAvailableModules = do
122listAvailableModules = do
133− outputPath <- confOutputPath . envConfiguration <$> ask
123+ oDir <- outputDirectory
134 liftIO $ do
124 liftIO $ do
135− cwd <- getCurrentDirectory
136− dirs <- getDirectoryContents (cwd </> outputPath)
125+ contents <- getDirectoryContents oDir
137− return (ModuleList (listAvailableModules' dirs))
138−
139−listAvailableModules' :: [FilePath] -> [Text]
140−listAvailableModules' dirs =
141− let cleanedModules = filter (`notElem` [".", ".."]) dirs
126+ let cleaned = filter (`notElem` [".", ".."]) contents
142− in map T.pack cleanedModules
127+ return (ModuleList (map toS cleaned))
143
128
144−caseSplit :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
129+caseSplit :: (Ide m, MonadError PscIdeError m) =>
145 Text -> Int -> Int -> CS.WildcardAnnotations -> Text -> m Success
130 Text -> Int -> Int -> CS.WildcardAnnotations -> Text -> m Success
146caseSplit l b e csa t = do
131caseSplit l b e csa t = do
147 patterns <- CS.makePattern l b e csa <$> CS.caseSplit t
132 patterns <- CS.makePattern l b e csa <$> CS.caseSplit t
148 pure (MultilineTextResult patterns)
133 pure (MultilineTextResult patterns)
149
134
150−addClause :: Text -> CS.WildcardAnnotations -> Success
135+-- | Finds all the externs.json files inside the output folder and returns the
151−addClause t wca = MultilineTextResult (CS.addClause t wca)
136+-- corresponding Modulenames
152−
153−importsForFile :: (MonadIO m, MonadLogger m, MonadError PscIdeError m) =>
154− FilePath -> m Success
155−importsForFile fp = do
156− imports <- getImportsForFile fp
157− pure (ImportList imports)
158−
159−-- | The first argument is a set of modules to load. The second argument
160−-- denotes modules for which to load dependencies
161−loadModulesAndDeps :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
162− [ModuleIdent] -> [ModuleIdent] -> m Success
163−loadModulesAndDeps mods deps = do
164− r1 <- mapM loadModule (mods ++ deps)
165− r2 <- mapM loadModuleDependencies deps
166− let moduleResults = T.concat r1
167− let dependencyResults = T.concat r2
168− pure (TextResult (moduleResults <> ", " <> dependencyResults))
169−
170−loadModuleDependencies ::(PscIde m, MonadLogger m, MonadError PscIdeError m) =>
171− ModuleIdent -> m Text
172−loadModuleDependencies moduleName = do
173− m <- getModule moduleName
174− case getDependenciesForModule <$> m of
175− Just deps -> do
176− mapM_ loadModule deps
177− -- We need to load the modules, that get reexported from the dependencies
178− depModules <- catMaybes <$> mapM getModule deps
179− -- What to do with errors here? This basically means a reexported dependency
180− -- doesn't exist in the output/ folder
181− traverse_ loadReexports depModules
182− pure ("Dependencies for " <> moduleName <> " loaded.")
183− Nothing -> throwError (ModuleNotFound moduleName)
184−
185−loadReexports :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
137+findAvailableExterns :: (Ide m, MonadError PscIdeError m) => m [P.ModuleName]
186− Module -> m [ModuleIdent]
138+findAvailableExterns = do
187−loadReexports m = case getReexports m of
139+ oDir <- outputDirectory
188− [] -> pure []
189− exportDeps -> do
190− -- I'm fine with this crashing on a failed pattern match.
191− -- If this ever fails I'll need to look at GADTs
192− let reexports = map (\(Export mn) -> mn) exportDeps
193− $(logDebug) ("Loading reexports for module: " <> fst m <>
194− " reexports: " <> T.intercalate ", " reexports)
195− traverse_ loadModule reexports
196− exportDepsModules <- catMaybes <$> traverse getModule reexports
197− exportDepDeps <- traverse loadReexports exportDepsModules
198− return $ concat exportDepDeps
199−
200−getDependenciesForModule :: Module -> [ModuleIdent]
201−getDependenciesForModule (_, decls) = mapMaybe getDependencyName decls
202− where getDependencyName (Dependency dependencyName _ _) = Just dependencyName
203− getDependencyName _ = Nothing
204−
205−loadModule :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
206− ModuleIdent -> m Text
207−loadModule "Prim" = pure "Prim won't be loaded"
208−loadModule mn = do
209− path <- filePathFromModule mn
210− loadExtern path
211− $(logDebug) ("Loaded extern file at: " <> T.pack path)
212− pure ("Loaded extern file at: " <> T.pack path)
213−
214−loadAllModules :: (PscIde m, MonadLogger m, MonadError PscIdeError m) => m Success
215−loadAllModules = do
216− outputPath <- confOutputPath . envConfiguration <$> ask
217− cwd <- liftIO getCurrentDirectory
218− let outputDirectory = cwd </> outputPath
219− liftIO (doesDirectoryExist outputDirectory)
140+ unlessM (liftIO (doesDirectoryExist oDir))
220− >>= flip unless (throwError (GeneralError "Couldn't locate your output directory"))
141+ (throwError (GeneralError "Couldn't locate your output directory."))
142+ liftIO $ do
221− liftIO (getDirectoryContents outputDirectory)
143+ directories <- getDirectoryContents oDir
222− >>= liftIO . traverse (getExternsPath outputDirectory)
144+ moduleNames <- filterM (containsExterns oDir) directories
223− >>= traverse_ loadExtern . catMaybes
145+ pure (P.moduleNameFromString <$> moduleNames)
224− pure (TextResult "All modules loaded.")
225 where
146 where
147+ -- Takes the output directory and a filepath like "Monad.Control.Eff" and
148+ -- looks up, whether that folder contains an externs.json
226− getExternsPath :: FilePath -> FilePath -> IO (Maybe FilePath)
149+ containsExterns :: FilePath -> FilePath -> IO Bool
227− getExternsPath outputDirectory d
150+ containsExterns oDir d
228− | d `elem` [".", ".."] = pure Nothing
151+ | d `elem` [".", ".."] = pure False
229 | otherwise = do
152 | otherwise = do
230− let file = outputDirectory </> d </> "externs.json"
153+ let file = oDir </> d </> "externs.json"
231− ex <- doesFileExist file
154+ doesFileExist file
232− if ex
155+
233− then pure (Just file)
156+-- | Finds all matches for the globs specified at the commandline
234− else pure Nothing
157+findAllSourceFiles :: Ide m => m [FilePath]
235−
158+findAllSourceFiles = do
159+ globs <- confGlobs . ideConfiguration <$> ask
160+ liftIO (concatMapM glob globs)
161+
162+-- | Looks up the ExternsFiles for the given Modulenames and loads them into the
163+-- server state. Then proceeds to parse all the specified sourcefiles and
164+-- inserts their ASTs into the state. Finally kicks off an async worker, which
165+-- populates Stage 2 and 3 of the state.
166+loadModules
236−filePathFromModule :: (PscIde m, MonadError PscIdeError m) =>
167+ :: (Ide m, MonadError PscIdeError m, MonadLogger m)
237− ModuleIdent -> m FilePath
168+ => [P.ModuleName]
238−filePathFromModule moduleName = do
169+ -> m Success
239− outputPath <- confOutputPath . envConfiguration <$> ask
170+loadModules moduleNames = do
240− cwd <- liftIO getCurrentDirectory
171+ -- We resolve all the modulenames to externs files and load these into memory.
241− let path = cwd </> outputPath </> T.unpack moduleName </> "externs.json"
172+ oDir <- outputDirectory
242− ex <- liftIO $ doesFileExist path
173+ let efPaths =
243− if ex
174+ map (\mn -> oDir </> P.runModuleName mn </> "externs.json") moduleNames
244− then pure path
175+ efiles <- traverse readExternFile efPaths
245− else throwError (ModuleFileNotFound moduleName)
176+ traverse_ insertExterns efiles
177+
178+ -- We parse all source files, log eventual parse failures if the debug flag
179+ -- was set and insert the succesful parses into the state.
180+ (failures, allModules) <-
181+ partitionEithers <$> (traverse parseModule =<< findAllSourceFiles)
182+ unless (null failures) $
183+ $(logDebug) ("Failed to parse: " <> show failures)
184+ traverse_ insertModule allModules
185+
186+ -- Finally we kick off the worker with @async@ and return the number of
187+ -- successfully parsed modules.
188+ env <- ask
189+ let runLogger =
190+ runStdoutLoggingT
191+ . filterLogger (\_ _ -> confDebug (ideConfiguration env))
192+ -- populateStage2 and 3 return Unit for now, so it's fine to discard this
193+ -- result. We might want to block on this in a benchmarking situation.
194+ _ <- liftIO (async (runLogger (runReaderT (populateStage2 *> populateStage3) env)))
195+ pure (TextResult ("Loaded " <> show (length efiles) <> " modules and "
196+ <> show (length allModules) <> " source files."))
src/Language/PureScript/Ide/CaseSplit.hs+24−30
@@ -13,7 +13,6 @@
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
14
14
15{-# LANGUAGE OverloadedStrings #-}
15{-# LANGUAGE OverloadedStrings #-}
16−{-# LANGUAGE PackageImports #-}
17
16
18module Language.PureScript.Ide.CaseSplit
17module Language.PureScript.Ide.CaseSplit
19 ( WildcardAnnotations()
18 ( WildcardAnnotations()
@@ -24,26 +23,19 @@ module Language.PureScript.Ide.CaseSplit
24 , caseSplit
23 , caseSplit
25 ) where
24 ) where
26
25
27−import Prelude ()
26+import Protolude hiding (Constructor)
28−import Prelude.Compat hiding (lex)
29
27
30−import Control.Arrow (second)
31−import Control.Monad.Error.Class
32−import "monad-logger" Control.Monad.Logger
33−import Data.List (find)
34−import Data.Monoid
35−import Data.Text (Text)
36import qualified Data.Text as T
28import qualified Data.Text as T
37import qualified Language.PureScript as P
29import qualified Language.PureScript as P
38
30
39import Language.PureScript.Externs
31import Language.PureScript.Externs
40import Language.PureScript.Ide.Error
32import Language.PureScript.Ide.Error
41−import Language.PureScript.Ide.Externs (unwrapPositioned)
42import Language.PureScript.Ide.State
33import Language.PureScript.Ide.State
43import Language.PureScript.Ide.Types
34import Language.PureScript.Ide.Types
44import Language.PureScript.Ide.Util
35import Language.PureScript.Ide.Util
45
36
46import Text.Parsec as Parsec
37import Text.Parsec as Parsec
38+import qualified Text.PrettyPrint.Boxes as Box
47
39
48type Constructor = (P.ProperName 'P.ConstructorName, [P.Type])
40type Constructor = (P.ProperName 'P.ConstructorName, [P.Type])
49
41
@@ -55,17 +47,17 @@ explicitAnnotations = WildcardAnnotations True
55noAnnotations :: WildcardAnnotations
47noAnnotations :: WildcardAnnotations
56noAnnotations = WildcardAnnotations False
48noAnnotations = WildcardAnnotations False
57
49
58−caseSplit :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
50+caseSplit :: (Ide m, MonadError PscIdeError m) =>
59 Text -> m [Constructor]
51 Text -> m [Constructor]
60caseSplit q = do
52caseSplit q = do
61− type' <- parseType' (T.unpack q)
53+ type' <- parseType' q
62 (tc, args) <- splitTypeConstructor type'
54 (tc, args) <- splitTypeConstructor type'
63 (EDType _ _ (P.DataType typeVars ctors)) <- findTypeDeclaration tc
55 (EDType _ _ (P.DataType typeVars ctors)) <- findTypeDeclaration tc
64 let applyTypeVars = P.everywhereOnTypes (P.replaceAllTypeVars (zip (map fst typeVars) args))
56 let applyTypeVars = P.everywhereOnTypes (P.replaceAllTypeVars (zip (map fst typeVars) args))
65 let appliedCtors = map (second (map applyTypeVars)) ctors
57 let appliedCtors = map (second (map applyTypeVars)) ctors
66 pure appliedCtors
58 pure appliedCtors
67
59
68−findTypeDeclaration :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
60+findTypeDeclaration :: (Ide m, MonadError PscIdeError m) =>
69 P.ProperName 'P.TypeName -> m ExternsDeclaration
61 P.ProperName 'P.TypeName -> m ExternsDeclaration
70findTypeDeclaration q = do
62findTypeDeclaration q = do
71 efs <- getExternFiles
63 efs <- getExternFiles
@@ -115,39 +107,41 @@ makePattern t x y wsa = makePattern' (T.take x t) (T.drop y t)
115 where
107 where
116 makePattern' lhs rhs = map (\ctor -> lhs <> prettyCtor wsa ctor <> rhs)
108 makePattern' lhs rhs = map (\ctor -> lhs <> prettyCtor wsa ctor <> rhs)
117
109
118−addClause :: Text -> WildcardAnnotations -> [Text]
110+addClause :: (MonadError PscIdeError m) => Text -> WildcardAnnotations -> m [Text]
119−addClause s wca =
111+addClause s wca = do
120− let (fName, fType) = parseTypeDeclaration' (T.unpack s)
112+ (fName, fType) <- parseTypeDeclaration' s
121− (args, _) = splitFunctionType fType
113+ let args = splitFunctionType fType
122 template = runIdentT fName <> " " <>
114 template = runIdentT fName <> " " <>
123 T.unwords (map (prettyPrintWildcard wca) args) <>
115 T.unwords (map (prettyPrintWildcard wca) args) <>
124 " = ?" <> (T.strip . runIdentT $ fName)
116 " = ?" <> (T.strip . runIdentT $ fName)
125− in [s, template]
117+ pure [s, template]
126
118
127parseType' :: (MonadError PscIdeError m) =>
119parseType' :: (MonadError PscIdeError m) =>
128− String -> m P.Type
120+ Text -> m P.Type
129parseType' s =
121parseType' s =
130− case P.lex "<psc-ide>" s >>= P.runTokenParser "<psc-ide>" (P.parseType <* Parsec.eof) of
122+ case P.lex "<psc-ide>" (toS s) >>= P.runTokenParser "<psc-ide>" (P.parseType <* Parsec.eof) of
131 Right type' -> pure type'
123 Right type' -> pure type'
132 Left err ->
124 Left err ->
133 throwError (GeneralError ("Parsing the splittype failed with:"
125 throwError (GeneralError ("Parsing the splittype failed with:"
134− ++ show err))
126+ <> show err))
135
127
136−parseTypeDeclaration' :: String -> (P.Ident, P.Type)
128+parseTypeDeclaration' :: (MonadError PscIdeError m) => Text -> m (P.Ident, P.Type)
137parseTypeDeclaration' s =
129parseTypeDeclaration' s =
138 let x = do
130 let x = do
139− ts <- P.lex "" s
131+ ts <- P.lex "" (toS s)
140 P.runTokenParser "" (P.parseDeclaration <* Parsec.eof) ts
132 P.runTokenParser "" (P.parseDeclaration <* Parsec.eof) ts
141 in
133 in
142 case unwrapPositioned <$> x of
134 case unwrapPositioned <$> x of
143− Right (P.TypeDeclaration i t) -> (i, t)
135+ Right (P.TypeDeclaration i t) -> pure (i, t)
144− y -> error (show y)
136+ Right _ -> throwError (GeneralError "Found a non-type-declaration")
145−
137+ Left err ->
138+ throwError (GeneralError ("Parsing the type signature failed with: "
139+ <> toS (Box.render (P.prettyPrintParseError err))))
140+
146−splitFunctionType :: P.Type -> ([P.Type], P.Type)
141+splitFunctionType :: P.Type -> [P.Type]
147−splitFunctionType t = (arguments, returns)
142+splitFunctionType t = fromMaybe [] arguments
148 where
143 where
149− returns = last splitted
150− arguments = init splitted
144+ arguments = initMay splitted
151 splitted = splitType' t
145 splitted = splitType' t
152 splitType' (P.ForAll _ t' _) = splitType' t'
146 splitType' (P.ForAll _ t' _) = splitType' t'
153 splitType' (P.ConstrainedType _ t') = splitType' t'
147 splitType' (P.ConstrainedType _ t') = splitType' t'
src/Language/PureScript/Ide/Command.hs+11−18
@@ -16,31 +16,26 @@
16
16
17module Language.PureScript.Ide.Command where
17module Language.PureScript.Ide.Command where
18
18
19−import Prelude ()
19+import Protolude
20−import Prelude.Compat
21
20
22−import Control.Monad
23import Data.Aeson
21import Data.Aeson
24−import Data.Text (Text)
25import qualified Language.PureScript as P
22import qualified Language.PureScript as P
26import Language.PureScript.Ide.CaseSplit
23import Language.PureScript.Ide.CaseSplit
27import Language.PureScript.Ide.Filter
24import Language.PureScript.Ide.Filter
28import Language.PureScript.Ide.Matcher
25import Language.PureScript.Ide.Matcher
29import Language.PureScript.Ide.Types
26import Language.PureScript.Ide.Types
27+import System.FilePath
30
28
31data Command
29data Command
32− = Load
30+ = Load [P.ModuleName]
33− { loadModules :: [ModuleIdent]
34− , loadDependencies :: [ModuleIdent]
35− }
36 | Type
31 | Type
37− { typeSearch :: DeclIdent
32+ { typeSearch :: Text
38 , typeFilters :: [Filter]
33 , typeFilters :: [Filter]
39 , typeCurrentModule :: Maybe P.ModuleName
34 , typeCurrentModule :: Maybe P.ModuleName
40 }
35 }
41 | Complete
36 | Complete
42 { completeFilters :: [Filter]
37 { completeFilters :: [Filter]
43− , completeMatcher :: Matcher
38+ , completeMatcher :: Matcher IdeDeclaration
44 , completeCurrentModule :: Maybe P.ModuleName
39 , completeCurrentModule :: Maybe P.ModuleName
45 }
40 }
46 | Pursuit
41 | Pursuit
@@ -68,12 +63,12 @@ data Command
68
63
69data ImportCommand
64data ImportCommand
70 = AddImplicitImport P.ModuleName
65 = AddImplicitImport P.ModuleName
71− | AddImportForIdentifier DeclIdent
66+ | AddImportForIdentifier Text
72 deriving (Show, Eq)
67 deriving (Show, Eq)
73
68
74instance FromJSON ImportCommand where
69instance FromJSON ImportCommand where
75 parseJSON = withObject "ImportCommand" $ \o -> do
70 parseJSON = withObject "ImportCommand" $ \o -> do
76− (command :: String) <- o .: "importCommand"
71+ (command :: Text) <- o .: "importCommand"
77 case command of
72 case command of
78 "addImplicitImport" ->
73 "addImplicitImport" ->
79 AddImplicitImport <$> (P.moduleNameFromString <$> o .: "module")
74 AddImplicitImport <$> (P.moduleNameFromString <$> o .: "module")
@@ -85,7 +80,7 @@ data ListType = LoadedModules | Imports FilePath | AvailableModules
85
80
86instance FromJSON ListType where
81instance FromJSON ListType where
87 parseJSON = withObject "ListType" $ \o -> do
82 parseJSON = withObject "ListType" $ \o -> do
88− (listType' :: String) <- o .: "type"
83+ (listType' :: Text) <- o .: "type"
89 case listType' of
84 case listType' of
90 "import" -> Imports <$> o .: "file"
85 "import" -> Imports <$> o .: "file"
91 "loadedModules" -> pure LoadedModules
86 "loadedModules" -> pure LoadedModules
@@ -94,7 +89,7 @@ instance FromJSON ListType where
94
89
95instance FromJSON Command where
90instance FromJSON Command where
96 parseJSON = withObject "command" $ \o -> do
91 parseJSON = withObject "command" $ \o -> do
97− (command :: String) <- o .: "command"
92+ (command :: Text) <- o .: "command"
98 case command of
93 case command of
99 "list" -> List <$> o .:? "params" .!= LoadedModules
94 "list" -> List <$> o .:? "params" .!= LoadedModules
100 "cwd" -> pure Cwd
95 "cwd" -> pure Cwd
@@ -103,11 +98,9 @@ instance FromJSON Command where
103 "load" -> do
98 "load" -> do
104 params' <- o .:? "params"
99 params' <- o .:? "params"
105 case params' of
100 case params' of
106− Nothing -> pure (Load [] [])
101+ Nothing -> pure (Load [])
107 Just params ->
102 Just params ->
108− Load
109− <$> params .:? "modules" .!= []
103+ Load <$> (map P.moduleNameFromString <$> params .:? "modules" .!= [])
110− <*> params .:? "dependencies" .!= []
111 "type" -> do
104 "type" -> do
112 params <- o .: "params"
105 params <- o .: "params"
113 Type
106 Type
src/Language/PureScript/Ide/Completion.hs+17−17
@@ -1,32 +1,32 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2module Language.PureScript.Ide.Completion
2module Language.PureScript.Ide.Completion
3+ ( getCompletions
3− (getCompletions, getExactMatches)
4+ , getExactMatches
4− where
5+ ) where
5
6
6−import Prelude ()
7+import Protolude
7−import Prelude.Compat
8
8
9−import Data.Maybe (mapMaybe)
10import Language.PureScript.Ide.Filter
9import Language.PureScript.Ide.Filter
11import Language.PureScript.Ide.Matcher
10import Language.PureScript.Ide.Matcher
12import Language.PureScript.Ide.Types
11import Language.PureScript.Ide.Types
12+import Language.PureScript.Ide.Util
13
13
14-- | Applies the CompletionFilters and the Matcher to the given Modules
14-- | Applies the CompletionFilters and the Matcher to the given Modules
15-- and sorts the found Completions according to the Matching Score
15-- and sorts the found Completions according to the Matching Score
16−getCompletions :: [Filter] -> Matcher -> [Module] -> [Match]
16+getCompletions
17+ :: [Filter]
18+ -> Matcher IdeDeclaration
19+ -> [Module]
20+ -> [Match IdeDeclaration]
17getCompletions filters matcher modules =
21getCompletions filters matcher modules =
18− runMatcher matcher $ completionsFromModules (applyFilters filters modules)
22+ runMatcher matcher (completionsFromModules discardAnn (applyFilters filters modules))
19
23
20−getExactMatches :: DeclIdent -> [Filter] -> [Module] -> [Match]
24+getExactMatches :: Text -> [Filter] -> [Module] -> [Match IdeDeclarationAnn]
21getExactMatches search filters modules =
25getExactMatches search filters modules =
22− completionsFromModules $
23− applyFilters (equalityFilter search : filters) modules
26+ completionsFromModules identity (applyFilters (equalityFilter search : filters) modules)
24
27
25−completionsFromModules :: [Module] -> [Match]
28+completionsFromModules :: (IdeDeclarationAnn -> a) -> [Module] -> [Match a]
26−completionsFromModules = foldMap completionFromModule
29+completionsFromModules f = foldMap completionFromModule
27 where
30 where
28− completionFromModule :: Module -> [Match]
31+ completionFromModule (moduleName, decls) =
29− completionFromModule (moduleIdent, decls) = mapMaybe (matchFromDecl moduleIdent) decls
32+ map (\x -> Match (moduleName, f x)) decls
30−
31−matchFromDecl :: ModuleIdent -> ExternDecl -> Maybe Match
32−matchFromDecl mi = Just . Match mi
src/Language/PureScript/Ide/Conversions.hsnew file+35
@@ -0,0 +1,35 @@
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 Protolude
18+import Data.Text (unwords, lines, strip)
19+import qualified Language.PureScript as P
20+
21+runProperNameT :: P.ProperName a -> Text
22+runProperNameT = toS . P.runProperName
23+
24+runIdentT :: P.Ident -> Text
25+runIdentT = toS . P.runIdent
26+
27+runOpNameT :: P.OpName a -> Text
28+runOpNameT = toS . P.runOpName
29+
30+runModuleNameT :: P.ModuleName -> Text
31+runModuleNameT = toS . P.runModuleName
32+
33+prettyTypeT :: P.Type -> Text
34+prettyTypeT = unwords . map strip . lines . toS . P.prettyPrintType
35+
src/Language/PureScript/Ide/Error.hs+8−12
@@ -14,25 +14,21 @@
14
14
15{-# LANGUAGE OverloadedStrings #-}
15{-# LANGUAGE OverloadedStrings #-}
16module Language.PureScript.Ide.Error
16module Language.PureScript.Ide.Error
17− (ErrorMsg, PscIdeError(..), textError)
17+ ( PscIdeError(..)
18− where
18+ ) where
19
19
20−import Prelude.Compat
20+import Protolude
21import Data.Aeson
21import Data.Aeson
22−import Data.Monoid
23−import Data.Text (Text, pack)
24import Language.PureScript.Errors.JSON
22import Language.PureScript.Errors.JSON
25import Language.PureScript.Ide.Types (ModuleIdent)
23import Language.PureScript.Ide.Types (ModuleIdent)
26import qualified Text.Parsec.Error as P
24import qualified Text.Parsec.Error as P
27
25
28−type ErrorMsg = String
29−
30data PscIdeError
26data PscIdeError
31− = GeneralError ErrorMsg
27+ = GeneralError Text
32 | NotFound Text
28 | NotFound Text
33 | ModuleNotFound ModuleIdent
29 | ModuleNotFound ModuleIdent
34 | ModuleFileNotFound ModuleIdent
30 | ModuleFileNotFound ModuleIdent
35− | ParseError P.ParseError ErrorMsg
31+ | ParseError P.ParseError Text
36 | RebuildError [JSONError]
32 | RebuildError [JSONError]
37
33
38instance ToJSON PscIdeError where
34instance ToJSON PscIdeError where
@@ -46,7 +42,7 @@ instance ToJSON PscIdeError where
46 ]
42 ]
47
43
48textError :: PscIdeError -> Text
44textError :: PscIdeError -> Text
49−textError (GeneralError msg) = pack msg
45+textError (GeneralError msg) = msg
50textError (NotFound ident) = "Symbol '" <> ident <> "' not found."
46textError (NotFound ident) = "Symbol '" <> ident <> "' not found."
51textError (ModuleNotFound ident) = "Module '" <> ident <> "' not found."
47textError (ModuleNotFound ident) = "Module '" <> ident <> "' not found."
52textError (ModuleFileNotFound ident) = "Extern file for module " <> ident <>" could not be found"
48textError (ModuleFileNotFound ident) = "Extern file for module " <> ident <>" could not be found"
@@ -54,5 +50,5 @@ textError (ParseError parseError msg) = let escape = show
54 -- escape newlines and other special
50 -- escape newlines and other special
55 -- chars so we can send the error
51 -- chars so we can send the error
56 -- over the socket as a single line
52 -- over the socket as a single line
57− in pack $ msg <> ": " <> show (escape parseError)
53+ in msg <> ": " <> escape parseError
58−textError (RebuildError err) = pack (show err)
54+textError (RebuildError err) = show err
src/Language/PureScript/Ide/Externs.hs+62−63
@@ -12,115 +12,114 @@
12-- Handles externs files for psc-ide
12-- Handles externs files for psc-ide
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
14
14
15−{-# LANGUAGE OverloadedStrings #-}
15+{-# LANGUAGE OverloadedStrings #-}
16+{-# LANGUAGE RecordWildCards #-}
17+{-# LANGUAGE FlexibleContexts #-}
16
18
17module Language.PureScript.Ide.Externs
19module Language.PureScript.Ide.Externs
18− ( ExternDecl(..),
19− ModuleIdent,
20− DeclIdent,
21− readExternFile,
20+ ( readExternFile,
22 convertExterns,
21 convertExterns,
23− unwrapPositioned,
22+ annotateLocations
24− unwrapPositionedRef
25 ) where
23 ) where
26
24
27−import Prelude ()
25+import Protolude
28−import Prelude.Compat
29
26
30−import Control.Monad.Error.Class
31−import Control.Monad.IO.Class
32import Data.Aeson (decodeStrict)
27import Data.Aeson (decodeStrict)
33import Data.List (nub)
28import Data.List (nub)
34−import Data.Maybe (mapMaybe)
35−import Data.Monoid
36−import Data.Text (Text)
37−import qualified Data.Text as T
29+import qualified Data.Map as Map
38import qualified Data.ByteString as BS
30import qualified Data.ByteString as BS
39import Language.PureScript.Ide.Error (PscIdeError (..))
31import Language.PureScript.Ide.Error (PscIdeError (..))
40import Language.PureScript.Ide.Types
32import Language.PureScript.Ide.Types
41import Language.PureScript.Ide.Util
33import Language.PureScript.Ide.Util
42
34
43import qualified Language.PureScript as P
35import qualified Language.PureScript as P
36+import System.FilePath
44
37
45readExternFile :: (MonadIO m, MonadError PscIdeError m) =>
38readExternFile :: (MonadIO m, MonadError PscIdeError m) =>
46 FilePath -> m P.ExternsFile
39 FilePath -> m P.ExternsFile
47readExternFile fp = do
40readExternFile fp = do
48 parseResult <- liftIO (decodeStrict <$> BS.readFile fp)
41 parseResult <- liftIO (decodeStrict <$> BS.readFile fp)
49 case parseResult of
42 case parseResult of
50− Nothing -> throwError . GeneralError $ "Parsing the extern at: " ++ fp ++ " failed"
43+ Nothing -> throwError . GeneralError $ "Parsing the extern at: " <> toS fp <> " failed"
51 Just externs -> pure externs
44 Just externs -> pure externs
52
45
53−moduleNameToText :: P.ModuleName -> Text
46+convertExterns :: P.ExternsFile -> (Module, [(P.ModuleName, P.DeclarationRef)])
54−moduleNameToText = T.pack . P.runModuleName
47+convertExterns ef =
55−
48+ ((P.efModuleName ef, decls), exportDecls)
56−identToText :: P.Ident -> Text
57−identToText = T.pack . P.runIdent
58−
59−convertExterns :: P.ExternsFile -> Module
60−convertExterns ef = (moduleName, exportDecls ++ importDecls ++ decls ++ operatorDecls ++ tyOperatorDecls)
61 where
49 where
62− moduleName = moduleNameToText (P.efModuleName ef)
50+ decls = map
63− importDecls = convertImport <$> P.efImports ef
51+ (IdeDeclarationAnn emptyAnn)
52+ (cleanDeclarations ++ operatorDecls ++ tyOperatorDecls)
64 exportDecls = mapMaybe (convertExport . unwrapPositionedRef) (P.efExports ef)
53 exportDecls = mapMaybe (convertExport . unwrapPositionedRef) (P.efExports ef)
65 operatorDecls = convertOperator <$> P.efFixities ef
54 operatorDecls = convertOperator <$> P.efFixities ef
66 tyOperatorDecls = convertTypeOperator <$> P.efTypeFixities ef
55 tyOperatorDecls = convertTypeOperator <$> P.efTypeFixities ef
67− otherDecls = mapMaybe convertDecl (P.efDeclarations ef)
56+ declarations = mapMaybe convertDecl (P.efDeclarations ef)
68
57
69− typeClassFilter = foldMap removeTypeDeclarationsForClass (filter isTypeClassDeclaration otherDecls)
58+ typeClassFilter = foldMap removeTypeDeclarationsForClass (filter isTypeClassDeclaration declarations)
70− decls = nub $ appEndo typeClassFilter otherDecls
59+ cleanDeclarations = nub $ appEndo typeClassFilter declarations
71
60
72−removeTypeDeclarationsForClass :: ExternDecl -> Endo [ExternDecl]
61+removeTypeDeclarationsForClass :: IdeDeclaration -> Endo [IdeDeclaration]
73−removeTypeDeclarationsForClass (TypeClassDeclaration n) = Endo (filter notDuplicate)
62+removeTypeDeclarationsForClass (IdeTypeClass n) = Endo (filter notDuplicate)
74− where notDuplicate (TypeDeclaration n' _) = runProperNameT n /= runProperNameT n'
63+ where notDuplicate (IdeType n' _) = runProperNameT n /= runProperNameT n'
75− notDuplicate (TypeSynonymDeclaration n' _) = runProperNameT n /= runProperNameT n'
64+ notDuplicate (IdeTypeSynonym n' _) = runProperNameT n /= runProperNameT n'
76 notDuplicate _ = True
65 notDuplicate _ = True
77removeTypeDeclarationsForClass _ = mempty
66removeTypeDeclarationsForClass _ = mempty
78
67
79−isTypeClassDeclaration :: ExternDecl -> Bool
68+isTypeClassDeclaration :: IdeDeclaration -> Bool
80−isTypeClassDeclaration TypeClassDeclaration{} = True
69+isTypeClassDeclaration IdeTypeClass{} = True
81isTypeClassDeclaration _ = False
70isTypeClassDeclaration _ = False
82
71
83−convertImport :: P.ExternsImport -> ExternDecl
84−convertImport ei = Dependency
85− (moduleNameToText (P.eiModule ei))
86− []
87− (moduleNameToText <$> P.eiImportedAs ei)
88−
89−convertExport :: P.DeclarationRef -> Maybe ExternDecl
72+convertExport :: P.DeclarationRef -> Maybe (P.ModuleName, P.DeclarationRef)
90−convertExport (P.ModuleRef mn) = Just (Export (moduleNameToText mn))
73+convertExport (P.ReExportRef m r) = Just (m, r)
91convertExport _ = Nothing
74convertExport _ = Nothing
92
75
93−convertDecl :: P.ExternsDeclaration -> Maybe ExternDecl
76+convertDecl :: P.ExternsDeclaration -> Maybe IdeDeclaration
94−convertDecl P.EDType{..} = Just $ TypeDeclaration edTypeName edTypeKind
77+convertDecl P.EDType{..} = Just (IdeType edTypeName edTypeKind)
95−convertDecl P.EDTypeSynonym{..} = Just $
78+convertDecl P.EDTypeSynonym{..} =
96− TypeSynonymDeclaration edTypeSynonymName edTypeSynonymType
79+ Just (IdeTypeSynonym edTypeSynonymName edTypeSynonymType)
97convertDecl P.EDDataConstructor{..} = Just $
80convertDecl P.EDDataConstructor{..} = Just $
98− DataConstructor (runProperNameT edDataCtorName) edDataCtorTypeCtor edDataCtorType
81+ IdeDataConstructor edDataCtorName edDataCtorTypeCtor edDataCtorType
99convertDecl P.EDValue{..} = Just $
82convertDecl P.EDValue{..} = Just $
100− ValueDeclaration (identToText edValueName) edValueType
83+ IdeValue edValueName edValueType
101−convertDecl P.EDClass{..} = Just $ TypeClassDeclaration edClassName
84+convertDecl P.EDClass{..} = Just (IdeTypeClass edClassName)
102convertDecl P.EDInstance{} = Nothing
85convertDecl P.EDInstance{} = Nothing
103
86
104−convertOperator :: P.ExternsFixity -> ExternDecl
87+convertOperator :: P.ExternsFixity -> IdeDeclaration
105convertOperator P.ExternsFixity{..} =
88convertOperator P.ExternsFixity{..} =
106− ValueOperator
89+ IdeValueOperator
107 efOperator
90 efOperator
108− (T.pack (P.showQualified (either P.runIdent P.runProperName) efAlias))
91+ (toS (P.showQualified (either P.runIdent P.runProperName) efAlias))
109 efPrecedence
92 efPrecedence
110 efAssociativity
93 efAssociativity
111
94
112−convertTypeOperator :: P.ExternsTypeFixity -> ExternDecl
95+convertTypeOperator :: P.ExternsTypeFixity -> IdeDeclaration
113convertTypeOperator P.ExternsTypeFixity{..} =
96convertTypeOperator P.ExternsTypeFixity{..} =
114− TypeOperator
97+ IdeTypeOperator
115 efTypeOperator
98 efTypeOperator
116− (T.pack (P.showQualified P.runProperName efTypeAlias))
99+ (toS (P.showQualified P.runProperName efTypeAlias))
117 efTypePrecedence
100 efTypePrecedence
118 efTypeAssociativity
101 efTypeAssociativity
119
102
120−unwrapPositioned :: P.Declaration -> P.Declaration
103+annotateLocations :: Map (Either Text Text) P.SourceSpan -> Module -> Module
121−unwrapPositioned (P.PositionedDeclaration _ _ x) = x
104+annotateLocations ast (moduleName, decls) =
122−unwrapPositioned x = x
105+ (moduleName, map convertDeclaration decls)
123−
106+ where
124−unwrapPositionedRef :: P.DeclarationRef -> P.DeclarationRef
107+ convertDeclaration :: IdeDeclarationAnn -> IdeDeclarationAnn
125−unwrapPositionedRef (P.PositionedDeclarationRef _ _ x) = x
108+ convertDeclaration (IdeDeclarationAnn ann d) = case d of
126−unwrapPositionedRef x = x
109+ IdeValue i t ->
110+ annotateValue (runIdentT i) (IdeValue i t)
111+ IdeType i k ->
112+ annotateType (runProperNameT i) (IdeType i k)
113+ IdeTypeSynonym i t ->
114+ annotateType (runProperNameT i) (IdeTypeSynonym i t)
115+ IdeDataConstructor i tn t ->
116+ annotateValue (runProperNameT i) (IdeDataConstructor i tn t)
117+ IdeTypeClass i ->
118+ annotateType (runProperNameT i) (IdeTypeClass i)
119+ IdeValueOperator n i p a ->
120+ annotateValue i (IdeValueOperator n i p a)
121+ IdeTypeOperator n i p a ->
122+ annotateType i (IdeTypeOperator n i p a)
123+ where
124+ annotateValue x = IdeDeclarationAnn (ann {annLocation = Map.lookup (Left x) ast})
125+ annotateType x = IdeDeclarationAnn (ann {annLocation = Map.lookup (Right x) ast})
src/Language/PureScript/Ide/Filter.hs+17−50
@@ -20,22 +20,16 @@ module Language.PureScript.Ide.Filter
20 , moduleFilter
20 , moduleFilter
21 , prefixFilter
21 , prefixFilter
22 , equalityFilter
22 , equalityFilter
23− , dependencyFilter
24− , runFilter
25 , applyFilters
23 , applyFilters
26 ) where
24 ) where
27
25
28−import Prelude ()
26+import Protolude hiding (isPrefixOf)
29−import Prelude.Compat
30
27
31−import Control.Monad
32import Data.Aeson
28import Data.Aeson
33−import Data.Foldable
34−import Data.Maybe (listToMaybe, mapMaybe)
35−import Data.Monoid
36−import Data.Text (Text, isPrefixOf)
29+import Data.Text (isPrefixOf)
37import Language.PureScript.Ide.Types
30import Language.PureScript.Ide.Types
38import Language.PureScript.Ide.Util
31import Language.PureScript.Ide.Util
32+import qualified Language.PureScript as P
39
33
40newtype Filter = Filter (Endo [Module]) deriving(Monoid)
34newtype Filter = Filter (Endo [Module]) deriving(Monoid)
41
35
@@ -43,69 +37,46 @@ mkFilter :: ([Module] -> [Module]) -> Filter
43mkFilter = Filter . Endo
37mkFilter = Filter . Endo
44
38
45-- | Only keeps the given Modules
39-- | Only keeps the given Modules
46−moduleFilter :: [ModuleIdent] -> Filter
40+moduleFilter :: [P.ModuleName] -> Filter
47moduleFilter =
41moduleFilter =
48 mkFilter . moduleFilter'
42 mkFilter . moduleFilter'
49
43
50−moduleFilter' :: [ModuleIdent] -> [Module] -> [Module]
44+moduleFilter' :: [P.ModuleName] -> [Module] -> [Module]
51moduleFilter' moduleIdents = filter (flip elem moduleIdents . fst)
45moduleFilter' moduleIdents = filter (flip elem moduleIdents . fst)
52
46
53−-- | Only keeps the given Modules and all of their dependencies
54−dependencyFilter :: [ModuleIdent] -> Filter
55−dependencyFilter = mkFilter . dependencyFilter'
56−
57−dependencyFilter' :: [ModuleIdent] -> [Module] -> [Module]
58−dependencyFilter' moduleIdents mods =
59− moduleFilter' (concatMap (getDepForModule mods) moduleIdents) mods
60− where
61− getDepForModule :: [Module] -> ModuleIdent -> [ModuleIdent]
62− getDepForModule ms moduleIdent =
63− moduleIdent : maybe [] extractDeps (findModule moduleIdent ms)
64−
65− findModule :: ModuleIdent -> [Module] -> Maybe Module
66− findModule i ms = listToMaybe $ filter go ms
67− where go (mn, _) = i == mn
68−
69− extractDeps :: Module -> [ModuleIdent]
70− extractDeps = mapMaybe extractDep . snd
71− where extractDep (Dependency n _ _) = Just n
72− extractDep _ = Nothing
73−
74-- | Only keeps Identifiers that start with the given prefix
47-- | Only keeps Identifiers that start with the given prefix
75prefixFilter :: Text -> Filter
48prefixFilter :: Text -> Filter
76−prefixFilter "" = mkFilter id
49+prefixFilter "" = mkFilter identity
77prefixFilter t = mkFilter $ identFilter prefix t
50prefixFilter t = mkFilter $ identFilter prefix t
78 where
51 where
79− prefix :: ExternDecl -> Text -> Bool
52+ prefix :: IdeDeclaration -> Text -> Bool
80− prefix Export{} _ = False
81− prefix Dependency{} _ = False
82− prefix ed search = search `isPrefixOf` identifierFromExternDecl ed
53+ prefix ed search = search `isPrefixOf` identifierFromIdeDeclaration ed
83−
84
54
85-- | Only keeps Identifiers that are equal to the search string
55-- | Only keeps Identifiers that are equal to the search string
86equalityFilter :: Text -> Filter
56equalityFilter :: Text -> Filter
87equalityFilter = mkFilter . identFilter equality
57equalityFilter = mkFilter . identFilter equality
88 where
58 where
89− equality :: ExternDecl -> Text -> Bool
59+ equality :: IdeDeclaration -> Text -> Bool
90− equality ed search = identifierFromExternDecl ed == search
60+ equality ed search = identifierFromIdeDeclaration ed == search
91
61
92−identFilter :: (ExternDecl -> Text -> Bool ) -> Text -> [Module] -> [Module]
62+identFilter :: (IdeDeclaration -> Text -> Bool) -> Text -> [Module] -> [Module]
93identFilter predicate search =
63identFilter predicate search =
94 filter (not . null . snd) . fmap filterModuleDecls
64 filter (not . null . snd) . fmap filterModuleDecls
95 where
65 where
96 filterModuleDecls :: Module -> Module
66 filterModuleDecls :: Module -> Module
97− filterModuleDecls (moduleIdent,decls) =
67+ filterModuleDecls (moduleIdent, decls) =
98− (moduleIdent, filter (`predicate` search) decls)
68+ (moduleIdent, filter (flip predicate search . getDeclaration) decls)
69+ getDeclaration (IdeDeclarationAnn _ d) = d
99
70
100runFilter :: Filter -> [Module] -> [Module]
71runFilter :: Filter -> [Module] -> [Module]
101−runFilter (Filter f)= appEndo f
72+runFilter (Filter f) = appEndo f
102
73
103applyFilters :: [Filter] -> [Module] -> [Module]
74applyFilters :: [Filter] -> [Module] -> [Module]
104applyFilters = runFilter . fold
75applyFilters = runFilter . fold
105
76
106instance FromJSON Filter where
77instance FromJSON Filter where
107 parseJSON = withObject "filter" $ \o -> do
78 parseJSON = withObject "filter" $ \o -> do
108− (filter' :: String) <- o .: "filter"
79+ (filter' :: Text) <- o .: "filter"
109 case filter' of
80 case filter' of
110 "exact" -> do
81 "exact" -> do
111 params <- o .: "params"
82 params <- o .: "params"
@@ -117,10 +88,6 @@ instance FromJSON Filter where
117 return $ prefixFilter search
88 return $ prefixFilter search
118 "modules" -> do
89 "modules" -> do
119 params <- o .: "params"
90 params <- o .: "params"
120− modules <- params .: "modules"
91+ modules <- map P.moduleNameFromString <$> params .: "modules"
121 return $ moduleFilter modules
92 return $ moduleFilter modules
122− "dependencies" -> do
123− params <- o .: "params"
124− deps <- params .: "modules"
125− return $ dependencyFilter deps
126 _ -> mzero
93 _ -> mzero
src/Language/PureScript/Ide/Imports.hs+37−51
@@ -13,7 +13,6 @@
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
14
14
15{-# LANGUAGE OverloadedStrings #-}
15{-# LANGUAGE OverloadedStrings #-}
16−{-# LANGUAGE PackageImports #-}
17
16
18module Language.PureScript.Ide.Imports
17module Language.PureScript.Ide.Imports
19 ( addImplicitImport
18 ( addImplicitImport
@@ -30,28 +29,18 @@ module Language.PureScript.Ide.Imports
30 )
29 )
31 where
30 where
32
31
33−import Prelude.Compat
32+import Protolude
34−import Control.Applicative ((<|>))
35−import Control.Monad.Error.Class
36−import Control.Monad.IO.Class
37−import "monad-logger" Control.Monad.Logger
38−import Data.Bifunctor (first, second)
39−import Data.Function (on)
40−import qualified Data.List as List
41−import Data.Maybe (isNothing)
42−import Data.Monoid ((<>))
43−import Data.Text (Text)
44import qualified Data.Text as T
33import qualified Data.Text as T
34+import Data.List (nubBy, findIndex)
45import qualified Data.Text.IO as TIO
35import qualified Data.Text.IO as TIO
46import qualified Language.PureScript as P
36import qualified Language.PureScript as P
47import Language.PureScript.Ide.Completion
37import Language.PureScript.Ide.Completion
48import Language.PureScript.Ide.Error
38import Language.PureScript.Ide.Error
49−import Language.PureScript.Ide.Externs (unwrapPositioned,
50− unwrapPositionedRef)
51import Language.PureScript.Ide.Filter
39import Language.PureScript.Ide.Filter
52import Language.PureScript.Ide.State
40import Language.PureScript.Ide.State
53import Language.PureScript.Ide.Types
41import Language.PureScript.Ide.Types
54import Language.PureScript.Ide.Util
42import Language.PureScript.Ide.Util
43+import System.FilePath
55
44
56data Import = Import P.ModuleName P.ImportDeclarationType (Maybe P.ModuleName)
45data Import = Import P.ModuleName P.ImportDeclarationType (Maybe P.ModuleName)
57 deriving (Eq, Show)
46 deriving (Eq, Show)
@@ -87,7 +76,7 @@ parseImportsFromFile fp = do
87 Right res -> pure res
76 Right res -> pure res
88 Left err -> throwError (GeneralError err)
77 Left err -> throwError (GeneralError err)
89
78
90−parseImportsWithModuleName :: [Text] -> Either String (P.ModuleName, [Import])
79+parseImportsWithModuleName :: [Text] -> Either Text (P.ModuleName, [Import])
91parseImportsWithModuleName ls = do
80parseImportsWithModuleName ls = do
92 (P.Module _ _ mn decls _) <- moduleParse ls
81 (P.Module _ _ mn decls _) <- moduleParse ls
93 pure (mn, concatMap mkImport (unwrapPositioned <$> decls))
82 pure (mn, concatMap mkImport (unwrapPositioned <$> decls))
@@ -97,13 +86,13 @@ parseImportsWithModuleName ls = do
97 mkImport (P.ImportDeclaration mn it qual) = [Import mn it qual]
86 mkImport (P.ImportDeclaration mn it qual) = [Import mn it qual]
98 mkImport _ = []
87 mkImport _ = []
99
88
100−sliceImportSection :: [Text] -> Either String (P.ModuleName, [Text], [Import], [Text])
89+sliceImportSection :: [Text] -> Either Text (P.ModuleName, [Text], [Import], [Text])
101sliceImportSection ts =
90sliceImportSection ts =
102 case foldl step (ModuleHeader 0) (zip [0..] ts) of
91 case foldl step (ModuleHeader 0) (zip [0..] ts) of
103 Res start end ->
92 Res start end ->
104 let
93 let
105 (moduleHeader, (importSection, remainingFile)) =
94 (moduleHeader, (importSection, remainingFile)) =
106− List.splitAt (succ (end - start)) `second` List.splitAt start ts
95+ splitAt (succ (end - start)) `second` splitAt start ts
107 in
96 in
108 (\(mn, is) -> (mn, moduleHeader, is, remainingFile)) <$>
97 (\(mn, is) -> (mn, moduleHeader, is, remainingFile)) <$>
109 parseImportsWithModuleName (moduleHeader <> importSection)
98 parseImportsWithModuleName (moduleHeader <> importSection)
@@ -111,7 +100,7 @@ sliceImportSection ts =
111 -- If we don't find any imports, we insert a newline after the module
100 -- If we don't find any imports, we insert a newline after the module
112 -- declaration and begin a new importsection
101 -- declaration and begin a new importsection
113 ModuleHeader ix ->
102 ModuleHeader ix ->
114− let (moduleHeader, remainingFile) = List.splitAt (succ ix) ts
103+ let (moduleHeader, remainingFile) = splitAt (succ ix) ts
115 in
104 in
116 (\(mn, is) -> (mn, moduleHeader ++ [""], is, remainingFile)) <$>
105 (\(mn, is) -> (mn, moduleHeader ++ [""], is, remainingFile)) <$>
117 parseImportsWithModuleName moduleHeader
106 parseImportsWithModuleName moduleHeader
@@ -153,7 +142,7 @@ step (ImportSection start lastImportLine) (ix, l)
153 | otherwise = Res start lastImportLine
142 | otherwise = Res start lastImportLine
154step (Res start end) _ = Res start end
143step (Res start end) _ = Res start end
155
144
156−moduleParse :: [Text] -> Either String P.Module
145+moduleParse :: [Text] -> Either Text P.Module
157moduleParse t = first show $ do
146moduleParse t = first show $ do
158 tokens <- (P.lex "" . T.unpack . T.unlines) t
147 tokens <- (P.lex "" . T.unpack . T.unlines) t
159 P.runTokenParser "<psc-ide>" P.parseModule tokens
148 P.runTokenParser "<psc-ide>" P.parseModule tokens
@@ -182,8 +171,8 @@ addImplicitImport' imports mn =
182-- So @addExplicitImport "/File.purs" "bind" "Prelude"@ with an already existing
171-- So @addExplicitImport "/File.purs" "bind" "Prelude"@ with an already existing
183-- @import Prelude (bind)@ in the file File.purs returns @["import Prelude
172-- @import Prelude (bind)@ in the file File.purs returns @["import Prelude
184-- (bind, unit)"]@
173-- (bind, unit)"]@
185−addExplicitImport :: (MonadIO m, MonadError PscIdeError m, MonadLogger m) =>
174+addExplicitImport :: (MonadIO m, MonadError PscIdeError m) =>
186− FilePath -> ExternDecl -> P.ModuleName -> m [Text]
175+ FilePath -> IdeDeclaration -> P.ModuleName -> m [Text]
187addExplicitImport fp decl moduleName = do
176addExplicitImport fp decl moduleName = do
188 (mn, pre, imports, post) <- parseImportsFromFile fp
177 (mn, pre, imports, post) <- parseImportsFromFile fp
189 let newImportSection =
178 let newImportSection =
@@ -194,7 +183,7 @@ addExplicitImport fp decl moduleName = do
194 else addExplicitImport' decl moduleName imports
183 else addExplicitImport' decl moduleName imports
195 pure (pre ++ prettyPrintImportSection newImportSection ++ post)
184 pure (pre ++ prettyPrintImportSection newImportSection ++ post)
196
185
197−addExplicitImport' :: ExternDecl -> P.ModuleName -> [Import] -> [Import]
186+addExplicitImport' :: IdeDeclaration -> P.ModuleName -> [Import] -> [Import]
198addExplicitImport' decl moduleName imports =
187addExplicitImport' decl moduleName imports =
199 let
188 let
200 isImplicitlyImported =
189 isImplicitlyImported =
@@ -209,37 +198,34 @@ addExplicitImport' decl moduleName imports =
209 then imports
198 then imports
210 else updateAtFirstOrPrepend matches (insertDeclIntoImport decl) freshImport imports
199 else updateAtFirstOrPrepend matches (insertDeclIntoImport decl) freshImport imports
211 where
200 where
212− refFromDeclaration (TypeClassDeclaration n) =
201+ refFromDeclaration (IdeTypeClass n) =
213 P.TypeClassRef n
202 P.TypeClassRef n
214− refFromDeclaration (DataConstructor n tn _) =
203+ refFromDeclaration (IdeDataConstructor n tn _) =
215− P.TypeRef tn (Just [P.ProperName (T.unpack n)])
204+ P.TypeRef tn (Just [n])
216− refFromDeclaration (TypeDeclaration n _) =
205+ refFromDeclaration (IdeType n _) =
217 P.TypeRef n (Just [])
206 P.TypeRef n (Just [])
218− refFromDeclaration (ValueOperator op _ _ _) =
207+ refFromDeclaration (IdeValueOperator op _ _ _) =
219 P.ValueOpRef op
208 P.ValueOpRef op
220− refFromDeclaration (TypeOperator op _ _ _) =
209+ refFromDeclaration (IdeTypeOperator op _ _ _) =
221 P.TypeOpRef op
210 P.TypeOpRef op
222 refFromDeclaration d =
211 refFromDeclaration d =
223− P.ValueRef $ P.Ident $ T.unpack (identifierFromExternDecl d)
212+ P.ValueRef $ P.Ident $ T.unpack (identifierFromIdeDeclaration d)
224
213
225 -- | Adds a declaration to an import:
214 -- | Adds a declaration to an import:
226 -- TypeDeclaration "Maybe" + Data.Maybe (maybe) -> Data.Maybe(Maybe, maybe)
215 -- TypeDeclaration "Maybe" + Data.Maybe (maybe) -> Data.Maybe(Maybe, maybe)
227− insertDeclIntoImport :: ExternDecl -> Import -> Import
216+ insertDeclIntoImport :: IdeDeclaration -> Import -> Import
228 insertDeclIntoImport decl' (Import mn (P.Explicit refs) Nothing) =
217 insertDeclIntoImport decl' (Import mn (P.Explicit refs) Nothing) =
229 Import mn (P.Explicit (insertDeclIntoRefs decl' refs)) Nothing
218 Import mn (P.Explicit (insertDeclIntoRefs decl' refs)) Nothing
230 insertDeclIntoImport _ is = is
219 insertDeclIntoImport _ is = is
231
220
232− insertDeclIntoRefs :: ExternDecl -> [P.DeclarationRef] -> [P.DeclarationRef]
221+ insertDeclIntoRefs :: IdeDeclaration -> [P.DeclarationRef] -> [P.DeclarationRef]
233− insertDeclIntoRefs (DataConstructor dtor tn _) refs =
222+ insertDeclIntoRefs (IdeDataConstructor dtor tn _) refs =
234− let
235− dtor' = P.ProperName (T.unpack dtor)
236− in
237− updateAtFirstOrPrepend (matchType tn) (insertDtor dtor') (P.TypeRef tn (Just [dtor'])) refs
223+ updateAtFirstOrPrepend (matchType tn) (insertDtor dtor) (P.TypeRef tn (Just [dtor])) refs
238− insertDeclIntoRefs dr refs = List.nubBy ((==) `on` P.prettyPrintRef) (refFromDeclaration dr : refs)
224+ insertDeclIntoRefs dr refs = nubBy ((==) `on` P.prettyPrintRef) (refFromDeclaration dr : refs)
239
225
240 insertDtor dtor (P.TypeRef tn' dtors) =
226 insertDtor dtor (P.TypeRef tn' dtors) =
241 case dtors of
227 case dtors of
242− Just dtors' -> P.TypeRef tn' (Just (List.nub (dtor : dtors')))
228+ Just dtors' -> P.TypeRef tn' (Just (ordNub (dtor : dtors')))
243 -- This means the import was opened. We don't add anything in this case
229 -- This means the import was opened. We don't add anything in this case
244 -- import Data.Maybe (Maybe(..)) -> import Data.Maybe (Maybe(Just))
230 -- import Data.Maybe (Maybe(..)) -> import Data.Maybe (Maybe(Just))
245 Nothing -> P.TypeRef tn' Nothing
231 Nothing -> P.TypeRef tn' Nothing
@@ -251,10 +237,10 @@ addExplicitImport' decl moduleName imports =
251
237
252updateAtFirstOrPrepend :: (a -> Bool) -> (a -> a) -> a -> [a] -> [a]
238updateAtFirstOrPrepend :: (a -> Bool) -> (a -> a) -> a -> [a] -> [a]
253updateAtFirstOrPrepend p t d l =
239updateAtFirstOrPrepend p t d l =
254− case List.findIndex p l of
240+ case findIndex p l of
255 Nothing -> d : l
241 Nothing -> d : l
256 Just ix ->
242 Just ix ->
257− let (x, a : y) = List.splitAt ix l
243+ let (x, a : y) = splitAt ix l
258 in x ++ [t a] ++ y
244 in x ++ [t a] ++ y
259
245
260-- | Looks up the given identifier in the currently loaded modules.
246-- | Looks up the given identifier in the currently loaded modules.
@@ -265,30 +251,30 @@ updateAtFirstOrPrepend p t d l =
265--
251--
266-- * If more than one possible imports are found, reports the possibilities as a
252-- * If more than one possible imports are found, reports the possibilities as a
267-- list of completions.
253-- list of completions.
268−addImportForIdentifier :: (PscIde m, MonadError PscIdeError m, MonadLogger m)
254+addImportForIdentifier :: (Ide m, MonadError PscIdeError m)
269 => FilePath -- ^ The Sourcefile to read from
255 => FilePath -- ^ The Sourcefile to read from
270 -> Text -- ^ The identifier to import
256 -> Text -- ^ The identifier to import
271 -> [Filter] -- ^ Filters to apply before searching for
257 -> [Filter] -- ^ Filters to apply before searching for
272 -- the identifier
258 -- the identifier
273− -> m (Either [Match] [Text])
259+ -> m (Either [Match IdeDeclaration] [Text])
274addImportForIdentifier fp ident filters = do
260addImportForIdentifier fp ident filters = do
275− modules <- getAllModulesWithReexports
261+ modules <- getAllModules Nothing
276− case getExactMatches ident filters modules of
262+ case map (fmap discardAnn) (getExactMatches ident filters modules) of
277 [] ->
263 [] ->
278 throwError (NotFound "Couldn't find the given identifier. \
264 throwError (NotFound "Couldn't find the given identifier. \
279 \Have you loaded the corresponding module?")
265 \Have you loaded the corresponding module?")
280
266
281 -- Only one match was found for the given identifier, so we can insert it
267 -- Only one match was found for the given identifier, so we can insert it
282 -- right away
268 -- right away
283− [Match m decl] ->
269+ [Match (m, decl)] ->
284− Right <$> addExplicitImport fp decl (P.moduleNameFromString (T.unpack m))
270+ Right <$> addExplicitImport fp decl m
285
271
286 -- This case comes up for newtypes and dataconstructors. Because values and
272 -- This case comes up for newtypes and dataconstructors. Because values and
287 -- types don't share a namespace we can get multiple matches from the same
273 -- types don't share a namespace we can get multiple matches from the same
288 -- module. This also happens for parameterized types, as these generate both
274 -- module. This also happens for parameterized types, as these generate both
289 -- a type aswell as a type synonym.
275 -- a type aswell as a type synonym.
290
276
291− ms@[Match m1 d1, Match m2 d2] ->
277+ ms@[Match (m1, d1), Match (m2, d2)] ->
292 if m1 /= m2
278 if m1 /= m2
293 -- If the modules don't line up we just ask the user to specify the
279 -- If the modules don't line up we just ask the user to specify the
294 -- module
280 -- module
@@ -298,7 +284,7 @@ addImportForIdentifier fp ident filters = do
298 -- dataconstructor as that will give us an unnecessary import warning at
284 -- dataconstructor as that will give us an unnecessary import warning at
299 -- worst
285 -- worst
300 Just decl ->
286 Just decl ->
301− Right <$> addExplicitImport fp decl (P.moduleNameFromString (T.unpack m1))
287+ Right <$> addExplicitImport fp decl m1
302 -- Here we need the user to specify whether he wanted a dataconstructor
288 -- Here we need the user to specify whether he wanted a dataconstructor
303 -- or a type
289 -- or a type
304 Nothing ->
290 Nothing ->
@@ -309,9 +295,9 @@ addImportForIdentifier fp ident filters = do
309 xs ->
295 xs ->
310 pure $ Left xs
296 pure $ Left xs
311 where
297 where
312− decideRedundantCase dtor@(DataConstructor _ t _) (TypeDeclaration t' _) =
298+ decideRedundantCase dtor@(IdeDataConstructor _ t _) (IdeType t' _) =
313 if t == t' then Just dtor else Nothing
299 if t == t' then Just dtor else Nothing
314− decideRedundantCase TypeDeclaration{} ts@TypeSynonymDeclaration{} =
300+ decideRedundantCase IdeType{} ts@IdeTypeSynonym{} =
315 Just ts
301 Just ts
316 decideRedundantCase _ _ = Nothing
302 decideRedundantCase _ _ = Nothing
317
303
@@ -323,7 +309,7 @@ prettyPrintImport' (Import mn idt qual) =
323 T.pack $ "import " ++ P.prettyPrintImport mn idt qual
309 T.pack $ "import " ++ P.prettyPrintImport mn idt qual
324
310
325prettyPrintImportSection :: [Import] -> [Text]
311prettyPrintImportSection :: [Import] -> [Text]
326−prettyPrintImportSection imports = map prettyPrintImport' (List.sort imports)
312+prettyPrintImportSection imports = map prettyPrintImport' (sort imports)
327
313
328-- | Writes a list of lines to @Just filepath@ and responds with a @TextResult@,
314-- | Writes a list of lines to @Just filepath@ and responds with a @TextResult@,
329-- or returns the lines as a @MultilineTextResult@ if @Nothing@ was given as the
315-- or returns the lines as a @MultilineTextResult@ if @Nothing@ was given as the
src/Language/PureScript/Ide/Matcher.hs+26−32
@@ -14,23 +14,18 @@
14
14
15{-# LANGUAGE GeneralizedNewtypeDeriving #-}
15{-# LANGUAGE GeneralizedNewtypeDeriving #-}
16{-# LANGUAGE OverloadedStrings #-}
16{-# LANGUAGE OverloadedStrings #-}
17+{-# LANGUAGE FlexibleInstances #-}
17
18
18module Language.PureScript.Ide.Matcher
19module Language.PureScript.Ide.Matcher
19 ( Matcher
20 ( Matcher
20− , flexMatcher
21 , runMatcher
21 , runMatcher
22+ -- for tests
23+ , flexMatcher
22 ) where
24 ) where
23
25
24−import Prelude ()
26+import Protolude
25−import Prelude.Compat
26
27
27−import Control.Monad
28import Data.Aeson
28import Data.Aeson
29−import Data.Function (on)
30−import Data.List (sortBy)
31−import Data.Maybe (mapMaybe)
32−import Data.Monoid
33−import Data.Text (Text)
34import qualified Data.Text as T
29import qualified Data.Text as T
35import qualified Data.Text.Encoding as TE
30import qualified Data.Text.Encoding as TE
36import Language.PureScript.Ide.Types
31import Language.PureScript.Ide.Types
@@ -39,23 +34,22 @@ import Text.EditDistance
39import Text.Regex.TDFA ((=~))
34import Text.Regex.TDFA ((=~))
40
35
41
36
42−type ScoredMatch = (Match, Double)
37+type ScoredMatch a = (Match a, Double)
43
38
44−newtype Matcher = Matcher (Endo [Match]) deriving(Monoid)
39+newtype Matcher a = Matcher (Endo [Match a]) deriving (Monoid)
45
40
46−instance FromJSON Matcher where
41+instance FromJSON (Matcher IdeDeclaration) where
47 parseJSON = withObject "matcher" $ \o -> do
42 parseJSON = withObject "matcher" $ \o -> do
48− (matcher :: Maybe String) <- o .:? "matcher"
43+ (matcher :: Maybe Text) <- o .:? "matcher"
49 case matcher of
44 case matcher of
50 Just "flex" -> do
45 Just "flex" -> do
51 params <- o .: "params"
46 params <- o .: "params"
52− search <- params .: "search"
47+ flexMatcher <$> params .: "search"
53− pure $ flexMatcher search
54 Just "distance" -> do
48 Just "distance" -> do
55 params <- o .: "params"
49 params <- o .: "params"
50+ distanceMatcher
56− search <- params .: "search"
51+ <$> params .: "search"
57− maxDist <- params .: "maximumDistance"
52+ <*> params .: "maximumDistance"
58− pure $ distanceMatcher search maxDist
59 Just _ -> mzero
53 Just _ -> mzero
60 Nothing -> return mempty
54 Nothing -> return mempty
61
55
@@ -66,37 +60,37 @@ instance FromJSON Matcher where
66-- Examples:
60-- Examples:
67-- flMa matches flexMatcher. Score: 14.28
61-- flMa matches flexMatcher. Score: 14.28
68-- sons matches sortCompletions. Score: 6.25
62-- sons matches sortCompletions. Score: 6.25
69−flexMatcher :: Text -> Matcher
63+flexMatcher :: Text -> Matcher IdeDeclaration
70flexMatcher p = mkMatcher (flexMatch p)
64flexMatcher p = mkMatcher (flexMatch p)
71
65
72−distanceMatcher :: Text -> Int -> Matcher
66+distanceMatcher :: Text -> Int -> Matcher IdeDeclaration
73distanceMatcher q maxDist = mkMatcher (distanceMatcher' q maxDist)
67distanceMatcher q maxDist = mkMatcher (distanceMatcher' q maxDist)
74
68
75−distanceMatcher' :: Text -> Int -> [Match] -> [ScoredMatch]
69+distanceMatcher' :: Text -> Int -> [Match IdeDeclaration] -> [ScoredMatch IdeDeclaration]
76distanceMatcher' q maxDist = mapMaybe go
70distanceMatcher' q maxDist = mapMaybe go
77 where
71 where
78 go m = let d = dist (T.unpack y)
72 go m = let d = dist (T.unpack y)
79− y = identifierFromMatch m
73+ y = identifierFromIdeDeclaration (unwrapMatch m)
80 in if d <= maxDist
74 in if d <= maxDist
81 then Just (m, 1 / fromIntegral d)
75 then Just (m, 1 / fromIntegral d)
82 else Nothing
76 else Nothing
83 dist = levenshteinDistance defaultEditCosts (T.unpack q)
77 dist = levenshteinDistance defaultEditCosts (T.unpack q)
84
78
85−mkMatcher :: ([Match] -> [ScoredMatch]) -> Matcher
79+mkMatcher :: ([Match a] -> [ScoredMatch a]) -> Matcher a
86mkMatcher matcher = Matcher . Endo $ fmap fst . sortCompletions . matcher
80mkMatcher matcher = Matcher . Endo $ fmap fst . sortCompletions . matcher
87
81
88−runMatcher :: Matcher -> [Match] -> [Match]
82+runMatcher :: Matcher a -> [Match a] -> [Match a]
89runMatcher (Matcher m)= appEndo m
83runMatcher (Matcher m)= appEndo m
90
84
91−sortCompletions :: [ScoredMatch] -> [ScoredMatch]
85+sortCompletions :: [ScoredMatch a] -> [ScoredMatch a]
92sortCompletions = sortBy (flip compare `on` snd)
86sortCompletions = sortBy (flip compare `on` snd)
93
87
94−flexMatch :: Text -> [Match] -> [ScoredMatch]
88+flexMatch :: Text -> [Match IdeDeclaration] -> [ScoredMatch IdeDeclaration]
95flexMatch = mapMaybe . flexRate
89flexMatch = mapMaybe . flexRate
96
90
97−flexRate :: Text -> Match -> Maybe ScoredMatch
91+flexRate :: Text -> Match IdeDeclaration -> Maybe (ScoredMatch IdeDeclaration)
98flexRate p c = do
92flexRate p c = do
99− score <- flexScore p (identifierFromMatch c)
93+ score <- flexScore p (identifierFromIdeDeclaration (unwrapMatch c))
100 return (c, score)
94 return (c, score)
101
95
102-- FlexMatching ala Sublime.
96-- FlexMatching ala Sublime.
@@ -105,11 +99,11 @@ flexRate p c = do
105-- By string =~ pattern we'll get the start of the match and the length of
99-- By string =~ pattern we'll get the start of the match and the length of
106-- the matchas a (start, length) tuple if there's a match.
100-- the matchas a (start, length) tuple if there's a match.
107-- If match fails then it would be (-1,0)
101-- If match fails then it would be (-1,0)
108−flexScore :: Text -> DeclIdent -> Maybe Double
102+flexScore :: Text -> Text -> Maybe Double
109flexScore pat str =
103flexScore pat str =
110 case T.uncons pat of
104 case T.uncons pat of
111 Nothing -> Nothing
105 Nothing -> Nothing
112− Just (first, p) ->
106+ Just (first', p) ->
113 case TE.encodeUtf8 str =~ TE.encodeUtf8 pat' :: (Int, Int) of
107 case TE.encodeUtf8 str =~ TE.encodeUtf8 pat' :: (Int, Int) of
114 (-1,0) -> Nothing
108 (-1,0) -> Nothing
115 (start,len) -> Just $ calcScore start (start + len)
109 (start,len) -> Just $ calcScore start (start + len)
@@ -120,11 +114,11 @@ flexScore pat str =
120 -- escape prepends a backslash to "regexy" characters to prevent the
114 -- escape prepends a backslash to "regexy" characters to prevent the
121 -- matcher from crashing when trying to build the regex
115 -- matcher from crashing when trying to build the regex
122 escape :: Char -> Text
116 escape :: Char -> Text
123− escape c = if c `elem` ("[\\^$.|?*+(){}" :: String)
117+ escape c = if c `elem` T.unpack "[\\^$.|?*+(){}"
124 then T.pack ['\\', c]
118 then T.pack ['\\', c]
125 else T.singleton c
119 else T.singleton c
126 -- This just interleaves the search pattern with .*
120 -- This just interleaves the search pattern with .*
127 -- abcd[*] -> a.*b.*c.*d.*[*]
121 -- abcd[*] -> a.*b.*c.*d.*[*]
128− pat' = escape first <> foldMap (<> ".*") escapedPattern
122+ pat' = escape first' <> foldMap (<> ".*") escapedPattern
129 calcScore start end =
123 calcScore start end =
130 100.0 / fromIntegral ((1 + start) * (end - start + 1))
124 100.0 / fromIntegral ((1 + start) * (end - start + 1))
src/Language/PureScript/Ide/Pursuit.hs+9−12
@@ -14,20 +14,17 @@
14
14
15{-# LANGUAGE OverloadedStrings #-}
15{-# LANGUAGE OverloadedStrings #-}
16
16
17−module Language.PureScript.Ide.Pursuit where
17+module Language.PureScript.Ide.Pursuit
18+ ( searchPursuitForDeclarations
19+ , findPackagesForModuleIdent
20+ ) where
18
21
19−import Prelude ()
22+import Protolude
20−import Prelude.Compat
21
23
22import qualified Control.Exception as E
24import qualified Control.Exception as E
23import Data.Aeson
25import Data.Aeson
24−import Data.ByteString (ByteString)
25import Data.ByteString.Lazy (fromStrict)
26import Data.ByteString.Lazy (fromStrict)
26−import Data.Foldable (toList)
27−import Data.Maybe (mapMaybe)
28−import Data.Monoid ((<>))
29import Data.String
27import Data.String
30−import Data.Text (Text)
31import qualified Data.Text as T
28import qualified Data.Text as T
32import Language.PureScript.Ide.Types
29import Language.PureScript.Ide.Types
33import Network.HTTP.Types.Header (hAccept)
30import Network.HTTP.Types.Header (hAccept)
@@ -41,12 +38,12 @@ queryPursuit q = do
41 let qClean = T.dropWhileEnd (== '.') q
38 let qClean = T.dropWhileEnd (== '.') q
42 req' <- parseUrl "http://pursuit.purescript.org/search"
39 req' <- parseUrl "http://pursuit.purescript.org/search"
43 let req = req'
40 let req = req'
44− { queryString=("q=" <> (fromString . T.unpack) qClean)
41+ { queryString= "q=" <> (fromString . T.unpack) qClean
45 , requestHeaders=[(hAccept, "application/json")]
42 , requestHeaders=[(hAccept, "application/json")]
46 }
43 }
47 m <- newManager tlsManagerSettings
44 m <- newManager tlsManagerSettings
48 withHTTP req m $ \resp ->
45 withHTTP req m $ \resp ->
49− P.fold (<>) "" id $ responseBody resp
46+ P.fold (<>) "" identity (responseBody resp)
50
47
51
48
52handler :: HttpException -> IO [a]
49handler :: HttpException -> IO [a]
@@ -59,7 +56,7 @@ searchPursuitForDeclarations query =
59 let results' = decode (fromStrict r) :: Maybe Array
56 let results' = decode (fromStrict r) :: Maybe Array
60 case results' of
57 case results' of
61 Nothing -> pure []
58 Nothing -> pure []
62− Just results -> pure (mapMaybe isDeclarationResponse (map fromJSON (toList results)))) `E.catch`
59+ Just results -> pure (mapMaybe (isDeclarationResponse . fromJSON) (toList results))) `E.catch`
63 handler
60 handler
64 where
61 where
65 isDeclarationResponse (Success a@DeclarationResponse{}) = Just a
62 isDeclarationResponse (Success a@DeclarationResponse{}) = Just a
@@ -71,7 +68,7 @@ findPackagesForModuleIdent query =
71 let results' = decode (fromStrict r) :: Maybe Array
68 let results' = decode (fromStrict r) :: Maybe Array
72 case results' of
69 case results' of
73 Nothing -> pure []
70 Nothing -> pure []
74− Just results -> pure (mapMaybe isModuleResponse (map fromJSON (toList results)))) `E.catch`
71+ Just results -> pure (mapMaybe (isModuleResponse . fromJSON) (toList results))) `E.catch`
75 handler
72 handler
76 where
73 where
77 isModuleResponse (Success a@ModuleResponse{}) = Just a
74 isModuleResponse (Success a@ModuleResponse{}) = Just a
src/Language/PureScript/Ide/Rebuild.hs+16−18
@@ -8,14 +8,12 @@ module Language.PureScript.Ide.Rebuild
8 ( rebuildFile
8 ( rebuildFile
9 ) where
9 ) where
10
10
11−import Control.Monad.Error.Class
11+import Protolude
12−import Control.Monad.IO.Class
12+
13import "monad-logger" Control.Monad.Logger
13import "monad-logger" Control.Monad.Logger
14−import Control.Monad.Reader
14+import qualified Data.List as List
15−import Control.Monad.Trans.Except
16import qualified Data.Map.Lazy as M
15import qualified Data.Map.Lazy as M
17−import Data.Maybe (fromJust, mapMaybe)
16+import Data.Maybe (fromJust)
18−import Data.Monoid ((<>))
19import qualified Data.Set as S
17import qualified Data.Set as S
20import qualified Language.PureScript as P
18import qualified Language.PureScript as P
21import Language.PureScript.Errors.JSON
19import Language.PureScript.Errors.JSON
@@ -23,8 +21,8 @@ import Language.PureScript.Ide.Error
23import Language.PureScript.Ide.State
21import Language.PureScript.Ide.State
24import Language.PureScript.Ide.Types
22import Language.PureScript.Ide.Types
25import Language.PureScript.Ide.Util
23import Language.PureScript.Ide.Util
26−import Prelude.Compat
27import System.IO.UTF8 (readUTF8File)
24import System.IO.UTF8 (readUTF8File)
25+import System.FilePath
28
26
29-- | Given a filepath performs the following steps:
27-- | Given a filepath performs the following steps:
30--
28--
@@ -42,14 +40,14 @@ import System.IO.UTF8 (readUTF8File)
42-- warnings, and if rebuilding fails, returns a @RebuildError@ with the
40-- warnings, and if rebuilding fails, returns a @RebuildError@ with the
43-- generated errors.
41-- generated errors.
44rebuildFile
42rebuildFile
45− :: (PscIde m, MonadLogger m, MonadError PscIdeError m)
43+ :: (Ide m, MonadLogger m, MonadError PscIdeError m)
46 => FilePath
44 => FilePath
47 -> m Success
45 -> m Success
48rebuildFile path = do
46rebuildFile path = do
49
47
50 input <- liftIO (readUTF8File path)
48 input <- liftIO (readUTF8File path)
51
49
52− m <- case snd <$> P.parseModuleFromFile id (path, input) of
50+ m <- case snd <$> P.parseModuleFromFile identity (path, input) of
53 Left parseError -> throwError
51 Left parseError -> throwError
54 . RebuildError
52 . RebuildError
55 . toJSONErrors False P.Error
53 . toJSONErrors False P.Error
@@ -60,7 +58,7 @@ rebuildFile path = do
60 -- correctly to the 'Environment'.
58 -- correctly to the 'Environment'.
61 externs <- sortExterns m =<< getExternFiles
59 externs <- sortExterns m =<< getExternFiles
62
60
63− outputDirectory <- confOutputPath . envConfiguration <$> ask
61+ outputDirectory <- confOutputPath . ideConfiguration <$> ask
64
62
65 -- For rebuilding, we want to 'RebuildAlways', but for inferring foreign
63 -- For rebuilding, we want to 'RebuildAlways', but for inferring foreign
66 -- modules using their file paths, we need to specify the path in the 'Map'.
64 -- modules using their file paths, we need to specify the path in the 'Map'.
@@ -82,7 +80,7 @@ rebuildFile path = do
82-- | Rebuilds a module but opens up its export list first and stores the result
80-- | Rebuilds a module but opens up its export list first and stores the result
83-- inside the rebuild cache
81-- inside the rebuild cache
84rebuildModuleOpen
82rebuildModuleOpen
85− :: (PscIde m, MonadLogger m, MonadError PscIdeError m)
83+ :: (Ide m, MonadLogger m, MonadError PscIdeError m)
86 => MakeActionsEnv
84 => MakeActionsEnv
87 -> [P.ExternsFile]
85 -> [P.ExternsFile]
88 -> P.Module
86 -> P.Module
@@ -100,14 +98,14 @@ rebuildModuleOpen makeEnv externs m = do
100 Right result -> do
98 Right result -> do
101 $(logDebug)
99 $(logDebug)
102 ("Setting Rebuild cache: " <> runModuleNameT (P.efModuleName result))
100 ("Setting Rebuild cache: " <> runModuleNameT (P.efModuleName result))
103− setCachedRebuild result
101+ cacheRebuild result
104
102
105-- | Parameters we can access while building our @MakeActions@
103-- | Parameters we can access while building our @MakeActions@
106data MakeActionsEnv =
104data MakeActionsEnv =
107 MakeActionsEnv
105 MakeActionsEnv
108 { maeOutputDirectory :: FilePath
106 { maeOutputDirectory :: FilePath
109− , maeFilePathMap :: M.Map P.ModuleName (Either P.RebuildPolicy FilePath)
107+ , maeFilePathMap :: Map P.ModuleName (Either P.RebuildPolicy FilePath)
110− , maeForeignPathMap :: M.Map P.ModuleName FilePath
108+ , maeForeignPathMap :: Map P.ModuleName FilePath
111 , maePrefixComment :: Bool
109 , maePrefixComment :: Bool
112 }
110 }
113
111
@@ -135,9 +133,9 @@ shushCodegen ma MakeActionsEnv{..} =
135-- module. Throws an error if there is a cyclic dependency within the
133-- module. Throws an error if there is a cyclic dependency within the
136-- ExternsFiles
134-- ExternsFiles
137sortExterns
135sortExterns
138− :: (PscIde m, MonadError PscIdeError m)
136+ :: (Ide m, MonadError PscIdeError m)
139 => P.Module
137 => P.Module
140− -> M.Map P.ModuleName P.ExternsFile
138+ -> Map P.ModuleName P.ExternsFile
141 -> m [P.ExternsFile]
139 -> m [P.ExternsFile]
142sortExterns m ex = do
140sortExterns m ex = do
143 sorted' <- runExceptT
141 sorted' <- runExceptT
@@ -149,11 +147,11 @@ sortExterns m ex = do
149 case sorted' of
147 case sorted' of
150 Left _ -> throwError (GeneralError "There was a cycle in the dependencies")
148 Left _ -> throwError (GeneralError "There was a cycle in the dependencies")
151 Right (sorted, graph) -> do
149 Right (sorted, graph) -> do
152− let deps = fromJust (lookup (P.getModuleName m) graph)
150+ let deps = fromJust (List.lookup (P.getModuleName m) graph)
153 pure $ mapMaybe getExtern (deps `inOrderOf` map P.getModuleName sorted)
151 pure $ mapMaybe getExtern (deps `inOrderOf` map P.getModuleName sorted)
154 where
152 where
155 mkShallowModule P.ExternsFile{..} =
153 mkShallowModule P.ExternsFile{..} =
156− P.Module undefined [] efModuleName (map mkImport efImports) Nothing
154+ P.Module (P.internalModuleSourceSpan "<rebuild>") [] efModuleName (map mkImport efImports) Nothing
157 mkImport (P.ExternsImport mn it iq) =
155 mkImport (P.ExternsImport mn it iq) =
158 P.ImportDeclaration mn it iq
156 P.ImportDeclaration mn it iq
159 getExtern mn = M.lookup mn ex
157 getExtern mn = M.lookup mn ex
src/Language/PureScript/Ide/Reexports.hs+93−64
@@ -14,76 +14,105 @@
14-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
15
15
16{-# LANGUAGE OverloadedStrings #-}
16{-# LANGUAGE OverloadedStrings #-}
17+{-# LANGUAGE PackageImports #-}
18+{-# LANGUAGE TemplateHaskell #-}
19+{-# LANGUAGE RecordWildCards #-}
17
20
18−module Language.PureScript.Ide.Reexports where
21+module Language.PureScript.Ide.Reexports
22+ ( resolveReexports
23+ , prettyPrintReexportResult
24+ , reexportHasFailures
25+ , ReexportResult(..)
26+ ) where
19
27
28+import Protolude
20
29
21−import Prelude ()
22−import Prelude.Compat
23−
24−import Data.List (union)
25−import Data.Map (Map)
26import qualified Data.Map as Map
30import qualified Data.Map as Map
27−import Data.Maybe
28import Language.PureScript.Ide.Types
31import Language.PureScript.Ide.Types
29−
32+import Language.PureScript.Ide.Util
30−getReexports :: Module -> [ExternDecl]
33+import qualified Language.PureScript as P
31−getReexports (mn, decls)= concatMap getExport decls
34+
32− where getExport d
35+-- | Contains the module with resolved reexports, and eventual failures
33− | (Export mn') <- d
36+data ReexportResult a
34− , mn /= mn' = replaceExportWithAliases decls mn'
37+ = ReexportResult
35− | otherwise = []
38+ { reResolved :: a
36−
39+ , reFailed :: [(P.ModuleName, P.DeclarationRef)]
37−dependencyToExport :: ExternDecl -> ExternDecl
40+ } deriving (Show, Eq, Functor)
38−dependencyToExport (Dependency m _ _) = Export m
41+
39−dependencyToExport decl = decl
42+-- | Uses the passed formatter to format the resolved module, and adds eventual
40−
43+-- failures
41−replaceExportWithAliases :: [ExternDecl] -> ModuleIdent -> [ExternDecl]
44+prettyPrintReexportResult
42−replaceExportWithAliases decls ident =
45+ :: (a -> Text)
43− case filter isMatch decls of
46+ -- ^ Formatter for the resolved result
44− [] -> [Export ident]
47+ -> ReexportResult a
45− aliases -> map dependencyToExport aliases
48+ -- ^ The Result to be pretty printed
46− where isMatch d
49+ -> Text
47− | Dependency _ _ (Just alias) <- d
50+prettyPrintReexportResult f ReexportResult{..}
48− , alias == ident = True
51+ | null reFailed =
52+ "Successfully resolved reexports for " <> f reResolved
49− | otherwise = False
53+ | otherwise =
50−
54+ "Failed to resolve reexports for "
51−replaceReexport :: ExternDecl -> Module -> Module -> Module
55+ <> f reResolved
52−replaceReexport e@(Export _) (m, decls) (_, newDecls) =
56+ <> foldMap (\(mn, ref) -> runModuleNameT mn <> show ref) reFailed
53− (m, filter (/= e) decls `union` newDecls)
57+
54−replaceReexport _ _ _ = error "Should only get Exports here."
58+-- | Whether any Refs couldn't be resolved
55−
59+reexportHasFailures :: ReexportResult a -> Bool
56−emptyModule :: Module
60+reexportHasFailures = not . null . reFailed
57−emptyModule = ("Empty", [])
61+
58−
62+-- | Resolves Reexports for a given Module, by looking up the reexported values
59−isExport :: ExternDecl -> Bool
63+-- from the passed in Map
60−isExport (Export _) = True
64+resolveReexports
61−isExport _ = False
65+ :: Map P.ModuleName [IdeDeclarationAnn]
62−
66+ -- ^ Modules to search for the reexported declarations
63−removeExportDecls :: Module -> Module
67+ -> (Module, [(P.ModuleName, P.DeclarationRef)])
64−removeExportDecls = fmap (filter (not . isExport))
68+ -- ^ The module to resolve reexports for, aswell as the references to resolve
65−
69+ -> ReexportResult Module
66−replaceReexports :: Module -> Map ModuleIdent [ExternDecl] -> Module
70+resolveReexports modules ((moduleName, decls), refs) =
67−replaceReexports m db = result
71+ ReexportResult (moduleName, decls <> concat resolvedRefs) failedRefs
68 where
72 where
69− reexports = getReexports m
73+ (failedRefs, resolvedRefs) = partitionEithers (resolveRef' <$> refs)
70− result = foldl go (removeExportDecls m) reexports
74+ resolveRef' x@(mn, r) = case Map.lookup mn modules of
75+ Nothing -> Left x
76+ Just decls' -> first (mn,) (resolveRef decls' r)
77+
78+resolveRef
79+ :: [IdeDeclarationAnn]
80+ -> P.DeclarationRef
81+ -> Either P.DeclarationRef [IdeDeclarationAnn]
82+resolveRef decls ref = case ref of
83+ P.TypeRef tn mdtors ->
84+ case findRef (\case IdeType name _ -> name == tn; _ -> False) of
85+ Nothing -> Left ref
86+ Just d -> Right $ d : case mdtors of
87+ Nothing ->
88+ -- If the dataconstructor field inside the TypeRef is Nothing, that
89+ -- means that all data constructors are exported, so we need to look
90+ -- those up ourselfes
91+ findDtors tn
92+ Just dtors -> mapMaybe lookupDtor dtors
93+ P.ValueRef i ->
94+ findWrapped (\case IdeValue i' _ -> i' == i; _ -> False)
95+ P.TypeOpRef name ->
96+ findWrapped (\case IdeTypeOperator n _ _ _ -> n == name; _ -> False)
97+ P.ValueOpRef name ->
98+ findWrapped (\case IdeValueOperator n _ _ _ -> n == name; _ -> False)
99+ P.TypeClassRef name ->
100+ findWrapped (\case IdeTypeClass n -> n == name; _ -> False)
101+ _ ->
102+ Left ref
103+ where
104+ findWrapped = wrapSingle . findRef
105+ wrapSingle = maybe (Left ref) (Right . pure)
106+ findRef f = find (f . discardAnn) decls
71
107
72− go :: Module -> ExternDecl -> Module
108+ lookupDtor name =
73− go m' re@(Export name) = replaceReexport re m' (getModule name)
109+ findRef (\case IdeDataConstructor name' _ _ -> name == name'
74− go _ _ = error "partiality! woohoo"
110+ _ -> False)
75
111
76− getModule :: ModuleIdent -> Module
112+ findDtors tn = filter (f . discardAnn) decls
77− getModule name = clean res
78 where
113 where
79− res = fromMaybe emptyModule $ (name , ) <$> Map.lookup name db
114+ f :: IdeDeclaration -> Bool
80− -- we have to do this because keeping self exports in will result in
115+ f decl
81− -- infinite loops
116+ | (IdeDataConstructor _ tn' _) <- decl
82− clean (mn, decls) = (mn,) (filter (/= Export mn) decls)
117+ , tn == tn' = True
83−
118+ | otherwise = False
84−resolveReexports :: Map ModuleIdent [ExternDecl] -> Module -> Module
85−resolveReexports modules m =
86− let replaced = replaceReexports m modules
87− in if null (getReexports replaced)
88− then replaced
89− else resolveReexports modules replaced
src/Language/PureScript/Ide/SourceFile.hs+73−88
@@ -14,107 +14,92 @@
14
14
15{-# LANGUAGE OverloadedStrings #-}
15{-# LANGUAGE OverloadedStrings #-}
16
16
17−module Language.PureScript.Ide.SourceFile where
17+module Language.PureScript.Ide.SourceFile
18+ ( parseModule
19+ , getImportsForFile
20+ , extractSpans
21+ ) where
18
22
19−import Prelude
23+import Protolude
20
24
21−import Control.Monad.Error.Class
22−import Control.Monad.IO.Class
23−import Control.Monad.Trans.Except
24−import Data.Maybe (mapMaybe)
25−import Data.Monoid
26−import qualified Data.Text as T
27−import qualified Language.PureScript.AST.Declarations as D
25+import qualified Language.PureScript as P
28−import qualified Language.PureScript.AST.SourcePos as SP
29import Language.PureScript.Ide.Error
26import Language.PureScript.Ide.Error
30−import Language.PureScript.Ide.Externs (unwrapPositioned,
27+import Language.PureScript.Ide.Util
31− unwrapPositionedRef)
32import Language.PureScript.Ide.Types
28import Language.PureScript.Ide.Types
33−import qualified Language.PureScript.Names as N
29+import System.FilePath
34−import qualified Language.PureScript.Parser as P
35−import System.Directory
36import System.IO.UTF8 (readUTF8File)
30import System.IO.UTF8 (readUTF8File)
37
31
38−parseModuleFromFile :: (MonadIO m, MonadError PscIdeError m) =>
32+parseModule
39− FilePath -> m D.Module
33+ :: (MonadIO m)
40−parseModuleFromFile fp = do
34+ => FilePath
41− exists <- liftIO (doesFileExist fp)
35+ -> m (Either FilePath (FilePath, P.Module) )
42− if exists
36+parseModule path = do
43− then do
44− content <- liftIO (readUTF8File fp)
37+ contents <- liftIO (readUTF8File path)
45− let m = do tokens <- P.lex fp content
38+ case P.parseModuleFromFile identity (path, contents) of
46− P.runTokenParser "" P.parseModule tokens
39+ Left _ -> pure (Left path)
47− either (throwError . (`ParseError` "File could not be parsed.")) pure m
40+ Right m -> pure (Right m)
48− else throwError (NotFound "File does not exist.")
49
41
50−-- data Module = Module SourceSpan [Comment] ModuleName [Declaration] (Maybe [DeclarationRef])
42+getImports :: P.Module -> [(P.ModuleName, P.ImportDeclarationType, Maybe P.ModuleName)]
51−
52−getDeclarations :: D.Module -> [D.Declaration]
53−getDeclarations (D.Module _ _ _ declarations _) = declarations
54−
55−getImports :: D.Module -> [D.Declaration]
56−getImports (D.Module _ _ _ declarations _) =
43+getImports (P.Module _ _ _ declarations _) =
57 mapMaybe isImport declarations
44 mapMaybe isImport declarations
58 where
45 where
59− isImport (D.PositionedDeclaration _ _ (i@D.ImportDeclaration{})) = Just i
46+ isImport (P.PositionedDeclaration _ _ (P.ImportDeclaration a b c)) = Just (a, b, c)
60 isImport _ = Nothing
47 isImport _ = Nothing
61
48
62getImportsForFile :: (MonadIO m, MonadError PscIdeError m) =>
49getImportsForFile :: (MonadIO m, MonadError PscIdeError m) =>
63 FilePath -> m [ModuleImport]
50 FilePath -> m [ModuleImport]
64getImportsForFile fp = do
51getImportsForFile fp = do
65− module' <- parseModuleFromFile fp
52+ moduleE <- parseModule fp
66− let imports = getImports module'
53+ case moduleE of
54+ Left _ -> throwError (GeneralError "Failed to parse sourcefile.")
55+ Right (_, module') ->
67− pure (mkModuleImport . unwrapPositionedImport <$> imports)
56+ pure (mkModuleImport . unwrapPositionedImport <$> getImports module')
68− where
57+ where
69− mkModuleImport (D.ImportDeclaration mn importType' qualifier) =
58+ mkModuleImport (mn, importType', qualifier) =
70− ModuleImport
59+ ModuleImport
71− (T.pack (N.runModuleName mn))
60+ (runModuleNameT mn)
72− importType'
61+ importType'
73− (T.pack . N.runModuleName <$> qualifier)
62+ (runModuleNameT <$> qualifier)
74− mkModuleImport _ = error "Shouldn't have gotten anything but Imports here"
75− unwrapPositionedImport (D.ImportDeclaration mn importType' qualifier) =
63+ unwrapPositionedImport (mn, it, q) = (mn, unwrapImportType it, q)
76− D.ImportDeclaration mn (unwrapImportType importType') qualifier
77− unwrapPositionedImport x = x
78− unwrapImportType (D.Explicit decls) = D.Explicit (map unwrapPositionedRef decls)
64+ unwrapImportType (P.Explicit decls) = P.Explicit (map unwrapPositionedRef decls)
79− unwrapImportType (D.Hiding decls) = D.Hiding (map unwrapPositionedRef decls)
65+ unwrapImportType (P.Hiding decls) = P.Hiding (map unwrapPositionedRef decls)
80− unwrapImportType D.Implicit = D.Implicit
66+ unwrapImportType P.Implicit = P.Implicit
81−
82−getPositionedImports :: D.Module -> [D.Declaration]
83−getPositionedImports (D.Module _ _ _ declarations _) =
84− mapMaybe isImport declarations
85− where
86− isImport i@(D.PositionedDeclaration _ _ D.ImportDeclaration{}) = Just i
87− isImport _ = Nothing
88
67
89−getDeclPosition :: D.Module -> String -> Maybe SP.SourceSpan
68+-- | Given a surrounding Sourcespan and a Declaration from the PS AST, extracts
90−getDeclPosition m ident = getFirst (foldMap (match ident) decls)
69+-- definition sites inside that Declaration.
70+extractSpans
71+ :: P.SourceSpan
72+ -- ^ The surrounding span
73+ -> P.Declaration
74+ -- ^ The declaration to extract spans from
75+ -> [(Either Text Text, P.SourceSpan)]
76+ -- ^ A @Right@ corresponds to a type level declaration, and a @Left@ to a
77+ -- value level one
78+extractSpans ss d = case d of
79+ P.PositionedDeclaration ss' _ d' ->
80+ extractSpans ss' d'
81+ P.ValueDeclaration i _ _ _ ->
82+ [(Left (runIdentT i), ss)]
83+ P.TypeSynonymDeclaration name _ _ ->
84+ [(Right (runProperNameT name), ss)]
85+ P.TypeClassDeclaration name _ _ members ->
86+ (Right (runProperNameT name), ss) : concatMap (extractSpans' ss) members
87+ P.DataDeclaration _ name _ ctors ->
88+ (Right (runProperNameT name), ss)
89+ : map (\(cname, _) -> (Left (runProperNameT cname), ss)) ctors
90+ P.ExternDeclaration ident _ ->
91+ [(Left (runIdentT ident), ss)]
92+ P.ExternDataDeclaration name _ ->
93+ [(Right (runProperNameT name), ss)]
94+ _ -> []
91 where
95 where
92− decls = getDeclarations m
96+ -- We need this special case to be able to also get the position info for
97+ -- typeclass member functions. Typedeclaratations would clash with value
98+ -- declarations for non-typeclass members, which is why we can't handle them
99+ -- in extractSpans.
100+ extractSpans' ssP dP = case dP of
93− match q (D.PositionedDeclaration ss _ decl) = First (if go q decl
101+ P.PositionedDeclaration ssP' _ dP' ->
94− then Just ss
102+ extractSpans' ssP' dP'
95− else Nothing)
96− match _ _ = First Nothing
97−
98− go q (D.DataDeclaration _ name _ constructors) =
99− properEqual name q || any (\(x,_) -> properEqual x q) constructors
100− go q (D.DataBindingGroupDeclaration decls') = any (go q) decls'
101− go q (D.TypeSynonymDeclaration name _ _) = properEqual name q
102− go q (D.TypeDeclaration ident' _) = identEqual ident' q
103+ P.TypeDeclaration ident _ ->
103− go q (D.ValueDeclaration ident' _ _ _) = identEqual ident' q
104+ [(Left (runIdentT ident), ssP)]
104− go q (D.ExternDeclaration ident' _) = identEqual ident' q
105+ _ -> []
105− go q (D.ExternDataDeclaration name _) = properEqual name q
106− go q (D.TypeClassDeclaration name _ _ members) =
107− properEqual name q || any (go q . unwrapPositioned) members
108− go q (D.TypeInstanceDeclaration ident' _ _ _ _) =
109− identEqual ident' q
110− go _ _ = False
111−
112− properEqual x q = N.runProperName x == q
113− identEqual x q = N.runIdent x == q
114−
115−goToDefinition :: String -> FilePath -> IO (Maybe SP.SourceSpan)
116−goToDefinition q fp = do
117− m <- runExceptT (parseModuleFromFile fp)
118− case m of
119− Right module' -> pure (getDeclPosition module' q)
120− Left _ -> pure Nothing
src/Language/PureScript/Ide/State.hs+168−97
@@ -17,127 +17,198 @@
17{-# LANGUAGE TemplateHaskell #-}
17{-# LANGUAGE TemplateHaskell #-}
18
18
19module Language.PureScript.Ide.State
19module Language.PureScript.Ide.State
20− ( getPscIdeState
20+ ( getLoadedModulenames
21 , getExternFiles
21 , getExternFiles
22− , getModule
22+ , resetIdeState
23− , getModuleWithReexports
23+ , cacheRebuild
24− , getAllModulesWithReexports
24+ , insertExterns
25− , getAllModulesWithReexportsAndCache
26 , insertModule
25 , insertModule
27− , insertModuleSTM
26+ , insertExternsSTM
28− , getCachedRebuild
27+ , getAllModules
29− , resetPscIdeState
28+ , populateStage2
30− , setCachedRebuild
29+ , populateStage3
30+ , populateStage3STM
31 ) where
31 ) where
32
32
33−import Prelude ()
33+import Protolude
34−import Prelude.Compat
34+import qualified Prelude
35
35
36import Control.Concurrent.STM
36import Control.Concurrent.STM
37−import Control.Monad.IO.Class
38import "monad-logger" Control.Monad.Logger
37import "monad-logger" Control.Monad.Logger
39−import Control.Monad.Reader.Class
40import qualified Data.Map.Lazy as M
38import qualified Data.Map.Lazy as M
41−import Data.Maybe (mapMaybe)
42−import Data.Monoid
43import Language.PureScript.Externs
39import Language.PureScript.Externs
44import Language.PureScript.Ide.Externs
40import Language.PureScript.Ide.Externs
45import Language.PureScript.Ide.Reexports
41import Language.PureScript.Ide.Reexports
42+import Language.PureScript.Ide.SourceFile
46import Language.PureScript.Ide.Types
43import Language.PureScript.Ide.Types
47import Language.PureScript.Ide.Util
44import Language.PureScript.Ide.Util
48import qualified Language.PureScript as P
45import qualified Language.PureScript as P
46+import System.Clock
47+import System.FilePath
49
48
50−-- | Resets the PscIdeState to emptyPscIdeState
49+-- | Resets all State inside psc-ide
51−resetPscIdeState :: PscIde m => m ()
50+resetIdeState :: Ide m => m ()
52−resetPscIdeState = do
51+resetIdeState = do
53− stateVar <- envStateVar <$> ask
52+ ideVar <- ideStateVar <$> ask
54− liftIO $ atomically (writeTVar stateVar emptyPscIdeState)
53+ liftIO . atomically $ do
54+ writeTVar ideVar emptyIdeState
55+ setStage3STM ideVar emptyStage3
55
56
56−-- | Gets the entire PscIdeState
57+-- | Gets the loaded Modulenames
57−getPscIdeState :: PscIde m => m PscIdeState
58+getLoadedModulenames :: Ide m => m [P.ModuleName]
58−getPscIdeState = do
59+getLoadedModulenames = M.keys <$> getExternFiles
59− stateVar <- envStateVar <$> ask
60− liftIO (readTVarIO stateVar)
61
60
62-- | Gets all loaded ExternFiles
61-- | Gets all loaded ExternFiles
63−getExternFiles :: (PscIde m) => m (M.Map P.ModuleName ExternsFile)
62+getExternFiles :: Ide m => m (M.Map P.ModuleName ExternsFile)
64−getExternFiles = do
63+getExternFiles = s1Externs <$> getStage1
65− stateVar <- envStateVar <$> ask
66− liftIO (pscIdeStateExternsFiles <$> readTVarIO stateVar)
67
64
68−-- | Gets all loaded Modules and resolves Reexports
65+-- | Insert a Module into Stage1 of the State
69−getAllModulesWithReexports :: (PscIde m) => m [Module]
66+insertModule :: Ide m => (FilePath, P.Module) -> m ()
70−getAllModulesWithReexports = getAllModulesWithReexports' <$> getPscIdeState
67+insertModule module' = do
68+ stateVar <- ideStateVar <$> ask
69+ liftIO . atomically $ insertModuleSTM stateVar module'
71
70
72−-- | Pure version of @getAllModulesWithReexports@
71+-- | STM version of insertModule
73−getAllModulesWithReexports' :: PscIdeState -> [Module]
72+insertModuleSTM :: TVar IdeState -> (FilePath, P.Module) -> STM ()
74−getAllModulesWithReexports' state =
73+insertModuleSTM ref (fp, module') =
75− mapMaybe (getModuleWithReexports' state) (M.keys (pscIdeStateModules state))
74+ modifyTVar ref $ \x ->
75+ x { ideStage1 = (ideStage1 x) {
76+ s1Modules = M.insert
77+ (P.getModuleName module')
78+ (module', fp)
79+ (s1Modules (ideStage1 x))}}
80+
81+-- | Retrieves Stage1 from the State.
82+-- This includes loaded Externfiles
83+getStage1 :: Ide m => m Stage1
84+getStage1 = do
85+ st <- ideStateVar <$> ask
86+ fmap ideStage1 . liftIO . readTVarIO $ st
87+
88+-- | STM version of getStage1
89+getStage1STM :: TVar IdeState -> STM Stage1
90+getStage1STM ref = ideStage1 <$> readTVar ref
91+
92+-- | Retrieves Stage2 from the State.
93+getStage2 :: Ide m => m Stage2
94+getStage2 = do
95+ st <- ideStateVar <$> ask
96+ liftIO (atomically (getStage2STM st))
97+
98+getStage2STM :: TVar IdeState -> STM Stage2
99+getStage2STM ref = ideStage2 <$> readTVar ref
100+
101+-- | STM version of setStage2
102+setStage2STM :: TVar IdeState -> Stage2 -> STM ()
103+setStage2STM ref s2 = do
104+ modifyTVar ref $ \x ->
105+ x {ideStage2 = s2}
106+ pure ()
107+
108+-- | Retrieves Stage3 from the State.
109+-- This includes the denormalized Declarations and cached rebuilds
110+getStage3 :: Ide m => m Stage3
111+getStage3 = do
112+ st <- ideStateVar <$> ask
113+ fmap ideStage3 . liftIO . readTVarIO $ st
114+
115+-- | Sets Stage3 inside the compiler
116+setStage3STM :: TVar IdeState -> Stage3 -> STM ()
117+setStage3STM ref s3 = do
118+ modifyTVar ref $ \x ->
119+ x {ideStage3 = s3}
120+ pure ()
76
121
77-- | Checks if the given ModuleName matches the last rebuild cache and if it
122-- | Checks if the given ModuleName matches the last rebuild cache and if it
78−-- does, runs @getAllModulesWithReexports@ with the cached module replacing the
123+-- does returns all loaded definitions + the definitions inside the rebuild
79−-- loaded module
124+-- cache
80−getAllModulesWithReexportsAndCache
81− :: (PscIde m)
82− => Maybe P.ModuleName
125+getAllModules :: Ide m => Maybe P.ModuleName -> m [Module]
83− -> m [Module]
126+getAllModules mmoduleName = do
84−getAllModulesWithReexportsAndCache Nothing = getAllModulesWithReexports
127+ declarations <- s3Declarations <$> getStage3
85−getAllModulesWithReexportsAndCache (Just mn) = do
128+ rebuild <- cachedRebuild
86− state <- getPscIdeState
129+ case mmoduleName of
87− cachedRebuild <- getCachedRebuild
130+ Nothing -> pure (M.toList declarations)
88− case cachedRebuild of
131+ Just moduleName ->
89− Just (cachedIdent, ef) | cachedIdent == mn ->
132+ case rebuild of
90− pure (getAllModulesWithReexports' (insertModule' ef state))
133+ Just (cachedModulename, ef)
91− _ -> getAllModulesWithReexports
134+ | cachedModulename == moduleName -> do
92−
135+ (AstData asts) <- s2AstData <$> getStage2
93−-- | Looks up a single Module inside the loaded Modules
136+ let ast = fromMaybe M.empty (M.lookup moduleName asts)
94−getModule :: (PscIde m, MonadLogger m) => ModuleIdent -> m (Maybe Module)
137+ pure . M.toList $
95−getModule m = getModule' <$> getPscIdeState <*> pure m
138+ M.insert moduleName
96−
139+ (snd . annotateLocations ast . fst . convertExterns $ ef) declarations
97−-- | Pure version of @getModule@
140+ _ -> pure (M.toList declarations)
98−getModule' :: PscIdeState -> ModuleIdent -> Maybe Module
141+
99−getModule' ps mi = (mi,) <$> M.lookup mi (pscIdeStateModules ps)
100−
101−-- | Looks up a single Module and resolves its Reexports
102−getModuleWithReexports :: PscIde m => ModuleIdent -> m (Maybe Module)
103−getModuleWithReexports i = getModuleWithReexports' <$> getPscIdeState <*> pure i
104−
105−-- | Pure version of @getModuleWithReexports@
106−getModuleWithReexports' :: PscIdeState -> ModuleIdent -> Maybe Module
107−getModuleWithReexports' ps mi =
108− resolveReexports (pscIdeStateModules ps) <$> getModule' ps mi
109−
110−-- | Inserts an @ExternsFile@ into the PscIdeState. Also converts the
111−-- ExternsFile into psc-ide's internal Declaration format
142+-- | Adds an ExternsFile into psc-ide's State Stage1. This does not populate the
112−insertModule :: (PscIde m, MonadLogger m) =>
143+-- following Stages, which needs to be done after all the necessary Exterms have
144+-- been loaded.
113− ExternsFile -> m ()
145+insertExterns :: Ide m => ExternsFile -> m ()
114−insertModule externsFile = do
146+insertExterns ef = do
115− stateVar <- envStateVar <$> ask
147+ st <- ideStateVar <$> ask
116− let moduleName = efModuleName externsFile
148+ liftIO (atomically (insertExternsSTM st ef))
117− $(logDebug) $ "Inserting Module: " <> runModuleNameT moduleName
149+
118− liftIO . atomically $ insertModuleSTM stateVar externsFile
119−
120−-- | STM version of insertModule
150+-- | STM version of insertExterns
121−insertModuleSTM :: TVar PscIdeState -> ExternsFile -> STM ()
151+insertExternsSTM :: TVar IdeState -> ExternsFile -> STM ()
122−insertModuleSTM st ef = modifyTVar st (insertModule' ef)
152+insertExternsSTM ref ef =
123−
153+ modifyTVar ref $ \x ->
124−-- | Pure version of insertModule
154+ x { ideStage1 = (ideStage1 x) {
125−insertModule' :: ExternsFile -> PscIdeState -> PscIdeState
126−insertModule' ef state =
127− state
128− { pscIdeStateExternsFiles =
129− M.insert (efModuleName ef) ef (pscIdeStateExternsFiles state)
155+ s1Externs = M.insert (efModuleName ef) ef (s1Externs (ideStage1 x))}}
130− , pscIdeStateModules = let (mn, decls) = convertExterns ef
131− in M.insert mn decls (pscIdeStateModules state)
132− }
133
156
134-- | Sets rebuild cache to the given ExternsFile
157-- | Sets rebuild cache to the given ExternsFile
135−setCachedRebuild :: PscIde m => ExternsFile -> m ()
158+cacheRebuild :: Ide m => ExternsFile -> m ()
136−setCachedRebuild ef = do
159+cacheRebuild ef = do
137− st <- envStateVar <$> ask
160+ st <- ideStateVar <$> ask
138 liftIO . atomically . modifyTVar st $ \x ->
161 liftIO . atomically . modifyTVar st $ \x ->
162+ x { ideStage3 = (ideStage3 x) {
139− x { pscIdeStateCachedRebuild = Just (efModuleName ef, ef) }
163+ s3CachedRebuild = Just (efModuleName ef, ef)}}
140
164
141-- | Retrieves the rebuild cache
165-- | Retrieves the rebuild cache
142−getCachedRebuild :: PscIde m => m (Maybe (P.ModuleName, ExternsFile))
166+cachedRebuild :: Ide m => m (Maybe (P.ModuleName, ExternsFile))
143−getCachedRebuild = pscIdeStateCachedRebuild <$> getPscIdeState
167+cachedRebuild = s3CachedRebuild <$> getStage3
168+
169+-- | Extracts source spans from the parsed ASTs
170+populateStage2 :: (Ide m, MonadLogger m) => m ()
171+populateStage2 = do
172+ st <- ideStateVar <$> ask
173+ duration <- liftIO $ do
174+ start <- getTime Monotonic
175+ atomically (populateStage2STM st)
176+ end <- getTime Monotonic
177+ pure (Prelude.show (diffTimeSpec start end))
178+ $(logDebug) $ "Finished populating Stage2 in " <> toS duration
179+
180+-- | STM version of populateStage2
181+populateStage2STM :: TVar IdeState -> STM ()
182+populateStage2STM ref = do
183+ modules <- s1Modules <$> getStage1STM ref
184+ let spans = map (\((P.Module ss _ _ decls _), _) -> M.fromList (concatMap (extractSpans ss) decls)) modules
185+ setStage2STM ref (Stage2 (AstData spans))
186+
187+-- | Resolves reexports and populates Stage3 with data to be used in queries.
188+populateStage3 :: (Ide m, MonadLogger m) => m ()
189+populateStage3 = do
190+ st <- ideStateVar <$> ask
191+ (duration, results) <- liftIO $ do
192+ start <- getTime Monotonic
193+ results <- atomically (populateStage3STM st)
194+ end <- getTime Monotonic
195+ pure (Prelude.show (diffTimeSpec start end), results)
196+ traverse_
197+ (logWarnN . prettyPrintReexportResult (runModuleNameT . fst))
198+ (filter reexportHasFailures results)
199+ $(logDebug) $ "Finished populating Stage3 in " <> toS duration
200+
201+-- | STM version of populateStage3
202+populateStage3STM :: TVar IdeState -> STM [ReexportResult Module]
203+populateStage3STM ref = do
204+ externs <- s1Externs <$> getStage1STM ref
205+ (AstData asts) <- s2AstData <$> getStage2STM ref
206+ let modules = M.map convertExterns externs
207+ nModules :: Map P.ModuleName (Module, [(P.ModuleName, P.DeclarationRef)])
208+ nModules = M.mapWithKey
209+ (\moduleName (m, refs) ->
210+ (fromMaybe m $ annotateLocations <$> M.lookup moduleName asts <*> pure m, refs)) modules
211+ -- resolves reexports and discards load failures for now
212+ result = resolveReexports (M.map (snd . fst) nModules) <$> M.elems nModules
213+ setStage3STM ref (Stage3 (M.fromList (map reResolved result)) Nothing)
214+ pure result
src/Language/PureScript/Ide/Types.hs+99−75
@@ -12,101 +12,123 @@
12-- Type definitions for psc-ide
12-- Type definitions for psc-ide
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
14
14
15−{-# LANGUAGE OverloadedStrings #-}
15+{-# LANGUAGE OverloadedStrings #-}
16+{-# LANGUAGE DeriveFoldable #-}
16
17
17module Language.PureScript.Ide.Types where
18module Language.PureScript.Ide.Types where
18
19
19−import Prelude ()
20+import Protolude
20−import Prelude.Compat
21
21
22import Control.Concurrent.STM
22import Control.Concurrent.STM
23−import Control.Monad
24−import Control.Monad.Reader.Class
25−import Control.Monad.Trans
26import Data.Aeson
23import Data.Aeson
27import Data.Map.Lazy as M
24import Data.Map.Lazy as M
28−import Data.Maybe (maybeToList)
29−import Data.Text (Text (), pack, unpack)
30−import qualified Language.PureScript.AST.Declarations as D
31−import Language.PureScript.Externs
32import qualified Language.PureScript.Errors.JSON as P
25import qualified Language.PureScript.Errors.JSON as P
33−import qualified Language.PureScript.Names as N
34import qualified Language.PureScript as P
26import qualified Language.PureScript as P
35−
27+import Language.PureScript.Ide.Conversions
28+import System.FilePath
36−import Text.Parsec
29+import Text.Parsec as Parsec
37import Text.Parsec.Text
30import Text.Parsec.Text
38
31
39−type Ident = Text
40−type DeclIdent = Text
41type ModuleIdent = Text
32type ModuleIdent = Text
42
33
43−data ExternDecl
34+data IdeDeclaration
44− -- | A function/value declaration
45− = ValueDeclaration Ident P.Type
35+ = IdeValue P.Ident P.Type
46− | TypeDeclaration (P.ProperName 'P.TypeName) P.Kind
36+ | IdeType (P.ProperName 'P.TypeName) P.Kind
47− | TypeSynonymDeclaration (P.ProperName 'P.TypeName) P.Type
37+ | IdeTypeSynonym (P.ProperName 'P.TypeName) P.Type
48− -- | A Dependency onto another Module
49− | Dependency
50− ModuleIdent -- name of the dependency
51− [Text] -- explicit imports
52− (Maybe Text) -- An eventual qualifier
53− -- | A module declaration
54− | ModuleDecl
55− ModuleIdent -- The modules name
56− [DeclIdent] -- The exported identifiers
57− -- | A data/newtype declaration
58− | DataConstructor
59− DeclIdent -- The type name
60− (P.ProperName 'P.TypeName)
38+ | IdeDataConstructor (P.ProperName 'P.ConstructorName) (P.ProperName 'P.TypeName) P.Type
61− P.Type -- The "type"
62− -- | An exported module
63− | TypeClassDeclaration (P.ProperName 'P.ClassName)
39+ | IdeTypeClass (P.ProperName 'P.ClassName)
64− | ValueOperator (P.OpName 'P.ValueOpName) Ident P.Precedence P.Associativity
40+ | IdeValueOperator (P.OpName 'P.ValueOpName) Text P.Precedence P.Associativity
65− | TypeOperator (P.OpName 'P.TypeOpName) Ident P.Precedence P.Associativity
41+ | IdeTypeOperator (P.OpName 'P.TypeOpName) Text P.Precedence P.Associativity
66− | Export ModuleIdent -- The exported Modules name
42+ deriving (Show, Eq, Ord)
43+
44+data IdeDeclarationAnn = IdeDeclarationAnn Annotation IdeDeclaration
45+ deriving (Show, Eq, Ord)
46+
47+data Annotation
48+ = Annotation
49+ { annLocation :: Maybe P.SourceSpan
50+ , annExportedFrom :: Maybe P.ModuleName
67− deriving (Show,Eq,Ord)
51+ } deriving (Show, Eq, Ord)
68−
52+
69−type Module = (ModuleIdent, [ExternDecl])
53+emptyAnn :: Annotation
54+emptyAnn = Annotation Nothing Nothing
55+
56+type Module = (P.ModuleName, [IdeDeclarationAnn])
57+
58+newtype AstData a =
59+ AstData (Map P.ModuleName (Map (Either Text Text) a))
60+ deriving (Show, Eq, Ord, Functor, Foldable)
70
61
71data Configuration =
62data Configuration =
72 Configuration
63 Configuration
73 { confOutputPath :: FilePath
64 { confOutputPath :: FilePath
74 , confDebug :: Bool
65 , confDebug :: Bool
66+ , confGlobs :: [FilePath]
75 }
67 }
76
68
77−data PscIdeEnvironment =
69+data IdeEnvironment =
78− PscIdeEnvironment
70+ IdeEnvironment
79− { envStateVar :: TVar PscIdeState
71+ { ideStateVar :: TVar IdeState
80− , envConfiguration :: Configuration
72+ , ideConfiguration :: Configuration
81 }
73 }
82
74
83−type PscIde m = (MonadIO m, MonadReader PscIdeEnvironment m)
75+type Ide m = (MonadIO m, MonadReader IdeEnvironment m)
76+
77+data IdeState = IdeState
78+ { ideStage1 :: Stage1
79+ , ideStage2 :: Stage2
80+ , ideStage3 :: Stage3
81+ }
84
82
85−data PscIdeState =
83+emptyIdeState :: IdeState
86− PscIdeState
84+emptyIdeState = IdeState emptyStage1 emptyStage2 emptyStage3
87− { pscIdeStateModules :: M.Map Text [ExternDecl]
88− , pscIdeStateExternsFiles :: M.Map P.ModuleName ExternsFile
89− , pscIdeStateCachedRebuild :: Maybe (P.ModuleName, ExternsFile)
90− } deriving Show
91
85
92−emptyPscIdeState :: PscIdeState
86+emptyStage1 :: Stage1
93−emptyPscIdeState = PscIdeState M.empty M.empty Nothing
87+emptyStage1 = Stage1 M.empty M.empty
94
88
95−data Match = Match ModuleIdent ExternDecl
89+emptyStage2 :: Stage2
90+emptyStage2 = Stage2 (AstData M.empty)
91+
92+emptyStage3 :: Stage3
93+emptyStage3 = Stage3 M.empty Nothing
94+
95+data Stage1 = Stage1
96+ { s1Externs :: M.Map P.ModuleName P.ExternsFile
97+ , s1Modules :: M.Map P.ModuleName (P.Module, FilePath)
98+ }
99+
100+data Stage2 = Stage2
101+ { s2AstData :: AstData P.SourceSpan
102+ }
103+
104+data Stage3 = Stage3
105+ { s3Declarations :: M.Map P.ModuleName [IdeDeclarationAnn]
106+ , s3CachedRebuild :: Maybe (P.ModuleName, P.ExternsFile)
107+ }
108+
109+newtype Match a = Match (P.ModuleName, a)
96− deriving (Show, Eq)
110+ deriving (Show, Eq, Functor)
97
111
98newtype Completion =
112newtype Completion =
99− Completion (ModuleIdent, DeclIdent, Text)
113+ Completion (Text, Text, Text)
114+ deriving (Show,Eq)
115+
116+newtype Info =
117+ Info (Text, Text, Text, Maybe P.SourceSpan)
100 deriving (Show,Eq)
118 deriving (Show,Eq)
101
119
120+instance ToJSON Info where
121+ toJSON (Info (m, d, t, sourceSpan)) =
122+ object ["module" .= m, "identifier" .= d, "type" .= t, "definedAt" .= sourceSpan]
123+
102instance ToJSON Completion where
124instance ToJSON Completion where
103− toJSON (Completion (m,d,t)) =
125+ toJSON (Completion (m, d, t)) =
104 object ["module" .= m, "identifier" .= d, "type" .= t]
126 object ["module" .= m, "identifier" .= d, "type" .= t]
105
127
106data ModuleImport =
128data ModuleImport =
107 ModuleImport
129 ModuleImport
108 { importModuleName :: ModuleIdent
130 { importModuleName :: ModuleIdent
109− , importType :: D.ImportDeclarationType
131+ , importType :: P.ImportDeclarationType
110 , importQualifier :: Maybe Text
132 , importQualifier :: Maybe Text
111 } deriving(Show)
133 } deriving(Show)
112
134
@@ -116,29 +138,30 @@ instance Eq ModuleImport where
116 && importQualifier mi1 == importQualifier mi2
138 && importQualifier mi1 == importQualifier mi2
117
139
118instance ToJSON ModuleImport where
140instance ToJSON ModuleImport where
119− toJSON (ModuleImport mn D.Implicit qualifier) =
141+ toJSON (ModuleImport mn P.Implicit qualifier) =
120 object $ [ "module" .= mn
142 object $ [ "module" .= mn
121 , "importType" .= ("implicit" :: Text)
143 , "importType" .= ("implicit" :: Text)
122 ] ++ fmap (\x -> "qualifier" .= x) (maybeToList qualifier)
144 ] ++ fmap (\x -> "qualifier" .= x) (maybeToList qualifier)
123− toJSON (ModuleImport mn (D.Explicit refs) _) =
145+ toJSON (ModuleImport mn (P.Explicit refs) _) =
124 object [ "module" .= mn
146 object [ "module" .= mn
125 , "importType" .= ("explicit" :: Text)
147 , "importType" .= ("explicit" :: Text)
126 , "identifiers" .= (identifierFromDeclarationRef <$> refs)
148 , "identifiers" .= (identifierFromDeclarationRef <$> refs)
127 ]
149 ]
128− toJSON (ModuleImport mn (D.Hiding refs) _) =
150+ toJSON (ModuleImport mn (P.Hiding refs) _) =
129 object [ "module" .= mn
151 object [ "module" .= mn
130 , "importType" .= ("hiding" :: Text)
152 , "importType" .= ("hiding" :: Text)
131 , "identifiers" .= (identifierFromDeclarationRef <$> refs)
153 , "identifiers" .= (identifierFromDeclarationRef <$> refs)
132 ]
154 ]
133
155
134−identifierFromDeclarationRef :: D.DeclarationRef -> String
156+identifierFromDeclarationRef :: P.DeclarationRef -> Text
135−identifierFromDeclarationRef (D.TypeRef name _) = N.runProperName name
157+identifierFromDeclarationRef (P.TypeRef name _) = runProperNameT name
136−identifierFromDeclarationRef (D.ValueRef ident) = N.runIdent ident
158+identifierFromDeclarationRef (P.ValueRef ident) = runIdentT ident
137−identifierFromDeclarationRef (D.TypeClassRef name) = N.runProperName name
159+identifierFromDeclarationRef (P.TypeClassRef name) = runProperNameT name
138identifierFromDeclarationRef _ = ""
160identifierFromDeclarationRef _ = ""
139
161
140data Success =
162data Success =
141 CompletionResult [Completion]
163 CompletionResult [Completion]
164+ | InfoResult [Info]
142 | TextResult Text
165 | TextResult Text
143 | MultilineTextResult [Text]
166 | MultilineTextResult [Text]
144 | PursuitResult [PursuitResponse]
167 | PursuitResult [PursuitResponse]
@@ -153,6 +176,7 @@ encodeSuccess res =
153
176
154instance ToJSON Success where
177instance ToJSON Success where
155 toJSON (CompletionResult cs) = encodeSuccess cs
178 toJSON (CompletionResult cs) = encodeSuccess cs
179+ toJSON (InfoResult i) = encodeSuccess i
156 toJSON (TextResult t) = encodeSuccess t
180 toJSON (TextResult t) = encodeSuccess t
157 toJSON (MultilineTextResult ts) = encodeSuccess ts
181 toJSON (MultilineTextResult ts) = encodeSuccess ts
158 toJSON (PursuitResult resp) = encodeSuccess resp
182 toJSON (PursuitResult resp) = encodeSuccess resp
@@ -182,14 +206,14 @@ data PursuitResponse =
182 ModuleResponse ModuleIdent Text
206 ModuleResponse ModuleIdent Text
183 -- | A Pursuit Response for a declaration. Consist of the declarations type,
207 -- | A Pursuit Response for a declaration. Consist of the declarations type,
184 -- module, name and package
208 -- module, name and package
185− | DeclarationResponse Text ModuleIdent DeclIdent Text
209+ | DeclarationResponse Text ModuleIdent Text Text
186 deriving (Show,Eq)
210 deriving (Show,Eq)
187
211
188instance FromJSON PursuitResponse where
212instance FromJSON PursuitResponse where
189 parseJSON (Object o) = do
213 parseJSON (Object o) = do
190 package <- o .: "package"
214 package <- o .: "package"
191 info <- o .: "info"
215 info <- o .: "info"
192− (type' :: String) <- info .: "type"
216+ (type' :: Text) <- info .: "type"
193 case type' of
217 case type' of
194 "module" -> do
218 "module" -> do
195 name <- info .: "module"
219 name <- info .: "module"
@@ -204,26 +228,26 @@ instance FromJSON PursuitResponse where
204
228
205typeParse :: Text -> Either Text (Text, Text)
229typeParse :: Text -> Either Text (Text, Text)
206typeParse t = case parse parseType "" t of
230typeParse t = case parse parseType "" t of
207− Right (x,y) -> Right (pack x, pack y)
231+ Right (x,y) -> Right (x, y)
208− Left err -> Left (pack (show err))
232+ Left err -> Left (show err)
209 where
233 where
210− parseType :: Parser (String, String)
234+ parseType :: Parser (Text, Text)
211 parseType = do
235 parseType = do
212 name <- identifier
236 name <- identifier
213 _ <- string "::"
237 _ <- string "::"
214 spaces
238 spaces
215 type' <- many1 anyChar
239 type' <- many1 anyChar
216− pure (unpack name, type')
240+ pure (name, toS type')
217
241
218 identifier :: Parser Text
242 identifier :: Parser Text
219 identifier = do
243 identifier = do
220 spaces
244 spaces
221 ident <-
245 ident <-
222 -- necessary for being able to parse the following ((++), concat)
246 -- necessary for being able to parse the following ((++), concat)
223− between (char '(') (char ')') (many1 (noneOf ", )")) <|>
247+ between (char '(') (char ')') (many1 (noneOf ", )")) Parsec.<|>
224 many1 (noneOf ", )")
248 many1 (noneOf ", )")
225 spaces
249 spaces
226− pure (pack ident)
250+ pure (toS ident)
227
251
228instance ToJSON PursuitResponse where
252instance ToJSON PursuitResponse where
229 toJSON (ModuleResponse name package) =
253 toJSON (ModuleResponse name package) =
src/Language/PureScript/Ide/Util.hs+58−46
@@ -9,75 +9,87 @@
9-- Stability : experimental
9-- Stability : experimental
10--
10--
11-- |
11-- |
12−-- Generally useful functions and conversions
12+-- Generally useful functions
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
14
14
15{-# LANGUAGE OverloadedStrings #-}
15{-# LANGUAGE OverloadedStrings #-}
16
16
17−module Language.PureScript.Ide.Util where
17+module Language.PureScript.Ide.Util
18+ ( identifierFromIdeDeclaration
19+ , unwrapMatch
20+ , unwrapPositioned
21+ , unwrapPositionedRef
22+ , completionFromMatch
23+ , infoFromMatch
24+ , encodeT
25+ , decodeT
26+ , discardAnn
27+ , module Language.PureScript.Ide.Conversions
28+ ) where
18
29
19−import Prelude.Compat
30+import Protolude
20import Data.Aeson
31import Data.Aeson
21−import Data.Text (Text)
22import qualified Data.Text as T
32import qualified Data.Text as T
23−import Data.Text.Lazy (fromStrict, toStrict)
24import Data.Text.Lazy.Encoding (decodeUtf8, encodeUtf8)
33import Data.Text.Lazy.Encoding (decodeUtf8, encodeUtf8)
25import qualified Language.PureScript as P
34import qualified Language.PureScript as P
26import Language.PureScript.Ide.Types
35import Language.PureScript.Ide.Types
36+import Language.PureScript.Ide.Conversions
27
37
28−runProperNameT :: P.ProperName a -> Text
38+identifierFromIdeDeclaration :: IdeDeclaration -> Text
29−runProperNameT = T.pack . P.runProperName
39+identifierFromIdeDeclaration d = case d of
40+ IdeValue name _ -> runIdentT name
41+ IdeType name _ -> runProperNameT name
42+ IdeTypeSynonym name _ -> runProperNameT name
43+ IdeDataConstructor name _ _ -> runProperNameT name
44+ IdeTypeClass name -> runProperNameT name
45+ IdeValueOperator op _ _ _ -> runOpNameT op
46+ IdeTypeOperator op _ _ _ -> runOpNameT op
30
47
31−runIdentT :: P.Ident -> Text
48+discardAnn :: IdeDeclarationAnn -> IdeDeclaration
32−runIdentT = T.pack . P.runIdent
49+discardAnn (IdeDeclarationAnn _ d) = d
33
50
34−runOpNameT :: P.OpName a -> Text
51+unwrapMatch :: Match a -> a
35−runOpNameT = T.pack . P.runOpName
52+unwrapMatch (Match (_, ed)) = ed
36
53
37−runModuleNameT :: P.ModuleName -> Text
54+completionFromMatch :: Match IdeDeclaration -> Completion
38−runModuleNameT = T.pack . P.runModuleName
55+completionFromMatch = Completion . completionFromMatch'
39
56
40−prettyTypeT :: P.Type -> Text
57+completionFromMatch' :: Match IdeDeclaration -> (Text, Text, Text)
41−prettyTypeT = T.unwords . fmap T.strip . T.lines . T.pack . P.prettyPrintType
42−
43−identifierFromExternDecl :: ExternDecl -> Text
44−identifierFromExternDecl (ValueDeclaration name _) = name
45−identifierFromExternDecl (TypeDeclaration name _) = runProperNameT name
46−identifierFromExternDecl (TypeSynonymDeclaration name _) = runProperNameT name
47−identifierFromExternDecl (DataConstructor name _ _) = name
48−identifierFromExternDecl (TypeClassDeclaration name) = runProperNameT name
49−identifierFromExternDecl (ModuleDecl name _) = name
50−identifierFromExternDecl (ValueOperator op _ _ _) = runOpNameT op
51−identifierFromExternDecl (TypeOperator op _ _ _) = runOpNameT op
52−identifierFromExternDecl Dependency{} = "~Dependency~"
53−identifierFromExternDecl Export{} = "~Export~"
54−
55−identifierFromMatch :: Match -> Text
56−identifierFromMatch (Match _ ed) = identifierFromExternDecl ed
57−
58−completionFromMatch :: Match -> Maybe Completion
58+completionFromMatch' (Match (m', d)) = case d of
59−completionFromMatch (Match m d) = case d of
60− ValueDeclaration name type' -> Just $ Completion (m, name, prettyTypeT type')
59+ IdeValue name type' -> (m, runIdentT name, prettyTypeT type')
61− TypeDeclaration name kind -> Just $ Completion (m, runProperNameT name, T.pack $ P.prettyPrintKind kind)
60+ IdeType name kind -> (m, runProperNameT name, toS (P.prettyPrintKind kind))
62− TypeSynonymDeclaration name kind -> Just $ Completion (m, runProperNameT name, prettyTypeT kind)
61+ IdeTypeSynonym name kind -> (m, runProperNameT name, prettyTypeT kind)
63− DataConstructor name _ type' -> Just $ Completion (m, name, prettyTypeT type')
62+ IdeDataConstructor name _ type' -> (m, runProperNameT name, prettyTypeT type')
64− TypeClassDeclaration name -> Just $ Completion (m, runProperNameT name, "class")
63+ IdeTypeClass name -> (m, runProperNameT name, "class")
65− ModuleDecl name _ -> Just $ Completion ("module", name, "module")
64+ IdeValueOperator op ref precedence associativity ->
66− ValueOperator op ref precedence associativity -> Just $ Completion (m, runOpNameT op, showFixity precedence associativity ref op)
65+ (m, runOpNameT op, showFixity precedence associativity ref op)
66+ IdeTypeOperator op ref precedence associativity ->
67− TypeOperator op ref precedence associativity -> Just $ Completion (m, runOpNameT op, showFixity precedence associativity ref op)
67+ (m, runOpNameT op, showFixity precedence associativity ref op)
68− Dependency{} -> Nothing
69− Export{} -> Nothing
70 where
68 where
69+ m = runModuleNameT m'
71 showFixity p a r o =
70 showFixity p a r o =
72 let asso = case a of
71 let asso = case a of
73 P.Infix -> "infix"
72 P.Infix -> "infix"
74 P.Infixl -> "infixl"
73 P.Infixl -> "infixl"
75 P.Infixr -> "infixr"
74 P.Infixr -> "infixr"
76− in T.unwords [asso, T.pack (show p), r, "as", runOpNameT o]
75+ in T.unwords [asso, show p, r, "as", runOpNameT o]
77
76
77+infoFromMatch :: Match IdeDeclarationAnn -> Info
78+infoFromMatch (Match (m, (IdeDeclarationAnn ann d))) =
79+ Info (a, b, c, annLocation ann)
80+ where
81+ (a, b, c) = completionFromMatch' (Match (m, d))
78
82
79encodeT :: (ToJSON a) => a -> Text
83encodeT :: (ToJSON a) => a -> Text
80−encodeT = toStrict . decodeUtf8 . encode
84+encodeT = toS . decodeUtf8 . encode
81
85
82decodeT :: (FromJSON a) => Text -> Maybe a
86decodeT :: (FromJSON a) => Text -> Maybe a
83−decodeT = decode . encodeUtf8 . fromStrict
87+decodeT = decode . encodeUtf8 . toS
88+
89+unwrapPositioned :: P.Declaration -> P.Declaration
90+unwrapPositioned (P.PositionedDeclaration _ _ x) = x
91+unwrapPositioned x = x
92+
93+unwrapPositionedRef :: P.DeclarationRef -> P.DeclarationRef
94+unwrapPositionedRef (P.PositionedDeclarationRef _ _ x) = x
95+unwrapPositionedRef x = x
src/Language/PureScript/Ide/Watcher.hs+9−9
@@ -12,35 +12,35 @@
12-- File watcher for externs files
12-- File watcher for externs files
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
14
14
15−module Language.PureScript.Ide.Watcher where
15+module Language.PureScript.Ide.Watcher
16+ ( watcher
17+ ) where
18+
19+import Protolude
16
20
17−import Control.Concurrent (threadDelay)
18import Control.Concurrent.STM
21import Control.Concurrent.STM
19−import Control.Monad
20−import Control.Monad.Trans.Except
21import Language.PureScript.Ide.Externs
22import Language.PureScript.Ide.Externs
22import Language.PureScript.Ide.State
23import Language.PureScript.Ide.State
23import Language.PureScript.Ide.Types
24import Language.PureScript.Ide.Types
24−import Prelude
25import System.FilePath
25import System.FilePath
26import System.FSNotify
26import System.FSNotify
27
27
28-- | Reloads an ExternsFile from Disc. If the Event indicates the ExternsFile
28-- | Reloads an ExternsFile from Disc. If the Event indicates the ExternsFile
29-- was deleted we don't do anything.
29-- was deleted we don't do anything.
30−reloadFile :: TVar PscIdeState -> Event -> IO ()
30+reloadFile :: TVar IdeState -> Event -> IO ()
31reloadFile _ Removed{} = pure ()
31reloadFile _ Removed{} = pure ()
32−reloadFile stateVar ev = do
32+reloadFile ref ev = do
33 let fp = eventPath ev
33 let fp = eventPath ev
34 ef' <- runExceptT (readExternFile fp)
34 ef' <- runExceptT (readExternFile fp)
35 case ef' of
35 case ef' of
36 Left _ -> pure ()
36 Left _ -> pure ()
37 Right ef -> do
37 Right ef -> do
38− atomically (insertModuleSTM stateVar ef)
38+ void $ atomically (insertExternsSTM ref ef *> populateStage3STM ref)
39 putStrLn ("Reloaded File at: " ++ fp)
39 putStrLn ("Reloaded File at: " ++ fp)
40
40
41-- | Installs filewatchers for the given directory and reloads ExternsFiles when
41-- | Installs filewatchers for the given directory and reloads ExternsFiles when
42-- they change on disc
42-- they change on disc
43−watcher :: TVar PscIdeState -> FilePath -> IO ()
43+watcher :: TVar IdeState -> FilePath -> IO ()
44watcher stateVar fp =
44watcher stateVar fp =
45 withManagerConf (defaultConfig { confDebounce = NoDebounce }) $ \mgr -> do
45 withManagerConf (defaultConfig { confDebounce = NoDebounce }) $ \mgr -> do
46 _ <- watchTree mgr fp
46 _ <- watchTree mgr fp
src/Language/PureScript/Interactive.hs+47−41
@@ -1,8 +1,6 @@
1{-# LANGUAGE DoAndIfThenElse #-}
1{-# LANGUAGE DoAndIfThenElse #-}
2{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleContexts #-}
3−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE MultiParamTypeClasses #-}
3{-# LANGUAGE MultiParamTypeClasses #-}
5−{-# LANGUAGE RecordWildCards #-}
6{-# LANGUAGE TupleSections #-}
4{-# LANGUAGE TupleSections #-}
7{-# LANGUAGE DataKinds #-}
5{-# LANGUAGE DataKinds #-}
8
6
@@ -19,6 +17,7 @@ import Prelude ()
19import Prelude.Compat
17import Prelude.Compat
20
18
21import Data.List (intercalate, nub, sort, find, foldl')
19import Data.List (intercalate, nub, sort, find, foldl')
20+import Data.Maybe (mapMaybe)
22import qualified Data.Map as M
21import qualified Data.Map as M
23
22
24import Control.Monad.IO.Class (MonadIO, liftIO)
23import Control.Monad.IO.Class (MonadIO, liftIO)
@@ -39,12 +38,11 @@ import Language.PureScript.Interactive.Parser as Interactive
39import Language.PureScript.Interactive.Printer as Interactive
38import Language.PureScript.Interactive.Printer as Interactive
40import Language.PureScript.Interactive.Types as Interactive
39import Language.PureScript.Interactive.Types as Interactive
41
40
42−import System.Exit
41+import System.FilePath ((</>))
43−import System.Process (readProcessWithExitCode)
44
42
45-- | Pretty-print errors
43-- | Pretty-print errors
46printErrors :: MonadIO m => P.MultipleErrors -> m ()
44printErrors :: MonadIO m => P.MultipleErrors -> m ()
47−printErrors = liftIO . putStrLn . P.prettyPrintMultipleErrors False
45+printErrors = liftIO . putStrLn . P.prettyPrintMultipleErrors P.defaultPPEOptions
48
46
49-- | This is different than the runMake in 'Language.PureScript.Make' in that it specifies the
47-- | This is different than the runMake in 'Language.PureScript.Make' in that it specifies the
50-- options and ignores the warning messages.
48-- options and ignores the warning messages.
@@ -92,25 +90,28 @@ make ms = do
92-- | Performs a PSCi command
90-- | Performs a PSCi command
93handleCommand
91handleCommand
94 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
92 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
95− => Command
93+ => (String -> m ())
96 -> m ()
94 -> m ()
95+ -> Command
96+ -> m ()
97−handleCommand ShowHelp = liftIO $ putStrLn helpMessage
97+handleCommand _ _ ShowHelp = liftIO $ putStrLn helpMessage
98−handleCommand ResetState = handleResetState
98+handleCommand _ r ResetState = handleResetState r
99−handleCommand (Expression val) = handleExpression val
99+handleCommand c _ (Expression val) = handleExpression c val
100−handleCommand (Import im) = handleImport im
100+handleCommand _ _ (Import im) = handleImport im
101−handleCommand (Decls l) = handleDecls l
101+handleCommand _ _ (Decls l) = handleDecls l
102−handleCommand (TypeOf val) = handleTypeOf val
102+handleCommand _ _ (TypeOf val) = handleTypeOf val
103−handleCommand (KindOf typ) = handleKindOf typ
103+handleCommand _ _ (KindOf typ) = handleKindOf typ
104−handleCommand (BrowseModule moduleName) = handleBrowse moduleName
104+handleCommand _ _ (BrowseModule moduleName) = handleBrowse moduleName
105−handleCommand (ShowInfo QueryLoaded) = handleShowLoadedModules
105+handleCommand _ _ (ShowInfo QueryLoaded) = handleShowLoadedModules
106−handleCommand (ShowInfo QueryImport) = handleShowImportedModules
106+handleCommand _ _ (ShowInfo QueryImport) = handleShowImportedModules
107−handleCommand QuitPSCi = P.internalError "`handleCommand QuitPSCi` was called. This is a bug."
107+handleCommand _ _ QuitPSCi = P.internalError "`handleCommand QuitPSCi` was called. This is a bug."
108
108
109-- | Reset the application state
109-- | Reset the application state
110handleResetState
110handleResetState
111 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
111 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
112 => m ()
112 => m ()
113+ -> m ()
113−handleResetState = do
114+handleResetState reload = do
114 modify $ updateImportedModules (const [])
115 modify $ updateImportedModules (const [])
115 . updateLets (const [])
116 . updateLets (const [])
116 files <- asks psciLoadedFiles
117 files <- asks psciLoadedFiles
@@ -120,30 +121,25 @@ handleResetState = do
120 return (map snd modules, externs)
121 return (map snd modules, externs)
121 case e of
122 case e of
122 Left errs -> printErrors errs
123 Left errs -> printErrors errs
124+ Right (modules, externs) -> do
123− Right (modules, externs) -> modify (updateLoadedExterns (const (zip modules externs)))
125+ modify (updateLoadedExterns (const (zip modules externs)))
126+ reload
124
127
125-- | Takes a value expression and evaluates it with the current state.
128-- | Takes a value expression and evaluates it with the current state.
126−--
127−-- TODO: factor out the Node process runner, so that we can use PSCi in other settings.
128handleExpression
129handleExpression
129 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
130 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
131+ => (String -> m ())
130− => P.Expr
132+ -> P.Expr
131 -> m ()
133 -> m ()
132−handleExpression val = do
134+handleExpression evaluate val = do
133 st <- get
135 st <- get
134 let m = createTemporaryModule True st val
136 let m = createTemporaryModule True st val
135− nodeArgs <- asks ((++ [indexFile]) . psciNodeFlags)
136 e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
137 e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
137 case e of
138 case e of
138 Left errs -> printErrors errs
139 Left errs -> printErrors errs
139 Right _ -> do
140 Right _ -> do
140− liftIO $ writeFile indexFile "require('$PSCI')['$main']();"
141+ js <- liftIO $ readFile (modulesDir </> "$PSCI" </> "index.js")
141− process <- liftIO findNodeProcess
142+ evaluate js
142− result <- liftIO $ traverse (\node -> readProcessWithExitCode node nodeArgs "") process
143− case result of
144− Just (ExitSuccess, out, _) -> liftIO $ putStrLn out
145− Just (ExitFailure _, _, err) -> liftIO $ putStrLn err
146− Nothing -> liftIO $ putStrLn "Couldn't find node.js"
147
143
148-- |
144-- |
149-- Takes a list of declarations and updates the environment, then run a make. If the declaration fails,
145-- Takes a list of declarations and updates the environment, then run a make. If the declaration fails,
@@ -188,17 +184,27 @@ handleShowImportedModules = do
188 showDeclType P.Implicit = ""
184 showDeclType P.Implicit = ""
189 showDeclType (P.Explicit refs) = refsList refs
185 showDeclType (P.Explicit refs) = refsList refs
190 showDeclType (P.Hiding refs) = " hiding " ++ refsList refs
186 showDeclType (P.Hiding refs) = " hiding " ++ refsList refs
191− refsList refs = " (" ++ commaList (map showRef refs) ++ ")"
187+ refsList refs = " (" ++ commaList (mapMaybe showRef refs) ++ ")"
192
188
193− showRef :: P.DeclarationRef -> String
189+ showRef :: P.DeclarationRef -> Maybe String
190+ showRef (P.TypeRef pn dctors) =
194− showRef (P.TypeRef pn dctors) = N.runProperName pn ++ "(" ++ maybe ".." (commaList . map N.runProperName) dctors ++ ")"
191+ Just $ N.runProperName pn ++ "(" ++ maybe ".." (commaList . map N.runProperName) dctors ++ ")"
195− showRef (P.TypeOpRef op) = "type " ++ N.showOp op
192+ showRef (P.TypeOpRef op) =
193+ Just $ "type " ++ N.showOp op
196− showRef (P.ValueRef ident) = N.runIdent ident
194+ showRef (P.ValueRef ident) =
195+ Just $ N.runIdent ident
197− showRef (P.ValueOpRef op) = N.showOp op
196+ showRef (P.ValueOpRef op) =
197+ Just $ N.showOp op
198− showRef (P.TypeClassRef pn) = "class " ++ N.runProperName pn
198+ showRef (P.TypeClassRef pn) =
199+ Just $ "class " ++ N.runProperName pn
199− showRef (P.TypeInstanceRef ident) = N.runIdent ident
200+ showRef (P.TypeInstanceRef ident) =
201+ Just $ N.runIdent ident
202+ showRef (P.ModuleRef name) =
200− showRef (P.ModuleRef name) = "module " ++ N.runModuleName name
203+ Just $ "module " ++ N.runModuleName name
204+ showRef (P.ReExportRef _ _) =
205+ Nothing
201− showRef (P.PositionedDeclarationRef _ _ ref) = showRef ref
206+ showRef (P.PositionedDeclarationRef _ _ ref) =
207+ showRef ref
202
208
203 commaList :: [String] -> String
209 commaList :: [String] -> String
204 commaList = intercalate ", "
210 commaList = intercalate ", "
src/Language/PureScript/Interactive/Module.hs+16−3
@@ -26,7 +26,7 @@ supportModuleIsDefined = any ((== supportModuleName) . P.getModuleName)
26loadModule :: FilePath -> IO (Either String [P.Module])
26loadModule :: FilePath -> IO (Either String [P.Module])
27loadModule filename = do
27loadModule filename = do
28 content <- readUTF8File filename
28 content <- readUTF8File filename
29− return $ either (Left . P.prettyPrintMultipleErrors False) (Right . map snd) $ P.parseModulesFromFiles id [(filename, content)]
29+ return $ either (Left . P.prettyPrintMultipleErrors P.defaultPPEOptions) (Right . map snd) $ P.parseModulesFromFiles id [(filename, content)]
30
30
31-- |
31-- |
32-- Load all modules.
32-- Load all modules.
@@ -45,14 +45,27 @@ createTemporaryModule :: Bool -> PSCiState -> P.Expr -> P.Module
45createTemporaryModule exec PSCiState{psciImportedModules = imports, psciLetBindings = lets} val =
45createTemporaryModule exec PSCiState{psciImportedModules = imports, psciLetBindings = lets} val =
46 let
46 let
47 moduleName = P.ModuleName [P.ProperName "$PSCI"]
47 moduleName = P.ModuleName [P.ProperName "$PSCI"]
48+ effModuleName = P.moduleNameFromString "Control.Monad.Eff"
49+ effImport = (effModuleName, P.Implicit, Just (P.ModuleName [P.ProperName "$Eff"]))
48 supportImport = (supportModuleName, P.Implicit, Just (P.ModuleName [P.ProperName "$Support"]))
50 supportImport = (supportModuleName, P.Implicit, Just (P.ModuleName [P.ProperName "$Support"]))
49 eval = P.Var (P.Qualified (Just (P.ModuleName [P.ProperName "$Support"])) (P.Ident "eval"))
51 eval = P.Var (P.Qualified (Just (P.ModuleName [P.ProperName "$Support"])) (P.Ident "eval"))
50 mainValue = P.App eval (P.Var (P.Qualified Nothing (P.Ident "it")))
52 mainValue = P.App eval (P.Var (P.Qualified Nothing (P.Ident "it")))
51 itDecl = P.ValueDeclaration (P.Ident "it") P.Public [] $ Right val
53 itDecl = P.ValueDeclaration (P.Ident "it") P.Public [] $ Right val
54+ typeDecl = P.TypeDeclaration (P.Ident "$main")
55+ (P.TypeApp
56+ (P.TypeApp
57+ (P.TypeConstructor
58+ (P.Qualified (Just (P.ModuleName [P.ProperName "$Eff"])) (P.ProperName "Eff")))
59+ (P.TypeWildcard internalSpan))
60+ (P.TypeWildcard internalSpan))
52 mainDecl = P.ValueDeclaration (P.Ident "$main") P.Public [] $ Right mainValue
61 mainDecl = P.ValueDeclaration (P.Ident "$main") P.Public [] $ Right mainValue
53− decls = if exec then [itDecl, mainDecl] else [itDecl]
62+ decls = if exec then [itDecl, typeDecl, mainDecl] else [itDecl]
63+ internalSpan = P.internalModuleSourceSpan "<internal>"
54 in
64 in
65+ P.Module internalSpan
66+ [] moduleName
55− P.Module (P.internalModuleSourceSpan "<internal>") [] moduleName ((importDecl `map` (supportImport : imports)) ++ lets ++ decls) Nothing
67+ ((importDecl `map` (effImport : supportImport : imports)) ++ lets ++ decls)
68+ Nothing
56
69
57
70
58-- |
71-- |
src/Language/PureScript/Interactive/Types.hs−1
@@ -13,7 +13,6 @@ import qualified Language.PureScript as P
13--
13--
14data PSCiConfig = PSCiConfig
14data PSCiConfig = PSCiConfig
15 { psciLoadedFiles :: [FilePath]
15 { psciLoadedFiles :: [FilePath]
16− , psciNodeFlags :: [String]
17 , psciEnvironment :: P.Environment
16 , psciEnvironment :: P.Environment
18 } deriving Show
17 } deriving Show
19
18
src/Language/PureScript/Kinds.hs+8−18
@@ -6,30 +6,20 @@ import Prelude.Compat
6
6
7import qualified Data.Aeson.TH as A
7import qualified Data.Aeson.TH as A
8
8
9−-- |
10−-- The data type of kinds
9+-- | The data type of kinds
11−--
12data Kind
10data Kind
13− -- |
14− -- Unification variable of type Kind
11+ -- | Unification variable of type Kind
15− --
16 = KUnknown Int
12 = KUnknown Int
17− -- |
18− -- The kind of types
13+ -- | The kind of types
19− --
20 | Star
14 | Star
21− -- |
22− -- The kind of effects
15+ -- | The kind of effects
23− --
24 | Bang
16 | Bang
25− -- |
26− -- Kinds for labelled, unordered rows without duplicates
17+ -- | Kinds for labelled, unordered rows without duplicates
27− --
28 | Row Kind
18 | Row Kind
29− -- |
30− -- Function kinds
19+ -- | Function kinds
31− --
32 | FunKind Kind Kind
20 | FunKind Kind Kind
21+ -- | Type-level strings
22+ | Symbol
33 deriving (Show, Read, Eq, Ord)
23 deriving (Show, Read, Eq, Ord)
34
24
35$(A.deriveJSON A.defaultOptions ''Kind)
25$(A.deriveJSON A.defaultOptions ''Kind)
src/Language/PureScript/Linter/Exhaustive.hs+2−2
@@ -140,7 +140,7 @@ missingCasesSingle env mn (LiteralBinder (ObjectLiteral bs)) (LiteralBinder (Obj
140 where
140 where
141 fm = fromMaybe e
141 fm = fromMaybe e
142
142
143− compBS :: Eq a => b -> a -> Maybe b -> Maybe b -> (a, (b, b))
143+ compBS :: b -> a -> Maybe b -> Maybe b -> (a, (b, b))
144 compBS e s b b' = (s, compB e b b')
144 compBS e s b b' = (s, compB e b b')
145
145
146 (sortedNames, binders) = unzip $ genericMerge (compBS NullBinder) sbs sbs'
146 (sortedNames, binders) = unzip $ genericMerge (compBS NullBinder) sbs sbs'
@@ -274,7 +274,7 @@ checkExhaustive env mn numArgs cas expr = makeResult . first nub $ foldl' step (
274 --
274 --
275 -- The binder information is provided so that it can be embedded in the constraint,
275 -- The binder information is provided so that it can be embedded in the constraint,
276 -- and then included in the error message.
276 -- and then included in the error message.
277− addPartialConstraint :: MonadSupply m => ([[Binder]], Bool) -> Expr -> m Expr
277+ addPartialConstraint :: ([[Binder]], Bool) -> Expr -> m Expr
278 addPartialConstraint (bss, complete) e = do
278 addPartialConstraint (bss, complete) e = do
279 tyVar <- ("p" ++) . show <$> fresh
279 tyVar <- ("p" ++) . show <$> fresh
280 var <- freshName
280 var <- freshName
src/Language/PureScript/Linter/Imports.hs+1−2
@@ -169,8 +169,7 @@ lintImports (Module ss _ mn mdecls (Just mexports)) env usedImps = do
169 go (q, name) = M.alter (Just . maybe [name] (name :)) q
169 go (q, name) = M.alter (Just . maybe [name] (name :)) q
170
170
171 extractByQual
171 extractByQual
172− :: Eq a
173− => ModuleName
172+ :: ModuleName
174 -> M.Map (Qualified a) [ImportRecord a]
173 -> M.Map (Qualified a) [ImportRecord a]
175 -> (a -> Name)
174 -> (a -> Name)
176 -> [(ModuleName, Qualified Name)]
175 -> [(ModuleName, Qualified Name)]
src/Language/PureScript/Make.hs+2−2
@@ -132,7 +132,7 @@ data RebuildPolicy
132 | RebuildAlways deriving (Show, Read, Eq, Ord)
132 | RebuildAlways deriving (Show, Read, Eq, Ord)
133
133
134-- | Rebuild a single module
134-- | Rebuild a single module
135−rebuildModule :: forall m. (Monad m, MonadBaseControl IO m, MonadReader Options m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
135+rebuildModule :: forall m. (Monad m, MonadBaseControl IO m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
136 => MakeActions m
136 => MakeActions m
137 -> [ExternsFile]
137 -> [ExternsFile]
138 -> Module
138 -> Module
@@ -159,7 +159,7 @@ rebuildModule MakeActions{..} externs m@(Module _ _ moduleName _ _) = do
159-- If timestamps have not changed, the externs file can be used to provide the module's types without
159-- If timestamps have not changed, the externs file can be used to provide the module's types without
160-- having to typecheck the module again.
160-- having to typecheck the module again.
161--
161--
162−make :: forall m. (Monad m, MonadBaseControl IO m, MonadReader Options m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
162+make :: forall m. (Monad m, MonadBaseControl IO m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
163 => MakeActions m
163 => MakeActions m
164 -> [Module]
164 -> [Module]
165 -> m [ExternsFile]
165 -> m [ExternsFile]
src/Language/PureScript/Parser/Common.hs+10−1
@@ -16,9 +16,18 @@ import Language.PureScript.Parser.State
16
16
17import qualified Text.Parsec as P
17import qualified Text.Parsec as P
18
18
19+-- |
20+-- Parse a general proper name.
21+--
19properName :: TokenParser (ProperName a)
22properName :: TokenParser (ProperName a)
20properName = ProperName <$> uname
23properName = ProperName <$> uname
21
24
25+-- |
26+-- Parse a proper name for a type.
27+--
28+typeName :: TokenParser (ProperName 'TypeName)
29+typeName = ProperName <$> tyname
30+
22-- |
31-- |
23-- Parse a module name
32-- Parse a module name
24--
33--
@@ -63,7 +72,7 @@ augment p q f = flip (maybe id $ flip f) <$> p <*> P.optionMaybe q
63-- |
72-- |
64-- Run the first parser, then match the second zero or more times, applying the specified function for each match
73-- Run the first parser, then match the second zero or more times, applying the specified function for each match
65--
74--
66−fold :: P.Stream s m t => P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a
75+fold :: P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a
67fold first more combine = do
76fold first more combine = do
68 a <- first
77 a <- first
69 bs <- P.many more
78 bs <- P.many more
src/Language/PureScript/Parser/Declarations.hs+8−8
@@ -66,7 +66,7 @@ kindedIdent = (, Nothing) <$> identifier
66parseDataDeclaration :: TokenParser Declaration
66parseDataDeclaration :: TokenParser Declaration
67parseDataDeclaration = do
67parseDataDeclaration = do
68 dtype <- (reserved "data" *> return Data) <|> (reserved "newtype" *> return Newtype)
68 dtype <- (reserved "data" *> return Data) <|> (reserved "newtype" *> return Newtype)
69− name <- indented *> properName
69+ name <- indented *> typeName
70 tyArgs <- many (indented *> kindedIdent)
70 tyArgs <- many (indented *> kindedIdent)
71 ctors <- P.option [] $ do
71 ctors <- P.option [] $ do
72 indented *> equals
72 indented *> equals
@@ -80,7 +80,7 @@ parseTypeDeclaration =
80
80
81parseTypeSynonymDeclaration :: TokenParser Declaration
81parseTypeSynonymDeclaration :: TokenParser Declaration
82parseTypeSynonymDeclaration =
82parseTypeSynonymDeclaration =
83− TypeSynonymDeclaration <$> (reserved "type" *> indented *> properName)
83+ TypeSynonymDeclaration <$> (reserved "type" *> indented *> typeName)
84 <*> many (indented *> kindedIdent)
84 <*> many (indented *> kindedIdent)
85 <*> (indented *> equals *> noWildcards parsePolyType)
85 <*> (indented *> equals *> noWildcards parsePolyType)
86
86
@@ -108,7 +108,7 @@ parseValueDeclaration = do
108
108
109parseExternDeclaration :: TokenParser Declaration
109parseExternDeclaration :: TokenParser Declaration
110parseExternDeclaration = reserved "foreign" *> indented *> reserved "import" *> indented *>
110parseExternDeclaration = reserved "foreign" *> indented *> reserved "import" *> indented *>
111− (ExternDataDeclaration <$> (reserved "data" *> indented *> properName)
111+ (ExternDataDeclaration <$> (reserved "data" *> indented *> typeName)
112 <*> (indented *> doubleColon *> parseKind)
112 <*> (indented *> doubleColon *> parseKind)
113 <|> (do ident <- parseIdent
113 <|> (do ident <- parseIdent
114 ty <- indented *> doubleColon *> noWildcards parsePolyType
114 ty <- indented *> doubleColon *> noWildcards parsePolyType
@@ -132,7 +132,7 @@ parseFixityDeclaration = do
132 where
132 where
133 typeFixity fixity =
133 typeFixity fixity =
134 TypeFixity fixity
134 TypeFixity fixity
135− <$> (reserved "type" *> parseQualified properName)
135+ <$> (reserved "type" *> parseQualified typeName)
136 <*> (reserved "as" *> parseOperator)
136 <*> (reserved "as" *> parseOperator)
137 valueFixity fixity =
137 valueFixity fixity =
138 ValueFixity fixity
138 ValueFixity fixity
@@ -140,7 +140,7 @@ parseFixityDeclaration = do
140 <*> (reserved "as" *> parseOperator)
140 <*> (reserved "as" *> parseOperator)
141
141
142parseImportDeclaration :: TokenParser Declaration
142parseImportDeclaration :: TokenParser Declaration
143−parseImportDeclaration = do
143+parseImportDeclaration = withSourceSpan PositionedDeclaration $ do
144 (mn, declType, asQ) <- parseImportDeclaration'
144 (mn, declType, asQ) <- parseImportDeclaration'
145 return $ ImportDeclaration mn declType asQ
145 return $ ImportDeclaration mn declType asQ
146
146
@@ -169,7 +169,7 @@ parseDeclarationRef =
169 <|> (TypeOpRef <$> (indented *> reserved "type" *> parens parseOperator))
169 <|> (TypeOpRef <$> (indented *> reserved "type" *> parens parseOperator))
170 where
170 where
171 parseTypeRef = do
171 parseTypeRef = do
172− name <- properName
172+ name <- typeName
173 dctors <- P.optionMaybe $ parens (symbol' ".." *> pure Nothing <|> Just <$> commaSep properName)
173 dctors <- P.optionMaybe $ parens (symbol' ".." *> pure Nothing <|> Just <$> commaSep properName)
174 return $ TypeRef name (fromMaybe (Just []) dctors)
174 return $ TypeRef name (fromMaybe (Just []) dctors)
175
175
@@ -183,7 +183,7 @@ parseTypeClassDeclaration = do
183 return implies
183 return implies
184 className <- indented *> properName
184 className <- indented *> properName
185 idents <- P.many (indented *> kindedIdent)
185 idents <- P.many (indented *> kindedIdent)
186− members <- P.option [] . P.try $ do
186+ members <- P.option [] $ do
187 indented *> reserved "where"
187 indented *> reserved "where"
188 indented *> mark (P.many (same *> positioned parseTypeDeclaration))
188 indented *> mark (P.many (same *> positioned parseTypeDeclaration))
189 return $ TypeClassDeclaration className idents implies members
189 return $ TypeClassDeclaration className idents implies members
@@ -209,7 +209,7 @@ parseInstanceDeclaration = do
209parseTypeInstanceDeclaration :: TokenParser Declaration
209parseTypeInstanceDeclaration :: TokenParser Declaration
210parseTypeInstanceDeclaration = do
210parseTypeInstanceDeclaration = do
211 instanceDecl <- parseInstanceDeclaration
211 instanceDecl <- parseInstanceDeclaration
212− members <- P.option [] . P.try $ do
212+ members <- P.option [] $ do
213 indented *> reserved "where"
213 indented *> reserved "where"
214 mark (P.many (same *> positioned parseValueDeclaration))
214 mark (P.many (same *> positioned parseValueDeclaration))
215 return $ instanceDecl (ExplicitInstance members)
215 return $ instanceDecl (ExplicitInstance members)
src/Language/PureScript/Parser/Kinds.hs+4
@@ -18,10 +18,14 @@ parseStar = const Star <$> symbol' "*"
18parseBang :: TokenParser Kind
18parseBang :: TokenParser Kind
19parseBang = const Bang <$> symbol' "!"
19parseBang = const Bang <$> symbol' "!"
20
20
21+parseSymbol :: TokenParser Kind
22+parseSymbol = const Symbol <$> uname' "Symbol"
23+
21parseTypeAtom :: TokenParser Kind
24parseTypeAtom :: TokenParser Kind
22parseTypeAtom = indented *> P.choice
25parseTypeAtom = indented *> P.choice
23 [ parseStar
26 [ parseStar
24 , parseBang
27 , parseBang
28+ , parseSymbol
25 , parens parseKind
29 , parens parseKind
26 ]
30 ]
27-- |
31-- |
src/Language/PureScript/Parser/Lexer.hs+20−12
@@ -41,6 +41,7 @@ module Language.PureScript.Parser.Lexer
41 , commaSep1
41 , commaSep1
42 , lname
42 , lname
43 , qualifier
43 , qualifier
44+ , tyname
44 , uname
45 , uname
45 , uname'
46 , uname'
46 , mname
47 , mname
@@ -213,8 +214,9 @@ parseToken = P.choice
213 , P.try $ P.char '_' *> P.notFollowedBy identLetter *> pure Underscore
214 , P.try $ P.char '_' *> P.notFollowedBy identLetter *> pure Underscore
214 , HoleLit <$> P.try (P.char '?' *> P.many1 identLetter)
215 , HoleLit <$> P.try (P.char '?' *> P.many1 identLetter)
215 , LName <$> parseLName
216 , LName <$> parseLName
216− , do uName <- parseUName
217+ , parseUName >>= \uName ->
217− (guard (validModuleName uName) >> Qualifier uName <$ P.char '.') <|> pure (UName uName)
218+ (guard (validModuleName uName) >> Qualifier uName <$ P.char '.')
219+ <|> pure (UName uName)
218 , Symbol <$> parseSymbol
220 , Symbol <$> parseSymbol
219 , CharLiteral <$> parseCharLiteral
221 , CharLiteral <$> parseCharLiteral
220 , StringLiteral <$> parseStringLiteral
222 , StringLiteral <$> parseStringLiteral
@@ -226,7 +228,7 @@ parseToken = P.choice
226 parseLName = (:) <$> identStart <*> P.many identLetter
228 parseLName = (:) <$> identStart <*> P.many identLetter
227
229
228 parseUName :: P.Parsec String u String
230 parseUName :: P.Parsec String u String
229− parseUName = (:) <$> P.upper <*> P.many uidentLetter
231+ parseUName = (:) <$> P.upper <*> P.many identLetter
230
232
231 parseSymbol :: P.Parsec String u String
233 parseSymbol :: P.Parsec String u String
232 parseSymbol = P.many1 symbolChar
234 parseSymbol = P.many1 symbolChar
@@ -237,9 +239,6 @@ parseToken = P.choice
237 identLetter :: P.Parsec String u Char
239 identLetter :: P.Parsec String u Char
238 identLetter = P.alphaNum <|> P.oneOf "_'"
240 identLetter = P.alphaNum <|> P.oneOf "_'"
239
241
240− uidentLetter :: P.Parsec String u Char
241− uidentLetter = P.alphaNum <|> P.char '_'
242−
243 symbolChar :: P.Parsec String u Char
242 symbolChar :: P.Parsec String u Char
244 symbolChar = P.satisfy isSymbolChar
243 symbolChar = P.satisfy isSymbolChar
245
244
@@ -430,6 +429,18 @@ reserved s = token go P.<?> show s
430
429
431uname :: TokenParser String
430uname :: TokenParser String
432uname = token go P.<?> "proper name"
431uname = token go P.<?> "proper name"
432+ where
433+ go (UName s) | validUName s = Just s
434+ go _ = Nothing
435+
436+uname' :: String -> TokenParser ()
437+uname' s = token go P.<?> "proper name"
438+ where
439+ go (UName s') | s == s' = Just ()
440+ go _ = Nothing
441+
442+tyname :: TokenParser String
443+tyname = token go P.<?> "type name"
433 where
444 where
434 go (UName s) = Just s
445 go (UName s) = Just s
435 go _ = Nothing
446 go _ = Nothing
@@ -440,12 +451,6 @@ mname = token go P.<?> "module name"
440 go (UName s) | validModuleName s = Just s
451 go (UName s) | validModuleName s = Just s
441 go _ = Nothing
452 go _ = Nothing
442
453
443−uname' :: String -> TokenParser ()
444−uname' s = token go P.<?> show s
445− where
446− go (UName s') | s == s' = Just ()
447− go _ = Nothing
448−
449symbol :: TokenParser String
454symbol :: TokenParser String
450symbol = token go P.<?> "symbol"
455symbol = token go P.<?> "symbol"
451 where
456 where
@@ -496,6 +501,9 @@ identifier = token go P.<?> "identifier"
496validModuleName :: String -> Bool
501validModuleName :: String -> Bool
497validModuleName s = '_' `notElem` s
502validModuleName s = '_' `notElem` s
498
503
504+validUName :: String -> Bool
505+validUName s = '\'' `notElem` s
506+
499-- |
507-- |
500-- A list of purescript reserved identifiers
508-- A list of purescript reserved identifiers
501--
509--
src/Language/PureScript/Parser/Types.hs+5−1
@@ -26,6 +26,9 @@ parseFunction = parens rarrow >> return tyFunction
26parseObject :: TokenParser Type
26parseObject :: TokenParser Type
27parseObject = braces $ TypeApp tyRecord <$> parseRow
27parseObject = braces $ TypeApp tyRecord <$> parseRow
28
28
29+parseTypeLevelString :: TokenParser Type
30+parseTypeLevelString = TypeLevelString <$> stringLiteral
31+
29parseTypeWildcard :: TokenParser Type
32parseTypeWildcard :: TokenParser Type
30parseTypeWildcard = do
33parseTypeWildcard = do
31 start <- P.getPosition
34 start <- P.getPosition
@@ -40,7 +43,7 @@ parseTypeVariable = do
40 return $ TypeVar ident
43 return $ TypeVar ident
41
44
42parseTypeConstructor :: TokenParser Type
45parseTypeConstructor :: TokenParser Type
43−parseTypeConstructor = TypeConstructor <$> parseQualified properName
46+parseTypeConstructor = TypeConstructor <$> parseQualified typeName
44
47
45parseForAll :: TokenParser Type
48parseForAll :: TokenParser Type
46parseForAll = mkForAll <$> ((reserved "forall" <|> reserved "∀") *> P.many1 (indented *> identifier) <* indented <* dot)
49parseForAll = mkForAll <$> ((reserved "forall" <|> reserved "∀") *> P.many1 (indented *> identifier) <* indented <* dot)
@@ -53,6 +56,7 @@ parseTypeAtom :: TokenParser Type
53parseTypeAtom = indented *> P.choice
56parseTypeAtom = indented *> P.choice
54 [ P.try parseConstrainedType
57 [ P.try parseConstrainedType
55 , P.try parseFunction
58 , P.try parseFunction
59+ , parseTypeLevelString
56 , parseObject
60 , parseObject
57 , parseTypeWildcard
61 , parseTypeWildcard
58 , parseForAll
62 , parseForAll
src/Language/PureScript/Pretty/Common.hs+5−1
@@ -114,7 +114,7 @@ blockIndent = 4
114-- |
114-- |
115-- Pretty print with a new indentation level
115-- Pretty print with a new indentation level
116--
116--
117−withIndent :: (Emit gen) => StateT PrinterState Maybe gen -> StateT PrinterState Maybe gen
117+withIndent :: StateT PrinterState Maybe gen -> StateT PrinterState Maybe gen
118withIndent action = do
118withIndent action = do
119 modify $ \st -> st { indent = indent st + blockIndent }
119 modify $ \st -> st { indent = indent st + blockIndent }
120 result <- action
120 result <- action
@@ -153,3 +153,7 @@ before b1 b2 | rows b1 > 1 = b1 // b2
153
153
154beforeWithSpace :: Box -> Box -> Box
154beforeWithSpace :: Box -> Box -> Box
155beforeWithSpace b1 = before (b1 <> text " ")
155beforeWithSpace b1 = before (b1 <> text " ")
156+
157+-- | Place a Box on the bottom right of another
158+endWith :: Box -> Box -> Box
159+endWith l r = l <> vcat top [emptyBox (rows l - 1) (cols r), r]
src/Language/PureScript/Pretty/Kinds.hs+1
@@ -21,6 +21,7 @@ typeLiterals = mkPattern match
21 where
21 where
22 match Star = Just "*"
22 match Star = Just "*"
23 match Bang = Just "!"
23 match Bang = Just "!"
24+ match Symbol = Just "Symbol"
24 match (KUnknown u) = Just $ 'u' : show u
25 match (KUnknown u) = Just $ 'u' : show u
25 match _ = Nothing
26 match _ = Nothing
26
27
src/Language/PureScript/Pretty/Types.hs+1
@@ -32,6 +32,7 @@ typeLiterals = mkPattern match
32 where
32 where
33 match TypeWildcard{} = Just $ text "_"
33 match TypeWildcard{} = Just $ text "_"
34 match (TypeVar var) = Just $ text var
34 match (TypeVar var) = Just $ text var
35+ match (TypeLevelString s) = Just . text $ show s
35 match (PrettyPrintObject row) = Just $ prettyPrintRowWith '{' '}' row
36 match (PrettyPrintObject row) = Just $ prettyPrintRowWith '{' '}' row
36 match (TypeConstructor ctor) = Just $ text $ runProperName $ disqualify ctor
37 match (TypeConstructor ctor) = Just $ text $ runProperName $ disqualify ctor
37 match (TUnknown u) = Just $ text $ 't' : show u
38 match (TUnknown u) = Just $ text $ 't' : show u
src/Language/PureScript/Publish.hs+1
@@ -21,6 +21,7 @@ module Language.PureScript.Publish
21 , getResolvedDependencies
21 , getResolvedDependencies
22 ) where
22 ) where
23
23
24+import Prelude ()
24import Prelude.Compat hiding (userError)
25import Prelude.Compat hiding (userError)
25
26
26import Control.Arrow ((***))
27import Control.Arrow ((***))
src/Language/PureScript/Publish/ErrorsWarnings.hs+1−1
@@ -225,7 +225,7 @@ displayUserError e = case e of
225 CompileError err ->
225 CompileError err ->
226 vcat
226 vcat
227 [ para "Compile error:"
227 [ para "Compile error:"
228− , indented (vcat (P.prettyPrintMultipleErrorsBox False err))
228+ , indented (vcat (P.prettyPrintMultipleErrorsBox P.defaultPPEOptions err))
229 ]
229 ]
230 DirtyWorkingTree ->
230 DirtyWorkingTree ->
231 para (
231 para (
src/Language/PureScript/Sugar/CaseDeclarations.hs+1−1
@@ -144,7 +144,7 @@ toTuple (ValueDeclaration _ _ bs result) = (bs, result)
144toTuple (PositionedDeclaration _ _ d) = toTuple d
144toTuple (PositionedDeclaration _ _ d) = toTuple d
145toTuple _ = internalError "Not a value declaration"
145toTuple _ = internalError "Not a value declaration"
146
146
147−makeCaseDeclaration :: forall m. (MonadSupply m, MonadError MultipleErrors m) => Ident -> [([Binder], Either [(Guard, Expr)] Expr)] -> m Declaration
147+makeCaseDeclaration :: forall m. (MonadSupply m) => Ident -> [([Binder], Either [(Guard, Expr)] Expr)] -> m Declaration
148makeCaseDeclaration ident alternatives = do
148makeCaseDeclaration ident alternatives = do
149 let namedArgs = map findName . fst <$> alternatives
149 let namedArgs = map findName . fst <$> alternatives
150 argNames = foldl1 resolveNames namedArgs
150 argNames = foldl1 resolveNames namedArgs
src/Language/PureScript/Sugar/Names.hs+30−25
@@ -10,7 +10,7 @@ module Language.PureScript.Sugar.Names
10
10
11import Prelude.Compat
11import Prelude.Compat
12
12
13−import Control.Arrow (first, second)
13+import Control.Arrow (first)
14import Control.Monad
14import Control.Monad
15import Control.Monad.Error.Class (MonadError(..))
15import Control.Monad.Error.Class (MonadError(..))
16import Control.Monad.State.Lazy
16import Control.Monad.State.Lazy
@@ -84,16 +84,19 @@ desugarImportsWithEnv externs modules = do
84 toExportedType _ = Nothing
84 toExportedType _ = Nothing
85
85
86 exportedTypeOps :: M.Map (OpName 'TypeOpName) ModuleName
86 exportedTypeOps :: M.Map (OpName 'TypeOpName) ModuleName
87− exportedTypeOps = M.fromList $ (, efModuleName) <$> mapMaybe getTypeOpRef efExports
87+ exportedTypeOps = exportedRefs getTypeOpRef
88
88
89 exportedTypeClasses :: M.Map (ProperName 'ClassName) ModuleName
89 exportedTypeClasses :: M.Map (ProperName 'ClassName) ModuleName
90− exportedTypeClasses = M.fromList $ (, efModuleName) <$> mapMaybe getTypeClassRef efExports
90+ exportedTypeClasses = exportedRefs getTypeClassRef
91
91
92 exportedValues :: M.Map Ident ModuleName
92 exportedValues :: M.Map Ident ModuleName
93− exportedValues = M.fromList $ (, efModuleName) <$> mapMaybe getValueRef efExports
93+ exportedValues = exportedRefs getValueRef
94
94
95 exportedValueOps :: M.Map (OpName 'ValueOpName) ModuleName
95 exportedValueOps :: M.Map (OpName 'ValueOpName) ModuleName
96+ exportedValueOps = exportedRefs getValueOpRef
97+
98+ exportedRefs :: Ord a => (DeclarationRef -> Maybe a) -> M.Map a ModuleName
96− exportedValueOps = M.fromList $ (, efModuleName) <$> mapMaybe getValueOpRef efExports
99+ exportedRefs f = M.fromList $ (, efModuleName) <$> mapMaybe f efExports
97
100
98 updateEnv :: ([Module], Env) -> Module -> m ([Module], Env)
101 updateEnv :: ([Module], Env) -> Module -> m ([Module], Env)
99 updateEnv (ms, env) m@(Module ss _ mn _ refs) =
102 updateEnv (ms, env) m@(Module ss _ mn _ refs) =
@@ -110,9 +113,10 @@ desugarImportsWithEnv externs modules = do
110 renameInModule' env m@(Module _ _ mn _ _) =
113 renameInModule' env m@(Module _ _ mn _ _) =
111 warnAndRethrow (addHint (ErrorInModule mn)) $ do
114 warnAndRethrow (addHint (ErrorInModule mn)) $ do
112 let (_, imps, exps) = fromMaybe (internalError "Module is missing in renameInModule'") $ M.lookup mn env
115 let (_, imps, exps) = fromMaybe (internalError "Module is missing in renameInModule'") $ M.lookup mn env
113− (m', used) <- flip runStateT M.empty $ renameInModule imps (elaborateExports exps m)
116+ (m', used) <- flip runStateT M.empty $ renameInModule imps m
117+ let m'' = elaborateExports exps m'
114− lintImports m' env used
118+ lintImports m'' env used
115− return m'
119+ return m''
116
120
117-- |
121-- |
118-- Make all exports for a module explicit. This may still effect modules that
122-- Make all exports for a module explicit. This may still effect modules that
@@ -121,24 +125,25 @@ desugarImportsWithEnv externs modules = do
121--
125--
122elaborateExports :: Exports -> Module -> Module
126elaborateExports :: Exports -> Module -> Module
123elaborateExports exps (Module ss coms mn decls refs) =
127elaborateExports exps (Module ss coms mn decls refs) =
124− Module ss coms mn decls $
128+ Module ss coms mn decls $ Just
125− Just $ map (\(ctor, dctors) -> TypeRef ctor (Just dctors)) myTypes ++
129+ $ elaboratedTypeRefs
126− map TypeOpRef (my exportedTypeOps) ++
130+ ++ go TypeOpRef exportedTypeOps
127− map TypeClassRef (my exportedTypeClasses) ++
131+ ++ go TypeClassRef exportedTypeClasses
128− map ValueRef (my exportedValues) ++
132+ ++ go ValueRef exportedValues
129− map ValueOpRef (my exportedValueOps) ++
133+ ++ go ValueOpRef exportedValueOps
130− maybe [] (filter isModuleRef) refs
134+ ++ maybe [] (filter isModuleRef) refs
131 where
135 where
132− -- Extracts a list of values from the exports and filters out any values that
133− -- are re-exports from other modules.
134− my :: (Exports -> M.Map a ModuleName) -> [a]
135− my = map fst <$> filt (== mn)
136
136
137− myTypes :: [(ProperName 'TypeName, [ProperName 'ConstructorName])]
137+ elaboratedTypeRefs :: [DeclarationRef]
138− myTypes = second fst <$> filt ((== mn) . snd) exportedTypes
138+ elaboratedTypeRefs =
139+ flip map (M.toList (exportedTypes exps)) $ \(tctor, (dctors, mn')) ->
140+ let ref = TypeRef tctor (Just dctors)
141+ in if mn == mn' then ref else ReExportRef mn' ref
139
142
140− filt :: (b -> Bool) -> (Exports -> M.Map a b) -> [(a, b)]
143+ go :: (a -> DeclarationRef) -> (Exports -> M.Map a ModuleName) -> [DeclarationRef]
141− filt predicate f = M.toList $ predicate `M.filter` f exps
144+ go toRef select =
145+ flip map (M.toList (select exps)) $ \(export, mn') ->
146+ if mn == mn' then toRef export else ReExportRef mn' (toRef export)
142
147
143-- |
148-- |
144-- Replaces all local names with qualified names within a module and checks that all existing
149-- Replaces all local names with qualified names within a module and checks that all existing
@@ -292,7 +297,7 @@ renameInModule imports (Module ss coms mn decls exps) =
292 -- qualified references are replaced with their canoncial qualified names
297 -- qualified references are replaced with their canoncial qualified names
293 -- (e.g. M.Map -> Data.Map.Map).
298 -- (e.g. M.Map -> Data.Map.Map).
294 update
299 update
295− :: (Ord a, Show a)
300+ :: (Ord a)
296 => M.Map (Qualified a) [ImportRecord a]
301 => M.Map (Qualified a) [ImportRecord a]
297 -> (a -> Name)
302 -> (a -> Name)
298 -> Qualified a
303 -> Qualified a
@@ -329,5 +334,5 @@ renameInModule imports (Module ss coms mn decls exps) =
329 _ -> throwUnknown
334 _ -> throwUnknown
330
335
331 where
336 where
332− positioned err = maybe err (`rethrowWithPosition` err) pos
337+ positioned err = maybe err (`warnAndRethrowWithPosition` err) pos
333 throwUnknown = throwError . errorMessage . UnknownName . fmap toName $ qname
338 throwUnknown = throwError . errorMessage . UnknownName . fmap toName $ qname
src/Language/PureScript/Sugar/Names/Env.hs+68−31
@@ -10,6 +10,7 @@ module Language.PureScript.Sugar.Names.Env
10 , envModuleSourceSpan
10 , envModuleSourceSpan
11 , envModuleImports
11 , envModuleImports
12 , envModuleExports
12 , envModuleExports
13+ , ExportMode(..)
13 , exportType
14 , exportType
14 , exportTypeOp
15 , exportTypeOp
15 , exportTypeClass
16 , exportTypeClass
@@ -26,6 +27,7 @@ import Control.Monad.Error.Class (MonadError(..))
26import Control.Monad.Writer.Class (MonadWriter(..))
27import Control.Monad.Writer.Class (MonadWriter(..))
27
28
28import Data.Function (on)
29import Data.Function (on)
30+import Data.Foldable (find)
29import Data.List (groupBy, sortBy, delete)
31import Data.List (groupBy, sortBy, delete)
30import Data.Maybe (fromJust, mapMaybe)
32import Data.Maybe (fromJust, mapMaybe)
31import qualified Data.Map as M
33import qualified Data.Map as M
@@ -205,32 +207,51 @@ primEnv = M.singleton
205 primModuleName
207 primModuleName
206 (internalModuleSourceSpan "<Prim>", nullImports, primExports)
208 (internalModuleSourceSpan "<Prim>", nullImports, primExports)
207
209
210+-- |
211+-- When updating the `Exports` the behaviour is slightly different depending
212+-- on whether we are exporting values defined within the module or elaborating
213+-- re-exported values. This type is used to indicate which behaviour should be
214+-- used.
215+--
216+data ExportMode = Internal | ReExport
217+ deriving (Eq, Show)
218+
208-- |
219-- |
209-- Safely adds a type and its data constructors to some exports, returning an
220-- Safely adds a type and its data constructors to some exports, returning an
210-- error if a conflict occurs.
221-- error if a conflict occurs.
211--
222--
212exportType
223exportType
213 :: MonadError MultipleErrors m
224 :: MonadError MultipleErrors m
225+ => ExportMode
214− => Exports
226+ -> Exports
215 -> ProperName 'TypeName
227 -> ProperName 'TypeName
216 -> [ProperName 'ConstructorName]
228 -> [ProperName 'ConstructorName]
217 -> ModuleName
229 -> ModuleName
218 -> m Exports
230 -> m Exports
219−exportType exps name dctors mn = do
231+exportType exportMode exps name dctors mn = do
220 let exTypes = exportedTypes exps
232 let exTypes = exportedTypes exps
221 let exClasses = exportedTypeClasses exps
233 let exClasses = exportedTypeClasses exps
234+ case exportMode of
235+ Internal -> do
236+ when (name `M.member` exTypes) $
237+ throwDeclConflict (TyName name) (TyName name)
238+ when (coerceProperName name `M.member` exClasses) $
239+ throwDeclConflict (TyName name) (TyClassName (coerceProperName name))
240+ forM_ dctors $ \dctor -> do
241+ when ((elem dctor . fst) `any` exTypes) $
242+ throwDeclConflict (DctorName dctor) (DctorName dctor)
243+ when (coerceProperName dctor `M.member` exClasses) $
244+ throwDeclConflict (DctorName dctor) (TyClassName (coerceProperName dctor))
245+ ReExport -> do
222− forM_ (name `M.lookup` exTypes) $ \(_, mn') ->
246+ forM_ (name `M.lookup` exTypes) $ \(_, mn') ->
223− when (mn /= mn') $ throwConflictError ConflictingTypeDecls name
247+ when (mn /= mn') $
224− when (coerceProperName name `M.member` exClasses) $
248+ throwExportConflict mn mn' (TyName name)
225− throwConflictError TypeConflictsWithClass name
226− forM_ dctors $ \dctor -> do
249+ forM_ dctors $ \dctor ->
227− when (dctorExists (coerceProperName dctor) `any` exTypes) $
250+ forM_ ((elem dctor . fst) `find` exTypes) $ \(_, mn') ->
228− throwConflictError ConflictingCtorDecls dctor
251+ when (mn /= mn') $
229− when (coerceProperName dctor `M.member` exClasses) $
252+ throwExportConflict mn mn' (DctorName dctor)
230− throwConflictError CtorConflictsWithClass dctor
231 return $ exps { exportedTypes = M.alter updateOrInsert name exTypes }
253 return $ exps { exportedTypes = M.alter updateOrInsert name exTypes }
232 where
254 where
233− dctorExists dctor (dctors', mn') = mn /= mn' && elem dctor dctors'
234 updateOrInsert Nothing = Just (dctors, mn)
255 updateOrInsert Nothing = Just (dctors, mn)
235 updateOrInsert (Just (dctors', _)) = Just (dctors ++ dctors', mn)
256 updateOrInsert (Just (dctors', _)) = Just (dctors ++ dctors', mn)
236
257
@@ -245,7 +266,7 @@ exportTypeOp
245 -> ModuleName
266 -> ModuleName
246 -> m Exports
267 -> m Exports
247exportTypeOp exps op mn = do
268exportTypeOp exps op mn = do
248− typeOps <- addExport DuplicateTypeOpExport op mn (exportedTypeOps exps)
269+ typeOps <- addExport TyOpName op mn (exportedTypeOps exps)
249 return $ exps { exportedTypeOps = typeOps }
270 return $ exps { exportedTypeOps = typeOps }
250
271
251-- |
272-- |
@@ -253,17 +274,19 @@ exportTypeOp exps op mn = do
253--
274--
254exportTypeClass
275exportTypeClass
255 :: MonadError MultipleErrors m
276 :: MonadError MultipleErrors m
277+ => ExportMode
256− => Exports
278+ -> Exports
257 -> ProperName 'ClassName
279 -> ProperName 'ClassName
258 -> ModuleName
280 -> ModuleName
259 -> m Exports
281 -> m Exports
260−exportTypeClass exps name mn = do
282+exportTypeClass exportMode exps name mn = do
261 let exTypes = exportedTypes exps
283 let exTypes = exportedTypes exps
284+ when (exportMode == Internal) $ do
262− when (coerceProperName name `M.member` exTypes) $
285+ when (coerceProperName name `M.member` exTypes) $
263− throwConflictError ClassConflictsWithType name
286+ throwDeclConflict (TyClassName name) (TyName (coerceProperName name))
264− when ((elem (coerceProperName name) . fst) `any` exTypes) $
287+ when ((elem (coerceProperName name) . fst) `any` exTypes) $
265− throwConflictError ClassConflictsWithCtor name
288+ throwDeclConflict (TyClassName name) (DctorName (coerceProperName name))
266− classes <- addExport DuplicateClassExport name mn (exportedTypeClasses exps)
289+ classes <- addExport TyClassName name mn (exportedTypeClasses exps)
267 return $ exps { exportedTypeClasses = classes }
290 return $ exps { exportedTypeClasses = classes }
268
291
269-- |
292-- |
@@ -276,7 +299,7 @@ exportValue
276 -> ModuleName
299 -> ModuleName
277 -> m Exports
300 -> m Exports
278exportValue exps name mn = do
301exportValue exps name mn = do
279− values <- addExport DuplicateValueExport name mn (exportedValues exps)
302+ values <- addExport IdentName name mn (exportedValues exps)
280 return $ exps { exportedValues = values }
303 return $ exps { exportedValues = values }
281
304
282-- |
305-- |
@@ -290,7 +313,7 @@ exportValueOp
290 -> ModuleName
313 -> ModuleName
291 -> m Exports
314 -> m Exports
292exportValueOp exps op mn = do
315exportValueOp exps op mn = do
293− valueOps <- addExport DuplicateValueOpExport op mn (exportedValueOps exps)
316+ valueOps <- addExport ValOpName op mn (exportedValueOps exps)
294 return $ exps { exportedValueOps = valueOps }
317 return $ exps { exportedValueOps = valueOps }
295
318
296-- |
319-- |
@@ -299,28 +322,42 @@ exportValueOp exps op mn = do
299--
322--
300addExport
323addExport
301 :: (MonadError MultipleErrors m, Ord a)
324 :: (MonadError MultipleErrors m, Ord a)
302− => (a -> SimpleErrorMessage)
325+ => (a -> Name)
303 -> a
326 -> a
304 -> ModuleName
327 -> ModuleName
305 -> M.Map a ModuleName
328 -> M.Map a ModuleName
306 -> m (M.Map a ModuleName)
329 -> m (M.Map a ModuleName)
307−addExport what name mn exports =
330+addExport toName name mn exports =
308 case M.lookup name exports of
331 case M.lookup name exports of
309 Just mn'
332 Just mn'
310 | mn == mn' -> return exports
333 | mn == mn' -> return exports
311− | otherwise -> throwConflictError what name
334+ | otherwise -> throwExportConflict mn mn' (toName name)
312 Nothing ->
335 Nothing ->
313 return $ M.insert name mn exports
336 return $ M.insert name mn exports
314
337
315-- |
338-- |
316-- Raises an error for when there is more than one definition for something.
339-- Raises an error for when there is more than one definition for something.
317--
340--
318−throwConflictError
341+throwDeclConflict
319 :: MonadError MultipleErrors m
342 :: MonadError MultipleErrors m
320− => (a -> SimpleErrorMessage)
343+ => Name
321− -> a
344+ -> Name
345+ -> m a
346+throwDeclConflict new existing =
347+ throwError . errorMessage $ DeclConflict new existing
348+
349+-- |
350+-- Raises an error for when there are conflicting names in the exports.
351+--
352+throwExportConflict
353+ :: MonadError MultipleErrors m
354+ => ModuleName
355+ -> ModuleName
356+ -> Name
322− -> m b
357+ -> m a
358+throwExportConflict new existing name =
323−throwConflictError conflict = throwError . errorMessage . conflict
359+ throwError . errorMessage $
360+ ExportConflict (Qualified (Just new) name) (Qualified (Just existing) name)
324
361
325-- |
362-- |
326-- Gets the exports for a module, or raise an error if the module doesn't exist.
363-- Gets the exports for a module, or raise an error if the module doesn't exist.
@@ -338,7 +375,7 @@ getExports env mn =
338--
375--
339checkImportConflicts
376checkImportConflicts
340 :: forall m a
377 :: forall m a
341− . (Show a, MonadError MultipleErrors m, MonadWriter MultipleErrors m, Ord a)
378+ . (MonadError MultipleErrors m, MonadWriter MultipleErrors m)
342 => ModuleName
379 => ModuleName
343 -> (a -> Name)
380 -> (a -> Name)
344 -> [ImportRecord a]
381 -> [ImportRecord a]
src/Language/PureScript/Sugar/Names/Exports.hs+20−13
@@ -31,20 +31,28 @@ findExportable (Module _ _ mn ds _) =
31 where
31 where
32 updateExports :: Exports -> Declaration -> m Exports
32 updateExports :: Exports -> Declaration -> m Exports
33 updateExports exps (TypeClassDeclaration tcn _ _ ds') = do
33 updateExports exps (TypeClassDeclaration tcn _ _ ds') = do
34− exps' <- exportTypeClass exps tcn mn
34+ exps' <- exportTypeClass Internal exps tcn mn
35 foldM go exps' ds'
35 foldM go exps' ds'
36 where
36 where
37 go exps'' (TypeDeclaration name _) = exportValue exps'' name mn
37 go exps'' (TypeDeclaration name _) = exportValue exps'' name mn
38 go exps'' (PositionedDeclaration pos _ d) = rethrowWithPosition pos $ go exps'' d
38 go exps'' (PositionedDeclaration pos _ d) = rethrowWithPosition pos $ go exps'' d
39 go _ _ = internalError "Invalid declaration in TypeClassDeclaration"
39 go _ _ = internalError "Invalid declaration in TypeClassDeclaration"
40− updateExports exps (DataDeclaration _ tn _ dcs) = exportType exps tn (map fst dcs) mn
40+ updateExports exps (DataDeclaration _ tn _ dcs) =
41+ exportType Internal exps tn (map fst dcs) mn
41− updateExports exps (TypeSynonymDeclaration tn _ _) = exportType exps tn [] mn
42+ updateExports exps (TypeSynonymDeclaration tn _ _) =
43+ exportType Internal exps tn [] mn
42− updateExports exps (ExternDataDeclaration tn _) = exportType exps tn [] mn
44+ updateExports exps (ExternDataDeclaration tn _) =
45+ exportType Internal exps tn [] mn
43− updateExports exps (ValueDeclaration name _ _ _) = exportValue exps name mn
46+ updateExports exps (ValueDeclaration name _ _ _) =
47+ exportValue exps name mn
44− updateExports exps (ValueFixityDeclaration _ _ op) = exportValueOp exps op mn
48+ updateExports exps (ValueFixityDeclaration _ _ op) =
49+ exportValueOp exps op mn
45− updateExports exps (TypeFixityDeclaration _ _ op) = exportTypeOp exps op mn
50+ updateExports exps (TypeFixityDeclaration _ _ op) =
51+ exportTypeOp exps op mn
46− updateExports exps (ExternDeclaration name _) = exportValue exps name mn
52+ updateExports exps (ExternDeclaration name _) =
53+ exportValue exps name mn
47− updateExports exps (PositionedDeclaration pos _ d) = rethrowWithPosition pos $ updateExports exps d
54+ updateExports exps (PositionedDeclaration pos _ d) =
55+ rethrowWithPosition pos $ updateExports exps d
48 updateExports exps _ = return exps
56 updateExports exps _ = return exps
49
57
50-- |
58-- |
@@ -99,9 +107,9 @@ resolveExports env ss mn imps exps refs =
99 reClasses <- extract isPseudo name TyClassName (importedTypeClasses imps)
107 reClasses <- extract isPseudo name TyClassName (importedTypeClasses imps)
100 reValues <- extract isPseudo name IdentName (importedValues imps)
108 reValues <- extract isPseudo name IdentName (importedValues imps)
101 reValueOps <- extract isPseudo name ValOpName (importedValueOps imps)
109 reValueOps <- extract isPseudo name ValOpName (importedValueOps imps)
102− foldM (\exps' ((tctor, dctors), mn') -> exportType exps' tctor dctors mn') result (resolveTypeExports reTypes reDctors)
110+ foldM (\exps' ((tctor, dctors), mn') -> exportType ReExport exps' tctor dctors mn') result (resolveTypeExports reTypes reDctors)
103 >>= flip (foldM (uncurry . exportTypeOp)) (map resolveTypeOp reTypeOps)
111 >>= flip (foldM (uncurry . exportTypeOp)) (map resolveTypeOp reTypeOps)
104− >>= flip (foldM (uncurry . exportTypeClass)) (map resolveClass reClasses)
112+ >>= flip (foldM (uncurry . exportTypeClass ReExport)) (map resolveClass reClasses)
105 >>= flip (foldM (uncurry . exportValue)) (map resolveValue reValues)
113 >>= flip (foldM (uncurry . exportValue)) (map resolveValue reValues)
106 >>= flip (foldM (uncurry . exportValueOp)) (map resolveValueOp reValueOps)
114 >>= flip (foldM (uncurry . exportValueOp)) (map resolveValueOp reValueOps)
107 elaborateModuleExports result _ = return result
115 elaborateModuleExports result _ = return result
@@ -109,8 +117,7 @@ resolveExports env ss mn imps exps refs =
109 -- Extracts a list of values for a module based on a lookup table. If the
117 -- Extracts a list of values for a module based on a lookup table. If the
110 -- boolean is true the values are filtered by the qualification
118 -- boolean is true the values are filtered by the qualification
111 extract
119 extract
112− :: (Show a, Ord a)
113− => Bool
120+ :: Bool
114 -> ModuleName
121 -> ModuleName
115 -> (a -> Name)
122 -> (a -> Name)
116 -> M.Map (Qualified a) [ImportRecord a]
123 -> M.Map (Qualified a) [ImportRecord a]
src/Language/PureScript/Sugar/Names/Imports.hs+2−1
@@ -207,6 +207,7 @@ resolveImport importModule exps imps impQual = resolveByType
207 return $ imp { importedTypeClasses = typeClasses' }
207 return $ imp { importedTypeClasses = typeClasses' }
208 importRef _ _ TypeInstanceRef{} = internalError "TypeInstanceRef in importRef"
208 importRef _ _ TypeInstanceRef{} = internalError "TypeInstanceRef in importRef"
209 importRef _ _ ModuleRef{} = internalError "ModuleRef in importRef"
209 importRef _ _ ModuleRef{} = internalError "ModuleRef in importRef"
210+ importRef _ _ ReExportRef{} = internalError "ReExportRef in importRef"
210
211
211 -- Find all exported data constructors for a given type
212 -- Find all exported data constructors for a given type
212 allExportedDataConstructors
213 allExportedDataConstructors
@@ -218,7 +219,7 @@ resolveImport importModule exps imps impQual = resolveByType
218
219
219 -- Add something to an import resolution list
220 -- Add something to an import resolution list
220 updateImports
221 updateImports
221− :: (Ord a)
222+ :: Ord a
222 => M.Map (Qualified a) [ImportRecord a]
223 => M.Map (Qualified a) [ImportRecord a]
223 -> M.Map a b
224 -> M.Map a b
224 -> (b -> ModuleName)
225 -> (b -> ModuleName)
src/Language/PureScript/TypeChecker.hs+9−8
@@ -53,7 +53,7 @@ addDataType moduleName dtype name args dctors ctorKind = do
53 addDataConstructor moduleName dtype name (map fst args) dctor tys
53 addDataConstructor moduleName dtype name (map fst args) dctor tys
54
54
55addDataConstructor
55addDataConstructor
56− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
56+ :: (MonadState CheckState m, MonadError MultipleErrors m)
57 => ModuleName
57 => ModuleName
58 -> DataDeclType
58 -> DataDeclType
59 -> ProperName 'TypeName
59 -> ProperName 'TypeName
@@ -71,7 +71,7 @@ addDataConstructor moduleName dtype name args dctor tys = do
71 putEnv $ env { dataConstructors = M.insert (Qualified (Just moduleName) dctor) (dtype, name, polyType, fields) (dataConstructors env) }
71 putEnv $ env { dataConstructors = M.insert (Qualified (Just moduleName) dctor) (dtype, name, polyType, fields) (dataConstructors env) }
72
72
73addTypeSynonym
73addTypeSynonym
74− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
74+ :: (MonadState CheckState m, MonadError MultipleErrors m)
75 => ModuleName
75 => ModuleName
76 -> ProperName 'TypeName
76 -> ProperName 'TypeName
77 -> [(String, Maybe Kind)]
77 -> [(String, Maybe Kind)]
@@ -85,7 +85,7 @@ addTypeSynonym moduleName name args ty kind = do
85 , typeSynonyms = M.insert (Qualified (Just moduleName) name) (args, ty) (typeSynonyms env) }
85 , typeSynonyms = M.insert (Qualified (Just moduleName) name) (args, ty) (typeSynonyms env) }
86
86
87valueIsNotDefined
87valueIsNotDefined
88− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
88+ :: (MonadState CheckState m, MonadError MultipleErrors m)
89 => ModuleName
89 => ModuleName
90 -> Ident
90 -> Ident
91 -> m ()
91 -> m ()
@@ -96,7 +96,7 @@ valueIsNotDefined moduleName name = do
96 Nothing -> return ()
96 Nothing -> return ()
97
97
98addValue
98addValue
99− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
99+ :: (MonadState CheckState m)
100 => ModuleName
100 => ModuleName
101 -> Ident
101 -> Ident
102 -> Type
102 -> Type
@@ -107,7 +107,7 @@ addValue moduleName name ty nameKind = do
107 putEnv (env { names = M.insert (moduleName, name) (ty, nameKind, Defined) (names env) })
107 putEnv (env { names = M.insert (moduleName, name) (ty, nameKind, Defined) (names env) })
108
108
109addTypeClass
109addTypeClass
110− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
110+ :: (MonadState CheckState m)
111 => ModuleName
111 => ModuleName
112 -> ProperName 'ClassName
112 -> ProperName 'ClassName
113 -> [(String, Maybe Kind)]
113 -> [(String, Maybe Kind)]
@@ -123,7 +123,7 @@ addTypeClass moduleName pn args implies ds =
123 toPair _ = internalError "Invalid declaration in TypeClassDeclaration"
123 toPair _ = internalError "Invalid declaration in TypeClassDeclaration"
124
124
125addTypeClassDictionaries
125addTypeClassDictionaries
126− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
126+ :: (MonadState CheckState m)
127 => Maybe ModuleName
127 => Maybe ModuleName
128 -> M.Map (Qualified (ProperName 'ClassName)) (M.Map (Qualified Ident) TypeClassDictionaryInScope)
128 -> M.Map (Qualified (ProperName 'ClassName)) (M.Map (Qualified Ident) TypeClassDictionaryInScope)
129 -> m ()
129 -> m ()
@@ -132,7 +132,7 @@ addTypeClassDictionaries mn entries =
132 where insertState st = M.insertWith (M.unionWith M.union) mn entries (typeClassDictionaries . checkEnv $ st)
132 where insertState st = M.insertWith (M.unionWith M.union) mn entries (typeClassDictionaries . checkEnv $ st)
133
133
134checkDuplicateTypeArguments
134checkDuplicateTypeArguments
135− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
135+ :: (MonadState CheckState m, MonadError MultipleErrors m)
136 => [String]
136 => [String]
137 -> m ()
137 -> m ()
138checkDuplicateTypeArguments args = for_ firstDup $ \dup ->
138checkDuplicateTypeArguments args = for_ firstDup $ \dup ->
@@ -147,6 +147,7 @@ checkTypeClassInstance
147 -> Type
147 -> Type
148 -> m ()
148 -> m ()
149checkTypeClassInstance _ (TypeVar _) = return ()
149checkTypeClassInstance _ (TypeVar _) = return ()
150+checkTypeClassInstance _ (TypeLevelString _) = return ()
150checkTypeClassInstance _ (TypeConstructor ctor) = do
151checkTypeClassInstance _ (TypeConstructor ctor) = do
151 env <- getEnv
152 env <- getEnv
152 when (ctor `M.member` typeSynonyms env) . throwError . errorMessage $ TypeSynonymInstance
153 when (ctor `M.member` typeSynonyms env) . throwError . errorMessage $ TypeSynonymInstance
@@ -158,7 +159,7 @@ checkTypeClassInstance _ ty = throwError . errorMessage $ InvalidInstanceHead ty
158-- Check that type synonyms are fully-applied in a type
159-- Check that type synonyms are fully-applied in a type
159--
160--
160checkTypeSynonyms
161checkTypeSynonyms
161− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
162+ :: (MonadState CheckState m, MonadError MultipleErrors m)
162 => Type
163 => Type
163 -> m ()
164 -> m ()
164checkTypeSynonyms = void . replaceAllTypeSynonyms
165checkTypeSynonyms = void . replaceAllTypeSynonyms
src/Language/PureScript/TypeChecker/Entailment.hs+1
@@ -184,6 +184,7 @@ typeHeadsAreEqual _ (TUnknown u1) (TUnknown u2) | u1 == u2 = Just
184typeHeadsAreEqual _ (Skolem _ s1 _ _) (Skolem _ s2 _ _) | s1 == s2 = Just []
184typeHeadsAreEqual _ (Skolem _ s1 _ _) (Skolem _ s2 _ _) | s1 == s2 = Just []
185typeHeadsAreEqual _ t (TypeVar v) = Just [(v, t)]
185typeHeadsAreEqual _ t (TypeVar v) = Just [(v, t)]
186typeHeadsAreEqual _ (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = Just []
186typeHeadsAreEqual _ (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = Just []
187+typeHeadsAreEqual _ (TypeLevelString s1) (TypeLevelString s2) | s1 == s2 = Just []
187typeHeadsAreEqual m (TypeApp h1 t1) (TypeApp h2 t2) = (++) <$> typeHeadsAreEqual m h1 h2
188typeHeadsAreEqual m (TypeApp h1 t1) (TypeApp h2 t2) = (++) <$> typeHeadsAreEqual m h1 h2
188 <*> typeHeadsAreEqual m t1 t2
189 <*> typeHeadsAreEqual m t1 t2
189typeHeadsAreEqual _ REmpty REmpty = Just []
190typeHeadsAreEqual _ REmpty REmpty = Just []
src/Language/PureScript/TypeChecker/Kinds.hs+2
@@ -87,6 +87,7 @@ unifyKinds k1 k2 = do
87 go k (KUnknown u) = solveKind u k
87 go k (KUnknown u) = solveKind u k
88 go Star Star = return ()
88 go Star Star = return ()
89 go Bang Bang = return ()
89 go Bang Bang = return ()
90+ go Symbol Symbol = return ()
90 go (Row k1') (Row k2') = go k1' k2'
91 go (Row k1') (Row k2') = go k1' k2'
91 go (FunKind k1' k2') (FunKind k3 k4) = do
92 go (FunKind k1' k2') (FunKind k3 k4) = do
92 go k1' k3
93 go k1' k3
@@ -230,6 +231,7 @@ infer' other = (, []) <$> go other
230 unifyKinds k k'
231 unifyKinds k k'
231 return k'
232 return k'
232 go TypeWildcard{} = freshKind
233 go TypeWildcard{} = freshKind
234+ go (TypeLevelString _) = return Symbol
233 go (TypeVar v) = do
235 go (TypeVar v) = do
234 Just moduleName <- checkCurrentModule <$> get
236 Just moduleName <- checkCurrentModule <$> get
235 lookupTypeVariable moduleName (Qualified Nothing (ProperName v))
237 lookupTypeVariable moduleName (Qualified Nothing (ProperName v))
src/Language/PureScript/TypeChecker/Rows.hs+1−3
@@ -9,17 +9,15 @@ import Prelude.Compat
9
9
10import Control.Monad
10import Control.Monad
11import Control.Monad.Error.Class (MonadError(..))
11import Control.Monad.Error.Class (MonadError(..))
12−import Control.Monad.State.Class (MonadState(..))
13
12
14import Data.List
13import Data.List
15
14
16import Language.PureScript.AST
15import Language.PureScript.AST
17import Language.PureScript.Errors
16import Language.PureScript.Errors
18−import Language.PureScript.TypeChecker.Monad
19import Language.PureScript.Types
17import Language.PureScript.Types
20
18
21-- | Ensure rows do not contain duplicate labels
19-- | Ensure rows do not contain duplicate labels
22−checkDuplicateLabels :: forall m. (MonadError MultipleErrors m, MonadState CheckState m) => Expr -> m ()
20+checkDuplicateLabels :: forall m. (MonadError MultipleErrors m) => Expr -> m ()
23checkDuplicateLabels =
21checkDuplicateLabels =
24 let (_, f, _) = everywhereOnValuesM def go def
22 let (_, f, _) = everywhereOnValuesM def go def
25 in void . f
23 in void . f
src/Language/PureScript/TypeChecker/Skolems.hs+1−1
@@ -89,7 +89,7 @@ skolemizeTypesInValue ident sko scope ss =
89-- |
89-- |
90-- Ensure skolem variables do not escape their scope
90-- Ensure skolem variables do not escape their scope
91--
91--
92−skolemEscapeCheck :: (MonadError MultipleErrors m, MonadState CheckState m) => Expr -> m ()
92+skolemEscapeCheck :: (MonadError MultipleErrors m) => Expr -> m ()
93skolemEscapeCheck (TypedValue False _ _) = return ()
93skolemEscapeCheck (TypedValue False _ _) = return ()
94skolemEscapeCheck root@TypedValue{} =
94skolemEscapeCheck root@TypedValue{} =
95 -- Every skolem variable is created when a ForAll type is skolemized.
95 -- Every skolem variable is created when a ForAll type is skolemized.
src/Language/PureScript/TypeChecker/Types.hs+2−2
@@ -133,7 +133,7 @@ type TypeData = M.Map (ModuleName, Ident) (Type, NameKind, NameVisibility)
133type UntypedData = [(Ident, Type)]
133type UntypedData = [(Ident, Type)]
134
134
135typeDictionaryForBindingGroup ::
135typeDictionaryForBindingGroup ::
136− (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
136+ (MonadState CheckState m) =>
137 ModuleName ->
137 ModuleName ->
138 [(Ident, Expr)] ->
138 [(Ident, Expr)] ->
139 m ([(Ident, Expr)], [(Ident, (Expr, Type, Bool))], TypeData, UntypedData)
139 m ([(Ident, Expr)], [(Ident, (Expr, Type, Bool))], TypeData, UntypedData)
@@ -206,7 +206,7 @@ overTypes f = let (_, f', _) = everywhereOnValues id g id in f'
206
206
207-- | Check the kind of a type, failing if it is not of kind *.
207-- | Check the kind of a type, failing if it is not of kind *.
208checkTypeKind ::
208checkTypeKind ::
209− (MonadState CheckState m, MonadError MultipleErrors m) =>
209+ (MonadError MultipleErrors m) =>
210 Type ->
210 Type ->
211 Kind ->
211 Kind ->
212 m ()
212 m ()
src/Language/PureScript/TypeChecker/Unify.hs+8−7
@@ -153,13 +153,14 @@ unifyRows r1 r2 =
153-- Check that two types unify
153-- Check that two types unify
154--
154--
155unifiesWith :: Type -> Type -> Bool
155unifiesWith :: Type -> Type -> Bool
156−unifiesWith (TUnknown u1) (TUnknown u2) | u1 == u2 = True
156+unifiesWith (TUnknown u1) (TUnknown u2) = u1 == u2
157−unifiesWith (Skolem _ s1 _ _) (Skolem _ s2 _ _) | s1 == s2 = True
157+unifiesWith (Skolem _ s1 _ _) (Skolem _ s2 _ _) = s1 == s2
158−unifiesWith (TypeVar v1) (TypeVar v2) | v1 == v2 = True
158+unifiesWith (TypeVar v1) (TypeVar v2) = v1 == v2
159+unifiesWith (TypeLevelString s1) (TypeLevelString s2) = s1 == s2
159−unifiesWith (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = True
160+unifiesWith (TypeConstructor c1) (TypeConstructor c2) = c1 == c2
160−unifiesWith (TypeApp h1 t1) (TypeApp h2 t2) = h1 `unifiesWith` h2 && t1 `unifiesWith` t2
161+unifiesWith (TypeApp h1 t1) (TypeApp h2 t2) = h1 `unifiesWith` h2 && t1 `unifiesWith` t2
161−unifiesWith REmpty REmpty = True
162+unifiesWith REmpty REmpty = True
162−unifiesWith r1@RCons{} r2@RCons{} =
163+unifiesWith r1@RCons{} r2@RCons{} =
163 let (s1, r1') = rowToList r1
164 let (s1, r1') = rowToList r1
164 (s2, r2') = rowToList r2
165 (s2, r2') = rowToList r2
165
166
src/Language/PureScript/Types.hs+19−51
@@ -29,79 +29,47 @@ newtype SkolemScope = SkolemScope { runSkolemScope :: Int }
29-- The type of types
29-- The type of types
30--
30--
31data Type
31data Type
32− -- |
33− -- A unification variable of type Type
32+ -- | A unification variable of type Type
34− --
35 = TUnknown Int
33 = TUnknown Int
36− -- |
37− -- A named type variable
34+ -- | A named type variable
38− --
39 | TypeVar String
35 | TypeVar String
40− -- |
36+ -- | A type-level string
37+ | TypeLevelString String
41− -- A type wildcard, as would appear in a partial type synonym
38+ -- | A type wildcard, as would appear in a partial type synonym
42− --
43 | TypeWildcard SourceSpan
39 | TypeWildcard SourceSpan
44− -- |
45− -- A type constructor
40+ -- | A type constructor
46− --
47 | TypeConstructor (Qualified (ProperName 'TypeName))
41 | TypeConstructor (Qualified (ProperName 'TypeName))
48− -- |
49− -- A type operator. This will be desugared into a type constructor during the
42+ -- | A type operator. This will be desugared into a type constructor during the
50 -- "operators" phase of desugaring.
43 -- "operators" phase of desugaring.
51− --
52 | TypeOp (Qualified (OpName 'TypeOpName))
44 | TypeOp (Qualified (OpName 'TypeOpName))
53− -- |
54− -- A type application
45+ -- | A type application
55− --
56 | TypeApp Type Type
46 | TypeApp Type Type
57− -- |
58− -- Forall quantifier
47+ -- | Forall quantifier
59− --
60 | ForAll String Type (Maybe SkolemScope)
48 | ForAll String Type (Maybe SkolemScope)
61− -- |
62− -- A type with a set of type class constraints
49+ -- | A type with a set of type class constraints
63− --
64 | ConstrainedType [Constraint] Type
50 | ConstrainedType [Constraint] Type
65− -- |
66− -- A skolem constant
51+ -- | A skolem constant
67− --
68 | Skolem String Int SkolemScope (Maybe SourceSpan)
52 | Skolem String Int SkolemScope (Maybe SourceSpan)
69− -- |
70− -- An empty row
53+ -- | An empty row
71− --
72 | REmpty
54 | REmpty
73− -- |
74− -- A non-empty row
55+ -- | A non-empty row
75− --
76 | RCons String Type Type
56 | RCons String Type Type
77− -- |
78− -- A type with a kind annotation
57+ -- | A type with a kind annotation
79− --
80 | KindedType Type Kind
58 | KindedType Type Kind
81− -- |
82− -- A placeholder used in pretty printing
59+ -- | A placeholder used in pretty printing
83− --
84 | PrettyPrintFunction Type Type
60 | PrettyPrintFunction Type Type
85− -- |
86− -- A placeholder used in pretty printing
61+ -- | A placeholder used in pretty printing
87− --
88 | PrettyPrintObject Type
62 | PrettyPrintObject Type
89− -- |
90− -- A placeholder used in pretty printing
63+ -- | A placeholder used in pretty printing
91− --
92 | PrettyPrintForAll [String] Type
64 | PrettyPrintForAll [String] Type
93− -- |
94− -- Binary operator application. During the rebracketing phase of desugaring,
65+ -- | Binary operator application. During the rebracketing phase of desugaring,
95 -- this data constructor will be removed.
66 -- this data constructor will be removed.
96− --
97 | BinaryNoParensType Type Type Type
67 | BinaryNoParensType Type Type Type
98− -- |
99− -- Explicit parentheses. During the rebracketing phase of desugaring, this
68+ -- | Explicit parentheses. During the rebracketing phase of desugaring, this
100 -- data constructor will be removed.
69 -- data constructor will be removed.
101 --
70 --
102 -- Note: although it seems this constructor is not used, it _is_ useful,
71 -- Note: although it seems this constructor is not used, it _is_ useful,
103 -- since it prevents certain traversals from matching.
72 -- since it prevents certain traversals from matching.
104− --
105 | ParensInType Type
73 | ParensInType Type
106 deriving (Show, Read, Eq, Ord)
74 deriving (Show, Read, Eq, Ord)
107
75
stack-ghc-8.0.yamlnew file+7
@@ -0,0 +1,7 @@
1+resolver: nightly-2016-05-29
2+packages:
3+- '.'
4+extra-deps:
5+- pipes-http-1.0.2
6+- wai-websockets-3.0.0.9
7+- websockets-0.9.6.2
stack.yaml+2−5
@@ -1,8 +1,5 @@
1−resolver: lts-5.4
1+resolver: lts-6.1
2packages:
2packages:
3- '.'
3- '.'
4−extra-deps:
4+extra-deps: []
5−- bower-json-0.8.0
6−- language-javascript-0.6.0.4
7−- parsec-3.1.11
8flags: {}
5flags: {}
tests/Language/PureScript/Ide/FilterSpec.hs+21−32
@@ -1,32 +1,31 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
2module Language.PureScript.Ide.FilterSpec where
3module Language.PureScript.Ide.FilterSpec where
3
4
4−import Data.Text (Text)
5+import Protolude
5import Language.PureScript.Ide.Filter
6import Language.PureScript.Ide.Filter
6import Language.PureScript.Ide.Types
7import Language.PureScript.Ide.Types
7import qualified Language.PureScript as P
8import qualified Language.PureScript as P
8import Test.Hspec
9import Test.Hspec
9
10
10−value :: Text -> ExternDecl
11+value :: Text -> IdeDeclarationAnn
11−value s = ValueDeclaration s $ P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
12+value s = IdeDeclarationAnn emptyAnn (IdeValue (P.Ident (toS s)) P.REmpty)
13+
14+moduleA, moduleB :: Module
15+moduleA = (P.moduleNameFromString "Module.A", [value "function1"])
16+moduleB = (P.moduleNameFromString "Module.B", [value "data1"])
12
17
13modules :: [Module]
18modules :: [Module]
14−modules =
19+modules = [moduleA, moduleB]
15− [
16− ("Module.A", [value "function1"]),
17− ("Module.B", [value "data1"]),
18− ("Module.C", [ModuleDecl "Module.C" []]),
19− ("Module.D", [Dependency "Module.C" [] Nothing, value "asd"])
20− ]
21
20
22runEq :: Text -> [Module]
21runEq :: Text -> [Module]
23−runEq s = runFilter (equalityFilter s) modules
22+runEq s = applyFilters [equalityFilter s] modules
23+
24runPrefix :: Text -> [Module]
24runPrefix :: Text -> [Module]
25−runPrefix s = runFilter (prefixFilter s) modules
25+runPrefix s = applyFilters [prefixFilter s] modules
26+
26−runModule :: [ModuleIdent] -> [Module]
27+runModule :: [P.ModuleName] -> [Module]
27−runModule ms = runFilter (moduleFilter ms) modules
28+runModule ms = applyFilters [moduleFilter ms] modules
28−runDependency :: [ModuleIdent] -> [Module]
29−runDependency ms = runFilter (dependencyFilter ms) modules
30
29
31spec :: Spec
30spec :: Spec
32spec = do
31spec = do
@@ -34,30 +33,20 @@ spec = do
34 it "removes empty modules" $
33 it "removes empty modules" $
35 runEq "test" `shouldBe` []
34 runEq "test" `shouldBe` []
36 it "keeps function declarations that are equal" $
35 it "keeps function declarations that are equal" $
37− runEq "function1" `shouldBe` [head modules]
36+ runEq "function1" `shouldBe` [moduleA]
38− -- TODO: It would be more sensible to match Constructors
39 it "keeps data declarations that are equal" $
37 it "keeps data declarations that are equal" $
40− runEq "data1" `shouldBe` [modules !! 1]
38+ runEq "data1" `shouldBe` [moduleB]
41 describe "prefixFilter" $ do
39 describe "prefixFilter" $ do
42 it "keeps everything on empty string" $
40 it "keeps everything on empty string" $
43 runPrefix "" `shouldBe` modules
41 runPrefix "" `shouldBe` modules
44 it "keeps functionname prefix matches" $
42 it "keeps functionname prefix matches" $
45− runPrefix "fun" `shouldBe` [head modules]
43+ runPrefix "fun" `shouldBe` [moduleA]
46 it "keeps data decls prefix matches" $
44 it "keeps data decls prefix matches" $
47− runPrefix "dat" `shouldBe` [modules !! 1]
45+ runPrefix "dat" `shouldBe` [moduleB]
48− it "keeps module decl prefix matches" $
49− runPrefix "Mod" `shouldBe` [modules !! 2]
50 describe "moduleFilter" $ do
46 describe "moduleFilter" $ do
51 it "removes everything on empty input" $
47 it "removes everything on empty input" $
52 runModule [] `shouldBe` []
48 runModule [] `shouldBe` []
53 it "only keeps the specified modules" $
49 it "only keeps the specified modules" $
54− runModule ["Module.A", "Module.C"] `shouldBe` [head modules, modules !! 2]
50+ runModule [P.moduleNameFromString "Module.A"] `shouldBe` [moduleA]
55 it "ignores modules that are not in scope" $
51 it "ignores modules that are not in scope" $
56− runModule ["Module.A", "Module.C", "Unknown"] `shouldBe` [head modules, modules !! 2]
52+ runModule (P.moduleNameFromString <$> ["Module.A", "Unknown"]) `shouldBe` [moduleA]
57− describe "dependencyFilter" $ do
58− it "removes everything on empty input" $
59− runDependency [] `shouldBe` []
60− it "only keeps the specified modules if they have no imports" $
61− runDependency ["Module.A", "Module.B"] `shouldBe` [head modules, modules !! 1]
62− it "keeps the specified modules and their imports" $
63− runDependency ["Module.A", "Module.D"] `shouldBe` [head modules, modules !! 2, modules !! 3]
tests/Language/PureScript/Ide/Imports/IntegrationSpec.hs+14−25
@@ -1,8 +1,10 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
2module Language.PureScript.Ide.Imports.IntegrationSpec where
3module Language.PureScript.Ide.Imports.IntegrationSpec where
3
4
4−import Control.Monad (void)
5+
5−import Data.Text (Text)
6+import Protolude
7+
6import qualified Data.Text as T
8import qualified Data.Text as T
7import qualified Data.Text.IO as TIO
9import qualified Data.Text.IO as TIO
8import qualified Language.PureScript.Ide.Integration as Integration
10import qualified Language.PureScript.Ide.Integration as Integration
@@ -12,9 +14,7 @@ import System.Directory
12import System.FilePath
14import System.FilePath
13
15
14setup :: IO ()
16setup :: IO ()
15−setup = do
16− Integration.reset
17+setup = void (Integration.reset *> Integration.loadAll)
17− mapM_ Integration.loadModuleWithDeps ["ImportsSpec", "ImportsSpec1"]
18
18
19withSupportFiles :: (FilePath -> FilePath -> IO a) -> IO ()
19withSupportFiles :: (FilePath -> FilePath -> IO a) -> IO ()
20withSupportFiles test = do
20withSupportFiles test = do
@@ -35,52 +35,41 @@ spec = beforeAll_ setup . describe "Adding imports" $ do
35 let
35 let
36 sourceFileSkeleton :: [Text] -> [Text]
36 sourceFileSkeleton :: [Text] -> [Text]
37 sourceFileSkeleton importSection =
37 sourceFileSkeleton importSection =
38− [ "module ImportsSpec where" , ""] ++ importSection ++ [ "" , "myId = id"]
38+ [ "module ImportsSpec where" , ""] ++ importSection ++ [ "" , "myId x = x"]
39 it "adds an implicit import" $ do
39 it "adds an implicit import" $ do
40 withSupportFiles (Integration.addImplicitImport "ImportsSpec1")
40 withSupportFiles (Integration.addImplicitImport "ImportsSpec1")
41 outputFileShouldBe (sourceFileSkeleton
41 outputFileShouldBe (sourceFileSkeleton
42 [ "import ImportsSpec1"
42 [ "import ImportsSpec1"
43− , "import Main (id)"
44 ])
43 ])
45 it "adds an explicit unqualified import" $ do
44 it "adds an explicit unqualified import" $ do
46 withSupportFiles (Integration.addImport "exportedFunction")
45 withSupportFiles (Integration.addImport "exportedFunction")
47 outputFileShouldBe (sourceFileSkeleton
46 outputFileShouldBe (sourceFileSkeleton
48 [ "import ImportsSpec1 (exportedFunction)"
47 [ "import ImportsSpec1 (exportedFunction)"
49− , "import Main (id)"
50 ])
48 ])
51 it "adds an explicit unqualified import (type)" $ do
49 it "adds an explicit unqualified import (type)" $ do
52 withSupportFiles (Integration.addImport "MyType")
50 withSupportFiles (Integration.addImport "MyType")
53− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (MyType)"
51+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyType)"])
54− , "import Main (id)"
55− ])
56 it "adds an explicit unqualified import (parameterized type)" $ do
52 it "adds an explicit unqualified import (parameterized type)" $ do
57 withSupportFiles (Integration.addImport "MyParamType")
53 withSupportFiles (Integration.addImport "MyParamType")
58− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (MyParamType)"
54+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyParamType)"])
59− , "import Main (id)"
60− ])
61 it "adds an explicit unqualified import (typeclass)" $ do
55 it "adds an explicit unqualified import (typeclass)" $ do
62 withSupportFiles (Integration.addImport "ATypeClass")
56 withSupportFiles (Integration.addImport "ATypeClass")
63− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (class ATypeClass)"
57+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (class ATypeClass)"])
64− , "import Main (id)"])
65 it "adds an explicit unqualified import (dataconstructor)" $ do
58 it "adds an explicit unqualified import (dataconstructor)" $ do
66 withSupportFiles (Integration.addImport "MyJust")
59 withSupportFiles (Integration.addImport "MyJust")
67− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (MyMaybe(MyJust))"
60+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyMaybe(MyJust))"])
68− , "import Main (id)"])
69 it "adds an explicit unqualified import (newtype)" $ do
61 it "adds an explicit unqualified import (newtype)" $ do
70 withSupportFiles (Integration.addImport "MyNewtype")
62 withSupportFiles (Integration.addImport "MyNewtype")
71− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (MyNewtype(MyNewtype))"
63+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyNewtype(MyNewtype))"])
72− , "import Main (id)"])
73 it "adds an explicit unqualified import (typeclass member function)" $ do
64 it "adds an explicit unqualified import (typeclass member function)" $ do
74 withSupportFiles (Integration.addImport "typeClassFun")
65 withSupportFiles (Integration.addImport "typeClassFun")
75− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (typeClassFun)"
66+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (typeClassFun)"])
76− , "import Main (id)"])
77 it "doesn't add a newtypes constructor if only the type is exported" $ do
67 it "doesn't add a newtypes constructor if only the type is exported" $ do
78 withSupportFiles (Integration.addImport "OnlyTypeExported")
68 withSupportFiles (Integration.addImport "OnlyTypeExported")
79− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (OnlyTypeExported)"
69+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (OnlyTypeExported)"])
80− , "import Main (id)"])
81 it "doesn't add an import if the identifier is defined in the module itself" $ do
70 it "doesn't add an import if the identifier is defined in the module itself" $ do
82 withSupportFiles (Integration.addImport "myId")
71 withSupportFiles (Integration.addImport "myId")
83− outputFileShouldBe (sourceFileSkeleton [ "import Main (id)"])
72+ outputFileShouldBe (sourceFileSkeleton [])
84 it "responds with an error if it's undecidable whether we want a type or constructor" $
73 it "responds with an error if it's undecidable whether we want a type or constructor" $
85 withSupportFiles (\sourceFp outFp -> do
74 withSupportFiles (\sourceFp outFp -> do
86 r <- Integration.addImport "SpecialCase" sourceFp outFp
75 r <- Integration.addImport "SpecialCase" sourceFp outFp
tests/Language/PureScript/Ide/ImportsSpec.hs+9−9
@@ -1,8 +1,10 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
2module Language.PureScript.Ide.ImportsSpec where
3module Language.PureScript.Ide.ImportsSpec where
3
4
4−import Data.Maybe (fromJust)
5+import Protolude
5−import Data.Text (Text)
6+import Unsafe (fromJust)
7+
6import qualified Language.PureScript as P
8import qualified Language.PureScript as P
7import Language.PureScript.Ide.Imports
9import Language.PureScript.Ide.Imports
8import Language.PureScript.Ide.Types
10import Language.PureScript.Ide.Types
@@ -17,11 +19,9 @@ simpleFile =
17 ]
19 ]
18
20
19splitSimpleFile :: (P.ModuleName, [Text], [Import], [Text])
21splitSimpleFile :: (P.ModuleName, [Text], [Import], [Text])
20−splitSimpleFile = fromRight $ sliceImportSection simpleFile
22+splitSimpleFile = fromRight (sliceImportSection simpleFile)
21 where
23 where
22− fromRight (Right r) = r
24+ fromRight = fromJust . rightToMaybe
23− fromRight (Left _) = error "fromRight"
24−
25withImports :: [Text] -> [Text]
25withImports :: [Text] -> [Text]
26withImports is =
26withImports is =
27 take 2 simpleFile ++ is ++ drop 2 simpleFile
27 take 2 simpleFile ++ is ++ drop 2 simpleFile
@@ -68,11 +68,11 @@ spec = do
68 describe "import commands" $ do
68 describe "import commands" $ do
69 let simpleFileImports = let (_, _, i, _) = splitSimpleFile in i
69 let simpleFileImports = let (_, _, i, _) = splitSimpleFile in i
70 addValueImport i mn is =
70 addValueImport i mn is =
71− prettyPrintImportSection (addExplicitImport' (ValueDeclaration i wildcard) mn is)
71+ prettyPrintImportSection (addExplicitImport' (IdeValue (P.Ident i) wildcard) mn is)
72 addOpImport op mn is =
72 addOpImport op mn is =
73− prettyPrintImportSection (addExplicitImport' (ValueOperator op "" 2 P.Infix) mn is)
73+ prettyPrintImportSection (addExplicitImport' (IdeValueOperator op "" 2 P.Infix) mn is)
74 addDtorImport i t mn is =
74 addDtorImport i t mn is =
75− prettyPrintImportSection (addExplicitImport' (DataConstructor i t wildcard) mn is)
75+ prettyPrintImportSection (addExplicitImport' (IdeDataConstructor (P.ProperName i) t wildcard) mn is)
76 it "adds an implicit unqualified import" $
76 it "adds an implicit unqualified import" $
77 shouldBe
77 shouldBe
78 (addImplicitImport' simpleFileImports (P.moduleNameFromString "Data.Map"))
78 (addImplicitImport' simpleFileImports (P.moduleNameFromString "Data.Map"))
tests/Language/PureScript/Ide/Integration.hs+73−77
@@ -14,6 +14,7 @@
14
14
15{-# LANGUAGE OverloadedStrings #-}
15{-# LANGUAGE OverloadedStrings #-}
16{-# LANGUAGE ScopedTypeVariables #-}
16{-# LANGUAGE ScopedTypeVariables #-}
17+{-# LANGUAGE NoImplicitPrelude #-}
17module Language.PureScript.Ide.Integration
18module Language.PureScript.Ide.Integration
18 (
19 (
19 -- managing the server process
20 -- managing the server process
@@ -29,33 +30,33 @@ module Language.PureScript.Ide.Integration
29 -- sending commands
30 -- sending commands
30 , addImport
31 , addImport
31 , addImplicitImport
32 , addImplicitImport
33+ , loadAll
32 , loadModule
34 , loadModule
33− , loadModuleWithDeps
35+ , loadModules
34 , getCwd
36 , getCwd
35 , getFlexCompletions
37 , getFlexCompletions
36 , getFlexCompletionsInModule
38 , getFlexCompletionsInModule
37 , getType
39 , getType
40+ , getInfo
38 , rebuildModule
41 , rebuildModule
39 , reset
42 , reset
40 -- checking results
43 -- checking results
41 , resultIsSuccess
44 , resultIsSuccess
42 , parseCompletions
45 , parseCompletions
46+ , parseInfo
43 , parseTextResult
47 , parseTextResult
44 ) where
48 ) where
45
49
46−import Control.Concurrent (threadDelay)
50+import Protolude
47−import Control.Exception
51+import Unsafe (fromJust)
48−import Control.Monad (join, when)
52+
49import Data.Aeson
53import Data.Aeson
50import Data.Aeson.Types
54import Data.Aeson.Types
51−import qualified Data.ByteString.Lazy.UTF8 as BSL
52−import Data.Either (isRight)
53−import Data.Maybe (fromJust, isNothing, fromMaybe)
54import qualified Data.Text as T
55import qualified Data.Text as T
55import qualified Data.Vector as V
56import qualified Data.Vector as V
56import Language.PureScript.Ide.Util
57import Language.PureScript.Ide.Util
58+import qualified Language.PureScript as P
57import System.Directory
59import System.Directory
58−import System.Exit
59import System.FilePath
60import System.FilePath
60import System.IO.Error (mkIOError, userErrorType)
61import System.IO.Error (mkIOError, userErrorType)
61import System.Process
62import System.Process
@@ -70,8 +71,8 @@ startServer = do
70 pdir <- projectDirectory
71 pdir <- projectDirectory
71 -- Turn off filewatching since it creates race condition in a testing environment
72 -- Turn off filewatching since it creates race condition in a testing environment
72 (_, _, _, procHandle) <- createProcess $
73 (_, _, _, procHandle) <- createProcess $
73− (shell "psc-ide-server --no-watch") {cwd = Just pdir}
74+ (shell "psc-ide-server --no-watch src/*.purs") {cwd = Just pdir}
74− threadDelay 500000 -- give the server 500ms to start up
75+ threadDelay 2000000 -- give the server 2s to start up
75 return procHandle
76 return procHandle
76
77
77stopServer :: ProcessHandle -> IO ()
78stopServer :: ProcessHandle -> IO ()
@@ -80,26 +81,20 @@ stopServer = terminateProcess
80withServer :: IO a -> IO a
81withServer :: IO a -> IO a
81withServer s = do
82withServer s = do
82 _ <- startServer
83 _ <- startServer
83− started <- tryNTimes 5 (shush <$> (try getCwd :: IO (Either SomeException String)))
84+ started <- tryNTimes 5 (rightToMaybe <$> (try getCwd :: IO (Either SomeException Text)))
84 when (isNothing started) $
85 when (isNothing started) $
85 throwIO (mkIOError userErrorType "psc-ide-server didn't start in time" Nothing Nothing)
86 throwIO (mkIOError userErrorType "psc-ide-server didn't start in time" Nothing Nothing)
86 r <- s
87 r <- s
87 quitServer
88 quitServer
88 pure r
89 pure r
89
90
90−shush :: Either a b -> Maybe b
91−shush = either (const Nothing) Just
92−
93-- project management utils
91-- project management utils
94
92
95compileTestProject :: IO Bool
93compileTestProject :: IO Bool
96compileTestProject = do
94compileTestProject = do
97 pdir <- projectDirectory
95 pdir <- projectDirectory
98 (_, _, _, procHandle) <- createProcess $
96 (_, _, _, procHandle) <- createProcess $
99− (shell $ "psc " ++ fileGlob) { cwd = Just pdir
97+ (shell . toS $ "psc " <> fileGlob) { cwd = Just pdir }
100− , std_out = CreatePipe
101− , std_err = CreatePipe
102− }
103 r <- tryNTimes 5 (getProcessExitCode procHandle)
98 r <- tryNTimes 5 (getProcessExitCode procHandle)
104 pure (fromMaybe False (isSuccess <$> r))
99 pure (fromMaybe False (isSuccess <$> r))
105
100
@@ -121,24 +116,17 @@ deleteOutputFolder = do
121deleteFileIfExists :: FilePath -> IO ()
116deleteFileIfExists :: FilePath -> IO ()
122deleteFileIfExists fp = whenM (doesFileExist fp) (removeFile fp)
117deleteFileIfExists fp = whenM (doesFileExist fp) (removeFile fp)
123
118
124−whenM :: Monad m => m Bool -> m () -> m ()
125−whenM p f = do
126− x <- p
127− when x f
128−
129isSuccess :: ExitCode -> Bool
119isSuccess :: ExitCode -> Bool
130isSuccess ExitSuccess = True
120isSuccess ExitSuccess = True
131isSuccess (ExitFailure _) = False
121isSuccess (ExitFailure _) = False
132
122
133−fileGlob :: String
123+fileGlob :: Text
134−fileGlob = unwords
135− [ "\"src/**/*.purs\""
124+fileGlob = "\"src/**/*.purs\""
136− ]
137
125
138-- Integration Testing API
126-- Integration Testing API
139
127
140−sendCommand :: Value -> IO String
128+sendCommand :: Value -> IO Text
141−sendCommand v = readCreateProcess
129+sendCommand v = toS <$> readCreateProcess
142 ((shell "psc-ide-client") { std_out=CreatePipe
130 ((shell "psc-ide-client") { std_out=CreatePipe
143 , std_err=CreatePipe
131 , std_err=CreatePipe
144 })
132 })
@@ -146,65 +134,71 @@ sendCommand v = readCreateProcess
146
134
147quitServer :: IO ()
135quitServer :: IO ()
148quitServer = do
136quitServer = do
149− let quitCommand = object ["command" .= ("quit" :: String)]
137+ let quitCommand = object ["command" .= ("quit" :: Text)]
150− _ <- try $ sendCommand quitCommand :: IO (Either SomeException String)
138+ _ <- try $ sendCommand quitCommand :: IO (Either SomeException Text)
151 return ()
139 return ()
152
140
153reset :: IO ()
141reset :: IO ()
154reset = do
142reset = do
155− let resetCommand = object ["command" .= ("reset" :: String)]
143+ let resetCommand = object ["command" .= ("reset" :: Text)]
156− _ <- try $ sendCommand resetCommand :: IO (Either SomeException String)
144+ _ <- try $ sendCommand resetCommand :: IO (Either SomeException Text)
157 return ()
145 return ()
158
146
159−getCwd :: IO String
147+getCwd :: IO Text
160getCwd = do
148getCwd = do
161− let cwdCommand = object ["command" .= ("cwd" :: String)]
149+ let cwdCommand = object ["command" .= ("cwd" :: Text)]
162 sendCommand cwdCommand
150 sendCommand cwdCommand
163
151
164−loadModuleWithDeps :: String -> IO String
152+loadModule :: Text -> IO Text
153+loadModule m = loadModules [m]
154+
155+loadModules :: [Text] -> IO Text
165−loadModuleWithDeps m = sendCommand $ load [] [m]
156+loadModules = sendCommand . load
166
157
167−loadModule :: String -> IO String
158+loadAll :: IO Text
168−loadModule m = sendCommand $ load [m] []
159+loadAll = sendCommand (load [])
169
160
170−getFlexCompletions :: String -> IO [(String, String, String)]
161+getFlexCompletions :: Text -> IO [(Text, Text, Text)]
171getFlexCompletions q = parseCompletions <$> sendCommand (completion [] (Just (flexMatcher q)) Nothing)
162getFlexCompletions q = parseCompletions <$> sendCommand (completion [] (Just (flexMatcher q)) Nothing)
172
163
173−getFlexCompletionsInModule :: String -> String -> IO [(String, String, String)]
164+getFlexCompletionsInModule :: Text -> Text -> IO [(Text, Text, Text)]
174getFlexCompletionsInModule q m = parseCompletions <$> sendCommand (completion [] (Just (flexMatcher q)) (Just m))
165getFlexCompletionsInModule q m = parseCompletions <$> sendCommand (completion [] (Just (flexMatcher q)) (Just m))
175
166
176−getType :: String -> IO [(String, String, String)]
167+getType :: Text -> IO [(Text, Text, Text)]
177getType q = parseCompletions <$> sendCommand (typeC q [])
168getType q = parseCompletions <$> sendCommand (typeC q [])
178
169
170+getInfo :: Text -> IO [P.SourceSpan]
171+getInfo q = parseInfo <$> sendCommand (typeC q [])
172+
179−addImport :: String -> FilePath -> FilePath -> IO String
173+addImport :: Text -> FilePath -> FilePath -> IO Text
180addImport identifier fp outfp = sendCommand (addImportC identifier fp outfp)
174addImport identifier fp outfp = sendCommand (addImportC identifier fp outfp)
181
175
182−addImplicitImport :: String -> FilePath -> FilePath -> IO String
176+addImplicitImport :: Text -> FilePath -> FilePath -> IO Text
183addImplicitImport mn fp outfp = sendCommand (addImplicitImportC mn fp outfp)
177addImplicitImport mn fp outfp = sendCommand (addImplicitImportC mn fp outfp)
184
178
185−rebuildModule :: FilePath -> IO String
179+rebuildModule :: FilePath -> IO Text
186rebuildModule m = sendCommand (rebuildC m Nothing)
180rebuildModule m = sendCommand (rebuildC m Nothing)
187
181
188-- Command Encoding
182-- Command Encoding
189
183
190−commandWrapper :: String -> Value -> Value
184+commandWrapper :: Text -> Value -> Value
191commandWrapper c p = object ["command" .= c, "params" .= p]
185commandWrapper c p = object ["command" .= c, "params" .= p]
192
186
193−load :: [String] -> [String] -> Value
187+load :: [Text] -> Value
194−load ms ds = commandWrapper "load" (object ["modules" .= ms, "dependencies" .= ds])
188+load ms = commandWrapper "load" (object ["modules" .= ms])
195
189
196−typeC :: String -> [Value] -> Value
190+typeC :: Text -> [Value] -> Value
197typeC q filters = commandWrapper "type" (object ["search" .= q, "filters" .= filters])
191typeC q filters = commandWrapper "type" (object ["search" .= q, "filters" .= filters])
198
192
199−addImportC :: String -> FilePath -> FilePath -> Value
193+addImportC :: Text -> FilePath -> FilePath -> Value
200addImportC identifier = addImportW $
194addImportC identifier = addImportW $
201− object [ "importCommand" .= ("addImport" :: String)
195+ object [ "importCommand" .= ("addImport" :: Text)
202 , "identifier" .= identifier
196 , "identifier" .= identifier
203 ]
197 ]
204
198
205−addImplicitImportC :: String -> FilePath -> FilePath -> Value
199+addImplicitImportC :: Text -> FilePath -> FilePath -> Value
206addImplicitImportC mn = addImportW $
200addImplicitImportC mn = addImportW $
207− object [ "importCommand" .= ("addImplicitImport" :: String)
201+ object [ "importCommand" .= ("addImplicitImport" :: Text)
208 , "module" .= mn
202 , "module" .= mn
209 ]
203 ]
210
204
@@ -222,7 +216,7 @@ addImportW importCommand fp outfp =
222 ])
216 ])
223
217
224
218
225−completion :: [Value] -> Maybe Value -> Maybe String -> Value
219+completion :: [Value] -> Maybe Value -> Maybe Text -> Value
226completion filters matcher currentModule =
220completion filters matcher currentModule =
227 let
221 let
228 matcher' = case matcher of
222 matcher' = case matcher of
@@ -234,16 +228,16 @@ completion filters matcher currentModule =
234 in
228 in
235 commandWrapper "complete" (object $ "filters" .= filters : matcher' ++ currentModule' )
229 commandWrapper "complete" (object $ "filters" .= filters : matcher' ++ currentModule' )
236
230
237−flexMatcher :: String -> Value
231+flexMatcher :: Text -> Value
238−flexMatcher q = object [ "matcher" .= ("flex" :: String)
232+flexMatcher q = object [ "matcher" .= ("flex" :: Text)
239 , "params" .= object ["search" .= q]
233 , "params" .= object ["search" .= q]
240 ]
234 ]
241
235
242-- Result parsing
236-- Result parsing
243
237
244−unwrapResult :: Value -> Parser (Either String Value)
238+unwrapResult :: Value -> Parser (Either Text Value)
245unwrapResult = withObject "result" $ \o -> do
239unwrapResult = withObject "result" $ \o -> do
246− (rt :: String) <- o .: "resultType"
240+ (rt :: Text) <- o .: "resultType"
247 case rt of
241 case rt of
248 "error" -> do
242 "error" -> do
249 res <- o .: "result"
243 res <- o .: "result"
@@ -251,16 +245,16 @@ unwrapResult = withObject "result" $ \o -> do
251 "success" -> do
245 "success" -> do
252 res <- o .: "result"
246 res <- o .: "result"
253 pure (Right res)
247 pure (Right res)
254− _ -> fail "lol"
248+ _ -> mzero
255
249
256−withResult :: (Value -> Parser a) -> Value -> Parser (Either String a)
250+withResult :: (Value -> Parser a) -> Value -> Parser (Either Text a)
257withResult p v = do
251withResult p v = do
258 r <- unwrapResult v
252 r <- unwrapResult v
259 case r of
253 case r of
260 Left err -> pure (Left err)
254 Left err -> pure (Left err)
261 Right res -> Right <$> p res
255 Right res -> Right <$> p res
262
256
263−completionParser :: Value -> Parser [(String, String, String)]
257+completionParser :: Value -> Parser [(Text, Text, Text)]
264completionParser = withArray "res" $ \cs ->
258completionParser = withArray "res" $ \cs ->
265 mapM (withObject "completion" $ \o -> do
259 mapM (withObject "completion" $ \o -> do
266 ident <- o .: "identifier"
260 ident <- o .: "identifier"
@@ -268,22 +262,24 @@ completionParser = withArray "res" $ \cs ->
268 ty <- o .: "type"
262 ty <- o .: "type"
269 pure (module', ident, ty)) (V.toList cs)
263 pure (module', ident, ty)) (V.toList cs)
270
264
271−valueFromString :: String -> Value
265+infoParser :: Value -> Parser [P.SourceSpan]
272−valueFromString = fromJust . decode . BSL.fromString
266+infoParser = withArray "res" $ \cs ->
267+ mapM (withObject "info" $ \o -> o .: "definedAt") (V.toList cs)
273
268
274−resultIsSuccess :: String -> Bool
269+valueFromText :: Text -> Value
275−resultIsSuccess = isRight . join . parseEither unwrapResult . valueFromString
270+valueFromText = fromJust . decode . toS
276
271
277−parseCompletions :: String -> [(String, String, String)]
272+resultIsSuccess :: Text -> Bool
278−parseCompletions s = fromJust $ do
273+resultIsSuccess = isRight . join . first toS . parseEither unwrapResult . valueFromText
279− cs <- parseMaybe (withResult completionParser) (valueFromString s)
280− case cs of
281− Left _ -> error "Failed to parse completions"
282− Right cs' -> pure cs'
283
274
284−parseTextResult :: String -> String
275+parseCompletions :: Text -> [(Text, Text, Text)]
285−parseTextResult s = fromJust $ do
276+parseCompletions s =
277+ fromJust $ join (rightToMaybe <$> parseMaybe (withResult completionParser) (valueFromText s))
278+
279+parseInfo :: Text -> [P.SourceSpan]
280+parseInfo s =
281+ fromJust $ join (rightToMaybe <$> parseMaybe (withResult infoParser) (valueFromText s))
282+
283+parseTextResult :: Text -> Text
284+parseTextResult s =
286− r <- parseMaybe (withResult (withText "tr" pure)) (valueFromString s)
285+ fromJust $ join (rightToMaybe <$> parseMaybe (withResult (withText "tr" pure)) (valueFromText s))
287− case r of
288− Left _ -> error "Failed to parse textResult"
289− Right r' -> pure (T.unpack r')
tests/Language/PureScript/Ide/MatcherSpec.hs+16−17
@@ -1,33 +1,32 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
2
3
3module Language.PureScript.Ide.MatcherSpec where
4module Language.PureScript.Ide.MatcherSpec where
4
5
5−import Control.Monad (void)
6+import Protolude
6−import Data.Text (Text)
7+
7import qualified Language.PureScript as P
8import qualified Language.PureScript as P
8import Language.PureScript.Ide.Integration
9import Language.PureScript.Ide.Integration
9import Language.PureScript.Ide.Matcher
10import Language.PureScript.Ide.Matcher
10import Language.PureScript.Ide.Types
11import Language.PureScript.Ide.Types
11import Test.Hspec
12import Test.Hspec
12
13
13−value :: Text -> ExternDecl
14+value :: Text -> IdeDeclaration
14−value s = ValueDeclaration s $ P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
15+value s = IdeValue (P.Ident (toS s)) P.REmpty
15
16
16−completions :: [Match]
17+firstResult, secondResult, fiult :: Match IdeDeclaration
17−completions =
18− [ Match "" (value "firstResult")
18+firstResult = Match (P.moduleNameFromString "Match", value "firstResult")
19− , Match "" (value "secondResult")
19+secondResult = Match (P.moduleNameFromString "Match", value "secondResult")
20− , Match "" (value "fiult")
20+fiult = Match (P.moduleNameFromString "Match", value "fiult")
21− ]
22
21
23−mkResult :: [Int] -> [Match]
22+completions :: [Match IdeDeclaration]
24−mkResult = map (completions !!)
23+completions = [firstResult, secondResult, fiult]
25
24
26−runFlex :: Text -> [Match]
25+runFlex :: Text -> [Match IdeDeclaration]
27runFlex s = runMatcher (flexMatcher s) completions
26runFlex s = runMatcher (flexMatcher s) completions
28
27
29setup :: IO ()
28setup :: IO ()
30−setup = reset *> void (loadModuleWithDeps "Main")
29+setup = reset *> void loadAll
31
30
32spec :: Spec
31spec :: Spec
33spec = do
32spec = do
@@ -35,9 +34,9 @@ spec = do
35 it "doesn't match on an empty string" $
34 it "doesn't match on an empty string" $
36 runFlex "" `shouldBe` []
35 runFlex "" `shouldBe` []
37 it "matches on equality" $
36 it "matches on equality" $
38− runFlex "firstResult" `shouldBe` mkResult [0]
37+ runFlex "firstResult" `shouldBe` [firstResult]
39 it "scores short matches higher and sorts accordingly" $
38 it "scores short matches higher and sorts accordingly" $
40− runFlex "filt" `shouldBe` mkResult [2, 0]
39+ runFlex "filt" `shouldBe` [fiult, firstResult]
41
40
42 beforeAll_ setup . describe "Integration Tests: Flex Matcher" $ do
41 beforeAll_ setup . describe "Integration Tests: Flex Matcher" $ do
43 it "doesn't match on an empty string" $ do
42 it "doesn't match on an empty string" $ do
@@ -45,4 +44,4 @@ spec = do
45 cs `shouldBe` []
44 cs `shouldBe` []
46 it "matches on equality" $ do
45 it "matches on equality" $ do
47 cs <- getFlexCompletions "const"
46 cs <- getFlexCompletions "const"
48− cs `shouldBe` [("Main", "const", "forall a b. a -> b -> a")]
47+ cs `shouldBe` [("MatcherSpec", "const", "forall a b. a -> b -> a")]
tests/Language/PureScript/Ide/RebuildSpec.hs+10−6
@@ -1,19 +1,23 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE OverloadedStrings #-}
1module Language.PureScript.Ide.RebuildSpec where
3module Language.PureScript.Ide.RebuildSpec where
2
4
5+import Protolude
6+
3import qualified Language.PureScript.Ide.Integration as Integration
7import qualified Language.PureScript.Ide.Integration as Integration
4import System.FilePath
8import System.FilePath
5import Test.Hspec
9import Test.Hspec
6
10
7−shouldBeSuccess :: String -> IO ()
11+shouldBeSuccess :: Text -> IO ()
8shouldBeSuccess = shouldBe True . Integration.resultIsSuccess
12shouldBeSuccess = shouldBe True . Integration.resultIsSuccess
9
13
10−shouldBeFailure :: String -> IO ()
14+shouldBeFailure :: Text -> IO ()
11shouldBeFailure = shouldBe False . Integration.resultIsSuccess
15shouldBeFailure = shouldBe False . Integration.resultIsSuccess
12
16
13spec :: Spec
17spec :: Spec
14spec = before_ Integration.reset . describe "Rebuilding single modules" $ do
18spec = before_ Integration.reset . describe "Rebuilding single modules" $ do
15 it "rebuilds a correct module without dependencies successfully" $ do
19 it "rebuilds a correct module without dependencies successfully" $ do
16− _ <- Integration.loadModuleWithDeps "RebuildSpecSingleModule"
20+ _ <- Integration.loadModule "RebuildSpecSingleModule"
17 pdir <- Integration.projectDirectory
21 pdir <- Integration.projectDirectory
18 let file = pdir </> "src" </> "RebuildSpecSingleModule.purs"
22 let file = pdir </> "src" </> "RebuildSpecSingleModule.purs"
19 Integration.rebuildModule file >>= shouldBeSuccess
23 Integration.rebuildModule file >>= shouldBeSuccess
@@ -22,12 +26,12 @@ spec = before_ Integration.reset . describe "Rebuilding single modules" $ do
22 let file = pdir </> "src" </> "RebuildSpecSingleModule.fail"
26 let file = pdir </> "src" </> "RebuildSpecSingleModule.fail"
23 Integration.rebuildModule file >>= shouldBeFailure
27 Integration.rebuildModule file >>= shouldBeFailure
24 it "rebuilds a correct module with its dependencies successfully" $ do
28 it "rebuilds a correct module with its dependencies successfully" $ do
25− _ <- Integration.loadModuleWithDeps "RebuildSpecWithDeps"
29+ _ <- Integration.loadModules ["RebuildSpecWithDeps", "RebuildSpecDep"]
26 pdir <- Integration.projectDirectory
30 pdir <- Integration.projectDirectory
27 let file = pdir </> "src" </> "RebuildSpecWithDeps.purs"
31 let file = pdir </> "src" </> "RebuildSpecWithDeps.purs"
28 Integration.rebuildModule file >>= shouldBeSuccess
32 Integration.rebuildModule file >>= shouldBeSuccess
29 it "rebuilds a correct module that has reverse dependencies" $ do
33 it "rebuilds a correct module that has reverse dependencies" $ do
30− _ <- Integration.loadModuleWithDeps "RebuildSpecWithDeps"
34+ _ <- Integration.loadModule "RebuildSpecWithDeps"
31 pdir <- Integration.projectDirectory
35 pdir <- Integration.projectDirectory
32 let file = pdir </> "src" </> "RebuildSpecDep.purs"
36 let file = pdir </> "src" </> "RebuildSpecDep.purs"
33 Integration.rebuildModule file >>= shouldBeSuccess
37 Integration.rebuildModule file >>= shouldBeSuccess
@@ -37,7 +41,7 @@ spec = before_ Integration.reset . describe "Rebuilding single modules" $ do
37 let file = pdir </> "src" </> "RebuildSpecWithDeps.purs"
41 let file = pdir </> "src" </> "RebuildSpecWithDeps.purs"
38 Integration.rebuildModule file >>= shouldBeFailure
42 Integration.rebuildModule file >>= shouldBeFailure
39 it "rebuilds a correct module with a foreign file" $ do
43 it "rebuilds a correct module with a foreign file" $ do
40− _ <- Integration.loadModuleWithDeps "RebuildSpecWithForeign"
44+ _ <- Integration.loadModule "RebuildSpecWithForeign"
41 pdir <- Integration.projectDirectory
45 pdir <- Integration.projectDirectory
42 let file = pdir </> "src" </> "RebuildSpecWithForeign.purs"
46 let file = pdir </> "src" </> "RebuildSpecWithForeign.purs"
43 Integration.rebuildModule file >>= shouldBeSuccess
47 Integration.rebuildModule file >>= shouldBeSuccess
tests/Language/PureScript/Ide/ReexportsSpec.hs+54−71
@@ -1,81 +1,64 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
2module Language.PureScript.Ide.ReexportsSpec where
3module Language.PureScript.Ide.ReexportsSpec where
3
4
4−import Control.Exception (evaluate)
5+import qualified Prelude as Prelude
5−import Data.List (sort)
6+import Protolude
7+
6−import qualified Data.Map as Map
8+import qualified Data.Map as Map
7import Language.PureScript.Ide.Reexports
9import Language.PureScript.Ide.Reexports
8import Language.PureScript.Ide.Types
10import Language.PureScript.Ide.Types
9import qualified Language.PureScript as P
11import qualified Language.PureScript as P
10import Test.Hspec
12import Test.Hspec
11
13
12−wildcard :: P.Type
14+m :: Prelude.String -> P.ModuleName
13−wildcard = P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
15+m = P.moduleNameFromString
14−
16+
15−decl1 :: ExternDecl
17+d :: IdeDeclaration -> IdeDeclarationAnn
16−decl1 = ValueDeclaration "filter" wildcard
18+d = IdeDeclarationAnn emptyAnn
17−decl2 :: ExternDecl
19+
18−decl2 = ValueDeclaration "map" wildcard
20+valueA, typeA, classA, dtorA1, dtorA2 :: IdeDeclarationAnn
19−decl3 :: ExternDecl
21+valueA = d (IdeValue (P.Ident "valueA") P.REmpty)
20−decl3 = ValueDeclaration "catMaybe" wildcard
22+typeA = d (IdeType (P.ProperName "TypeA") P.Star)
21−dep1 :: ExternDecl
23+classA = d (IdeTypeClass (P.ProperName "ClassA"))
22−dep1 = Dependency "Test.Foo" [] (Just "T")
24+dtorA1 = d (IdeDataConstructor (P.ProperName "DtorA1") (P.ProperName "TypeA") P.REmpty)
23−dep2 :: ExternDecl
25+dtorA2 = d (IdeDataConstructor (P.ProperName "DtorA2") (P.ProperName "TypeA") P.REmpty)
24−dep2 = Dependency "Test.Bar" [] (Just "T")
26+
25−
27+env :: Map P.ModuleName [IdeDeclarationAnn]
26−circularModule :: Module
27−circularModule = ("Circular", [Export "Circular"])
28−
29−module1 :: Module
30−module1 = ("Module1", [Export "Module2", Export "Module3", decl1])
31−
32−module2 :: Module
33−module2 = ("Module2", [decl2])
34−
35−module3 :: Module
36−module3 = ("Module3", [decl3])
37−
38−module4 :: Module
39−module4 = ("Module4", [Export "T", decl1, dep1, dep2])
40−
41−result :: Module
42−result = ("Module1", [decl1, decl2, Export "Module3"])
43−
44−db :: Map.Map ModuleIdent [ExternDecl]
45−db = Map.fromList [module1, module2, module3]
28+env = Map.fromList
46−
29+ [ (m "A", [valueA, typeA, classA, dtorA1, dtorA2])
47−shouldBeEqualSorted :: Module -> Module -> Expectation
30+ ]
48−shouldBeEqualSorted (n1, d1) (n2, d2) = (n1, sort d1) `shouldBe` (n2, sort d2)
31+
32+type Refs = [(P.ModuleName, P.DeclarationRef)]
33+
34+succTestCases :: [(Text, Module, Refs, Module)]
35+succTestCases =
36+ [ ("resolves a value reexport", (m "C", []), [(m "A", P.ValueRef (P.Ident "valueA"))], (m "C", [valueA]))
37+ , ("resolves a type reexport with explicit data constructors"
38+ , (m "C", []), [(m "A", P.TypeRef (P.ProperName "TypeA") (Just [P.ProperName "DtorA1"]))], (m "C", [typeA, dtorA1]))
39+ , ("resolves a type reexport with implicit data constructors"
40+ , (m "C", []), [(m "A", P.TypeRef (P.ProperName "TypeA") Nothing)], (m "C", [typeA, dtorA1, dtorA2]))
41+ , ("resolves a class reexport", (m "C", []), [(m "A", P.TypeClassRef (P.ProperName "ClassA"))], (m "C", [classA]))
42+ ]
43+
44+failTestCases :: [(Text, Module, Refs)]
45+failTestCases =
46+ [ ("fails to resolve a non existing value", (m "C", []), [(m "A", P.ValueRef (P.Ident "valueB"))])
47+ , ("fails to resolve a non existing type reexport" , (m "C", []), [(m "A", P.TypeRef (P.ProperName "TypeB") Nothing)])
48+ , ("fails to resolve a non existing class reexport", (m "C", []), [(m "A", P.TypeClassRef (P.ProperName "ClassB"))])
49+ ]
49
50
50spec :: Spec
51spec :: Spec
51−spec =
52+spec = do
52− describe "Reexports" $ do
53+ describe "Successful Reexports" $
53− it "finds all reexports" $
54+ for_ succTestCases $ \(desc, initial, refs, result) ->
54− getReexports module1 `shouldBe` [Export "Module2", Export "Module3"]
55+ it (toS desc) $ do
55−
56+ let reResult = resolveReexports env (initial, refs)
56− it "replaces a reexport with another module" $
57+ reResolved reResult `shouldBe` result
57− replaceReexport (Export "Module2") module1 module2 `shouldBeEqualSorted` result
58+ reResult `shouldSatisfy` not . reexportHasFailures
58−
59+ describe "Failed Reexports" $
59− it "adds another module even if there is no export statement" $
60+ for_ failTestCases $ \(desc, initial, refs) ->
60− replaceReexport (Export "Module2") ("Module1", [decl1, Export "Module3"]) module2
61+ it (toS desc) $ do
61− `shouldBeEqualSorted` result
62+ let reResult = resolveReexports env (initial, refs)
62−
63+ reFailed reResult `shouldBe` refs
63− it "only adds a declaration once" $
64+ reResult `shouldSatisfy` reexportHasFailures
64− let replaced = replaceReexport (Export "Module2") module1 module2
65− in replaceReexport (Export "Module2") replaced module2 `shouldBeEqualSorted` result
66−
67− it "should error when given a non-Export to replace" $
68− evaluate (replaceReexport decl1 module1 module2)
69− `shouldThrow` errorCall "Should only get Exports here."
70− it "replaces all Exports with their corresponding declarations" $
71− replaceReexports module1 db `shouldBe` ("Module1", [decl1, decl2, decl3])
72−
73− it "does not list itself as a reexport" $
74− getReexports circularModule `shouldBe` []
75−
76− it "does not include circular references when replacing reexports" $
77− replaceReexports circularModule (uncurry Map.singleton circularModule )
78− `shouldBe` ("Circular", [])
79−
80− it "replaces exported aliases with imported module" $
81− getReexports module4 `shouldBe` [Export "Test.Foo", Export "Test.Bar"]
tests/Language/PureScript/Ide/SourceFile/IntegrationSpec.hsnew file+36
@@ -0,0 +1,36 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+module Language.PureScript.Ide.SourceFile.IntegrationSpec where
4+
5+
6+import Protolude
7+
8+import qualified Data.Text as T
9+import qualified Language.PureScript.Ide.Integration as Integration
10+import qualified Language.PureScript as P
11+import Test.Hspec
12+
13+setup :: IO ()
14+setup = void (Integration.reset *> Integration.loadAll)
15+
16+spec :: Spec
17+spec = beforeAll_ setup $ do
18+ describe "Sourcefile Integration" $ do
19+ it "finds a value declaration" $ do
20+ testCase "sfValue" (3, 1)
21+ it "finds a type declaration" $ do
22+ testCase "SFType" (5, 1)
23+ it "finds a data declaration" $ do
24+ testCase "SFData" (7, 1)
25+ it "finds a data constructor" $ do
26+ testCase "SFOne" (7, 1)
27+ it "finds a typeclass" $ do
28+ testCase "SFClass" (9, 1)
29+ it "finds a typeclass member" $ do
30+ testCase "sfShow" (10, 3)
31+
32+testCase :: Text -> (Int, Int) -> IO ()
33+testCase s (x, y) = do
34+ (P.SourceSpan f (P.SourcePos l c) _):_ <- Integration.getInfo s
35+ toS f `shouldSatisfy` T.isSuffixOf "SourceFileSpec.purs"
36+ (l, c) `shouldBe` (x, y)
tests/Language/PureScript/Ide/SourceFileSpec.hsnew file+46
@@ -0,0 +1,46 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+module Language.PureScript.Ide.SourceFileSpec where
4+
5+import Protolude
6+
7+import qualified Language.PureScript as P
8+import Language.PureScript.Ide.SourceFile
9+import Test.Hspec
10+
11+span0, span1, span2 :: P.SourceSpan
12+span0 = P.SourceSpan "ModuleLevel" (P.SourcePos 0 0) (P.SourcePos 1 1)
13+span1 = P.SourceSpan "" (P.SourcePos 1 1) (P.SourcePos 2 2)
14+span2 = P.SourceSpan "" (P.SourcePos 2 2) (P.SourcePos 3 3)
15+
16+value1, synonym1, class1, class2, data1, data2, foreign1, foreign2, member1 :: P.Declaration
17+value1 = P.ValueDeclaration (P.Ident "value1") P.Public [] (Left [])
18+synonym1 = P.TypeSynonymDeclaration (P.ProperName "Synonym1") [] P.REmpty
19+class1 = P.TypeClassDeclaration (P.ProperName "Class1") [] [] []
20+class2 = P.TypeClassDeclaration (P.ProperName "Class2") [] []
21+ [P.PositionedDeclaration span2 [] member1]
22+data1 = P.DataDeclaration P.Newtype (P.ProperName "Data1") [] []
23+data2 = P.DataDeclaration P.Data (P.ProperName "Data2") [] [(P.ProperName "Cons1", [])]
24+foreign1 = P.ExternDeclaration (P.Ident "foreign1") P.REmpty
25+foreign2 = P.ExternDataDeclaration (P.ProperName "Foreign2") P.Star
26+member1 = P.TypeDeclaration (P.Ident "member1") P.REmpty
27+
28+spec :: Spec
29+spec = do
30+ describe "Extracting Spans" $ do
31+ it "extracts a span for a value declaration" $
32+ extractSpans span0 (P.PositionedDeclaration span1 [] value1) `shouldBe` [(Left "value1", span1)]
33+ it "extracts a span for a type synonym declaration" $
34+ extractSpans span0 (P.PositionedDeclaration span1 [] synonym1) `shouldBe` [(Right "Synonym1", span1)]
35+ it "extracts a span for a typeclass declaration" $
36+ extractSpans span0 (P.PositionedDeclaration span1 [] class1) `shouldBe` [(Right "Class1", span1)]
37+ it "extracts spans for a typeclass declaration and its members" $
38+ extractSpans span0 (P.PositionedDeclaration span1 [] class2) `shouldBe` [(Right "Class2", span1), (Left "member1", span2)]
39+ it "extracts a span for a data declaration" $
40+ extractSpans span0 (P.PositionedDeclaration span1 [] data1) `shouldBe` [(Right "Data1", span1)]
41+ it "extracts spans for a data declaration and its constructors" $
42+ extractSpans span0 (P.PositionedDeclaration span1 [] data2) `shouldBe` [(Right "Data2", span1), (Left "Cons1", span1)]
43+ it "extracts a span for a foreign declaration" $
44+ extractSpans span0 (P.PositionedDeclaration span1 [] foreign1) `shouldBe` [(Left "foreign1", span1)]
45+ it "extracts a span for a data foreign declaration" $
46+ extractSpans span0 (P.PositionedDeclaration span1 [] foreign2) `shouldBe` [(Right "Foreign2", span1)]
tests/Language/PureScript/IdeSpec.hsdeleted−35
@@ -1,35 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−
3−module Language.PureScript.IdeSpec where
4−
5−import Control.Concurrent.STM
6−import Control.Monad.Reader
7−import Data.List
8−import qualified Data.Map as Map
9−import Language.PureScript.Ide
10−import Language.PureScript.Ide.Types
11−import Test.Hspec
12−
13−testState :: PscIdeState
14−testState = PscIdeState (Map.fromList [("Data.Array", []), ("Control.Monad.Eff", [])]) Map.empty Nothing
15−
16−defaultConfig :: Configuration
17−defaultConfig =
18− Configuration
19− {
20− confOutputPath = "output/"
21− , confDebug = False
22− }
23−
24−spec :: SpecWith ()
25−spec =
26− describe "list" $
27− describe "loadedModules" $ do
28− it "returns an empty list when no modules are loaded" $ do
29− st <- newTVarIO emptyPscIdeState
30− result <- runReaderT printModules (PscIdeEnvironment st defaultConfig)
31− result `shouldBe` ModuleList []
32− it "returns the list of loaded modules" $ do
33− st <- newTVarIO testState
34− ModuleList result <- runReaderT printModules (PscIdeEnvironment st defaultConfig)
35− sort result `shouldBe` sort ["Data.Array", "Control.Monad.Eff"]
tests/TestCompiler.hs+4−4
@@ -76,7 +76,7 @@ spec = do
76 externs <- ExceptT . fmap fst . runTest $ P.make (makeActions foreigns) (map snd modules)
76 externs <- ExceptT . fmap fst . runTest $ P.make (makeActions foreigns) (map snd modules)
77 return (zip (map snd modules) externs)
77 return (zip (map snd modules) externs)
78 case supportExterns of
78 case supportExterns of
79− Left errs -> fail (P.prettyPrintMultipleErrors False errs)
79+ Left errs -> fail (P.prettyPrintMultipleErrors P.defaultPPEOptions errs)
80 Right externs -> return (externs, passingFiles, warningFiles, failingFiles)
80 Right externs -> return (externs, passingFiles, warningFiles, failingFiles)
81
81
82 context "Passing examples" $
82 context "Passing examples" $
@@ -232,7 +232,7 @@ assertCompiles
232assertCompiles supportExterns inputFiles =
232assertCompiles supportExterns inputFiles =
233 assert supportExterns inputFiles checkMain $ \e ->
233 assert supportExterns inputFiles checkMain $ \e ->
234 case e of
234 case e of
235− Left errs -> return . Just . P.prettyPrintMultipleErrors False $ errs
235+ Left errs -> return . Just . P.prettyPrintMultipleErrors P.defaultPPEOptions $ errs
236 Right _ -> do
236 Right _ -> do
237 process <- findNodeProcess
237 process <- findNodeProcess
238 let entryPoint = modulesDir </> "index.js"
238 let entryPoint = modulesDir </> "index.js"
@@ -255,7 +255,7 @@ assertCompilesWithWarnings supportExterns inputFiles shouldWarnWith =
255 assert supportExterns inputFiles checkMain $ \e ->
255 assert supportExterns inputFiles checkMain $ \e ->
256 case e of
256 case e of
257 Left errs ->
257 Left errs ->
258− return . Just . P.prettyPrintMultipleErrors False $ errs
258+ return . Just . P.prettyPrintMultipleErrors P.defaultPPEOptions $ errs
259 Right warnings ->
259 Right warnings ->
260 return
260 return
261 . fmap (printAllWarnings warnings)
261 . fmap (printAllWarnings warnings)
@@ -263,7 +263,7 @@ assertCompilesWithWarnings supportExterns inputFiles shouldWarnWith =
263
263
264 where
264 where
265 printAllWarnings warnings =
265 printAllWarnings warnings =
266− (<> "\n\n" <> P.prettyPrintMultipleErrors False warnings)
266+ (<> "\n\n" <> P.prettyPrintMultipleErrors P.defaultPPEOptions warnings)
267
267
268assertDoesNotCompile
268assertDoesNotCompile
269 :: [(P.Module, P.ExternsFile)]
269 :: [(P.Module, P.ExternsFile)]
tests/TestUtils.hs+10−1
@@ -12,6 +12,8 @@ import Control.Exception
12import System.Process
12import System.Process
13import System.Directory
13import System.Directory
14import System.Info
14import System.Info
15+import System.Exit (exitFailure)
16+import System.IO (stderr, hPutStrLn)
15
17
16findNodeProcess :: IO (Maybe String)
18findNodeProcess :: IO (Maybe String)
17findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names
19findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names
@@ -33,10 +35,17 @@ updateSupportCode = do
33 then callProcess "setup-win.cmd" []
35 then callProcess "setup-win.cmd" []
34 else do
36 else do
35 callProcess "npm" ["install"]
37 callProcess "npm" ["install"]
38+ -- bower uses shebang "/usr/bin/env node", but we might have nodejs
39+ node <- maybe cannotFindNode pure =<< findNodeProcess
36 -- Sometimes we run as a root (e.g. in simple docker containers)
40 -- Sometimes we run as a root (e.g. in simple docker containers)
37 -- And we are non-interactive: https://github.com/bower/bower/issues/1162
41 -- And we are non-interactive: https://github.com/bower/bower/issues/1162
38− callProcess "node_modules/.bin/bower" ["--allow-root", "install", "--config.interactive=false"]
42+ callProcess node ["node_modules/.bin/bower", "--allow-root", "install", "--config.interactive=false"]
39 setCurrentDirectory "../.."
43 setCurrentDirectory "../.."
44+ where
45+ cannotFindNode :: IO a
46+ cannotFindNode = do
47+ hPutStrLn stderr "Cannot find node (or nodejs) executable"
48+ exitFailure
40
49
41-- |
50-- |
42-- The support modules that should be cached between test cases, to avoid
51-- The support modules that should be cached between test cases, to avoid
tests/support/pscide/src/ImportsSpec.purs+1−3
@@ -1,5 +1,3 @@
1module ImportsSpec where
1module ImportsSpec where
2
2
3−import Main (id)
4−
5−myId = id
3+myId x = x
tests/support/pscide/src/Main.purs → tests/support/pscide/src/MatcherSpec.pursrenamed+1−1
@@ -1,4 +1,4 @@
1−module Main where
1+module MatcherSpec where
2
2
3id :: forall a. a -> a
3id :: forall a. a -> a
4id x = x
4id x = x
tests/support/pscide/src/RebuildSpecSingleModule.purs+1−1
@@ -1,4 +1,4 @@
1module RebuildSpecSingleModule where
1module RebuildSpecSingleModule where
2
2
3id x = x
3id x = x
4−const x y = x
4+lulz x y = x
tests/support/pscide/src/RebuildSpecWithForeign.js−2
@@ -1,3 +1 @@
1−// module RebuildSpecWithForeign
2−
3exports.f = 5;
1exports.f = 5;
tests/support/pscide/src/SourceFileSpec.pursnew file+10
@@ -0,0 +1,10 @@
1+module SourceFileSpec where
2+
3+sfValue = "sfValue"
4+
5+type SFType = String
6+
7+data SFData = SFOne | SFTwo | SFThree
8+
9+class SFClass a where
10+ sfShow :: a -> String
travis/build.sh+1−1
@@ -45,7 +45,7 @@ then
45elif [ "$BUILD_TYPE" = "haddock" ]
45elif [ "$BUILD_TYPE" = "haddock" ]
46then
46then
47 echo ">>> Checking haddock documentation..."
47 echo ">>> Checking haddock documentation..."
48− $STACK haddock
48+ $STACK haddock --fast
49else
49else
50 echo "Unrecognised BUILD_TYPE: $BUILD_TYPE"
50 echo "Unrecognised BUILD_TYPE: $BUILD_TYPE"
51 exit 1
51 exit 1