git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge remote-tracking branch 'upstream/master' into pure11-0.9
commit7afff2eab57c7b2b446b36d572ccd6da6554073c authorAndy Arvanitis <andyarvanitis@gmail.com> dateWed 13 Jul 2016, 22:02 (10 years ago) parentafc1492f0d5256
127 files changed+2799−1771
.travis.yml+11−5 CONTRIBUTORS.md+2 LICENSE+270−10 examples/failing/2128-class.purs+5 examples/failing/2128-instance.purs+8 examples/failing/DeclConflictClassCtor.purs+6 examples/failing/DeclConflictClassSynonym.purs+8 examples/failing/DeclConflictClassType.purs+6 examples/failing/DeclConflictCtorClass.purs+6 examples/failing/DeclConflictCtorCtor.purs+6 examples/failing/DeclConflictSynonymClass.purs+8 examples/failing/DeclConflictSynonymType.purs+8 examples/failing/DeclConflictTypeClass.purs+6 examples/failing/DeclConflictTypeSynonym.purs+8 examples/failing/DeclConflictTypeType.purs+6 examples/failing/ExportConflictClass.purs+5 examples/failing/ExportConflictClass/A.purs+3 examples/failing/ExportConflictClass/B.purs+3 examples/failing/ExportConflictCtor.purs+5 examples/failing/ExportConflictCtor/A.purs+3 examples/failing/ExportConflictCtor/B.purs+3 examples/failing/ExportConflictType.purs+5 examples/failing/ExportConflictType/A.purs+3 examples/failing/ExportConflictType/B.purs+3 examples/failing/ExportConflictTypeOp.purs+5 examples/failing/ExportConflictTypeOp/A.purs+5 examples/failing/ExportConflictTypeOp/B.purs+5 examples/failing/ExportConflictValue.purs+5 examples/failing/OverlappingReExport/A.purs → examples/failing/ExportConflictValue/A.purs+2 examples/failing/OverlappingReExport/B.purs → examples/failing/ExportConflictValue/B.purs+2 examples/failing/ExportConflictValueOp.purs+5 examples/failing/ExportConflictValueOp/A.purs+6 examples/failing/ExportConflictValueOp/B.purs+6 examples/failing/OverlappingReExport.purs−5 examples/failing/ProgrammableTypeErrors.purs+16 examples/passing/2172.js+5 examples/passing/2172.purs+10 examples/passing/PrimedTypeName.purs+20 hierarchy/Main.hs+1−1 psc-bundle/Main.hs+1−9 psc-docs/Main.hs+1−1 psc-ide-client/Main.hs+6−16 psc-ide-server/Main.hs+33−42 psc-ide-server/PROTOCOL.md+26−9 psc-ide-server/README.md+4−1 psc/Main.hs+6−2 psci/Main.hs+259−27 psci/static/index.html+10 psci/static/index.js+63 purescript.cabal+43−15 src/Language/PureScript/AST/Declarations.hs+15−6 src/Language/PureScript/Bundle.hs+39−4 src/Language/PureScript/CodeGen/JS/Optimizer.hs+2−2 src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs+1−1 src/Language/PureScript/Constants.hs+6 src/Language/PureScript/Docs/ParseAndBookmark.hs+1−1 src/Language/PureScript/Environment.hs+4−1 src/Language/PureScript/Errors.hs+285−226 src/Language/PureScript/Errors/JSON.hs+1−1 src/Language/PureScript/Ide.hs+129−178 src/Language/PureScript/Ide/CaseSplit.hs+24−30 src/Language/PureScript/Ide/Command.hs+11−18 src/Language/PureScript/Ide/Completion.hs+17−17 src/Language/PureScript/Ide/Conversions.hs+35 src/Language/PureScript/Ide/Error.hs+8−12 src/Language/PureScript/Ide/Externs.hs+62−63 src/Language/PureScript/Ide/Filter.hs+17−50 src/Language/PureScript/Ide/Imports.hs+37−51 src/Language/PureScript/Ide/Matcher.hs+26−32 src/Language/PureScript/Ide/Pursuit.hs+9−12 src/Language/PureScript/Ide/Rebuild.hs+16−18 src/Language/PureScript/Ide/Reexports.hs+93−64 src/Language/PureScript/Ide/SourceFile.hs+73−88 src/Language/PureScript/Ide/State.hs+168−97 src/Language/PureScript/Ide/Types.hs+99−75 src/Language/PureScript/Ide/Util.hs+58−46 src/Language/PureScript/Ide/Watcher.hs+9−9 src/Language/PureScript/Interactive.hs+47−41 src/Language/PureScript/Interactive/Module.hs+16−3 src/Language/PureScript/Interactive/Types.hs−1 src/Language/PureScript/Kinds.hs+8−18 src/Language/PureScript/Linter/Exhaustive.hs+2−2 src/Language/PureScript/Linter/Imports.hs+1−2 src/Language/PureScript/Make.hs+2−2 src/Language/PureScript/Parser/Common.hs+10−1 src/Language/PureScript/Parser/Declarations.hs+8−8 src/Language/PureScript/Parser/Kinds.hs+4 src/Language/PureScript/Parser/Lexer.hs+20−12 src/Language/PureScript/Parser/Types.hs+5−1 src/Language/PureScript/Pretty/Common.hs+5−1 src/Language/PureScript/Pretty/Kinds.hs+1 src/Language/PureScript/Pretty/Types.hs+1 src/Language/PureScript/Publish.hs+1 src/Language/PureScript/Publish/ErrorsWarnings.hs+1−1 src/Language/PureScript/Sugar/CaseDeclarations.hs+1−1 src/Language/PureScript/Sugar/Names.hs+30−25 src/Language/PureScript/Sugar/Names/Env.hs+68−31 src/Language/PureScript/Sugar/Names/Exports.hs+20−13 src/Language/PureScript/Sugar/Names/Imports.hs+2−1 src/Language/PureScript/TypeChecker.hs+9−8 src/Language/PureScript/TypeChecker/Entailment.hs+1 src/Language/PureScript/TypeChecker/Kinds.hs+2 src/Language/PureScript/TypeChecker/Rows.hs+1−3 src/Language/PureScript/TypeChecker/Skolems.hs+1−1 src/Language/PureScript/TypeChecker/Types.hs+2−2 src/Language/PureScript/TypeChecker/Unify.hs+8−7 src/Language/PureScript/Types.hs+19−51 stack-ghc-8.0.yaml+7 stack.yaml+2−5 tests/Language/PureScript/Ide/FilterSpec.hs+21−32 tests/Language/PureScript/Ide/Imports/IntegrationSpec.hs+14−25 tests/Language/PureScript/Ide/ImportsSpec.hs+9−9 tests/Language/PureScript/Ide/Integration.hs+73−77 tests/Language/PureScript/Ide/MatcherSpec.hs+16−17 tests/Language/PureScript/Ide/RebuildSpec.hs+10−6 tests/Language/PureScript/Ide/ReexportsSpec.hs+54−71 tests/Language/PureScript/Ide/SourceFile/IntegrationSpec.hs+36 tests/Language/PureScript/Ide/SourceFileSpec.hs+46 tests/Language/PureScript/IdeSpec.hs−35 tests/TestCompiler.hs+4−4 tests/TestUtils.hs+10−1 tests/support/pscide/src/ImportsSpec.purs+1−3 tests/support/pscide/src/Main.purs → tests/support/pscide/src/MatcherSpec.purs+1−1 tests/support/pscide/src/RebuildSpecSingleModule.purs+1−1 tests/support/pscide/src/RebuildSpecWithForeign.js−2 tests/support/pscide/src/SourceFileSpec.purs+10 travis/build.sh+1−1
.travis.yml+11−5
@@ -12,20 +12,26 @@ matrix:
1212 os: linux
1313 dist: trusty
1414 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
1623
17− - compiler: cc-linux-nightly-normal
24+ - compiler: cc-linux-ghc8.0-normal
1825 os: linux
1926 dist: trusty
2027 sudo: required
21− env: BUILD_TYPE=normal STACKAGE_NIGHTLY=true
22− allow_failures: true
28+ env: BUILD_TYPE=normal STACK_YAML=stack-ghc-8.0.yaml
2329
2430 - compiler: cc-linux-lts-sdist
2531 os: linux
2632 dist: trusty
2733 sudo: required
28− env: BUILD_TYPE=sdist
34+ env: BUILD_TYPE=sdist COVERAGE=true
2935
3036 - compiler: cc-linux-lts-haddock
3137 os: linux
CONTRIBUTORS.md+2
@@ -71,6 +71,8 @@ This file lists the contributors to the PureScript compiler project, and the ter
7171- [@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).
7272- [@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).
7373- [@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).
7476
7577### Companies
7678
LICENSE+270−10
@@ -46,6 +46,7 @@ PureScript uses the following Haskell library packages. Their license files foll
4646 bytestring-builder
4747 case-insensitive
4848 cereal
49+ clock
4950 conduit
5051 conduit-extra
5152 connection
@@ -56,8 +57,10 @@ PureScript uses the following Haskell library packages. Their license files foll
5657 deepseq
5758 directory
5859 dlist
60+ easy-file
5961 edit-distance
6062 exceptions
63+ fail
6164 fast-logger
6265 filepath
6366 fsnotify
@@ -82,6 +85,7 @@ PureScript uses the following Haskell library packages. Their license files foll
8285 network
8386 network-uri
8487 old-locale
88+ old-time
8589 optparse-applicative
8690 parallel
8791 parsec
@@ -91,6 +95,7 @@ PureScript uses the following Haskell library packages. Their license files foll
9195 pipes-http
9296 primitive
9397 process
98+ protolude
9499 random
95100 regex-base
96101 regex-tdfa
@@ -105,6 +110,7 @@ PureScript uses the following Haskell library packages. Their license files foll
105110 stm
106111 stm-chans
107112 streaming-commons
113+ string-conv
108114 syb
109115 tagged
110116 template-haskell
@@ -117,6 +123,7 @@ PureScript uses the following Haskell library packages. Their license files foll
117123 transformers-compat
118124 unix
119125 unix-compat
126+ unix-time
120127 unordered-containers
121128 utf8-string
122129 vector
@@ -955,6 +962,41 @@ cereal LICENSE file:
955962 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
956963 POSSIBILITY OF SUCH DAMAGE.
957964
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+
9581000conduit LICENSE file:
9591001
9601002 Copyright (c) 2012 Michael Snoyman, http://www.yesodweb.com/
@@ -1142,16 +1184,16 @@ data-default-class LICENSE file:
11421184 may be used to endorse or promote products derived from this software
11431185 without specific prior written permission.
11441186
1145− THIS SOFTWARE IS PROVIDED BY LUKAS MAI AND CONTRIBUTORS "AS IS" AND ANY
1146− EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1187+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1188+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
11471189 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1148− DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
1149− DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1150− (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1151− LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
1152− ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1153− (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1154− SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1190+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
1191+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1192+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1193+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1194+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
1195+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1196+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11551197
11561198deepseq LICENSE file:
11571199
@@ -1295,6 +1337,38 @@ dlist LICENSE file:
12951337 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
12961338 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12971339
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+
12981372edit-distance LICENSE file:
12991373
13001374 Copyright (c) 2008-2013 Maximilian Bolingbroke
@@ -1354,6 +1428,39 @@ exceptions LICENSE file:
13541428 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
13551429 POSSIBILITY OF SUCH DAMAGE.
13561430
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+
13571464fast-logger LICENSE file:
13581465
13591466 Copyright (c) 2009, IIJ Innovation Institute Inc.
@@ -2122,6 +2229,72 @@ old-locale LICENSE file:
21222229
21232230 -----------------------------------------------------------------------------
21242231
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+
21252298optparse-applicative LICENSE file:
21262299
21272300 Copyright (c) 2012, Paolo Capriotti
@@ -2276,7 +2449,7 @@ pem LICENSE file:
22762449
22772450pipes LICENSE file:
22782451
2279− Copyright (c) 2012-2014 Gabriel Gonzalez
2452+ Copyright (c) 2012-2016 Gabriel Gonzalez
22802453 All rights reserved.
22812454
22822455 Redistribution and use in source and binary forms, with or without modification,
@@ -2427,6 +2600,28 @@ process LICENSE file:
24272600
24282601 -----------------------------------------------------------------------------
24292602
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+
24302625random LICENSE file:
24312626
24322627 This library (libraries/base) is derived from code from two
@@ -2873,6 +3068,39 @@ streaming-commons LICENSE file:
28733068 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28743069 SOFTWARE.
28753070
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+
28763104syb LICENSE file:
28773105
28783106 This library (libraries/syb) is derived from code from several
@@ -3289,6 +3517,38 @@ unix-compat LICENSE file:
32893517 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32903518 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32913519
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+
32923552unordered-containers LICENSE file:
32933553
32943554 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 @@
11module A where
2+
3+x :: Boolean
24x = true
examples/failing/OverlappingReExport/B.purs → examples/failing/ExportConflictValue/B.pursrenamed+2
@@ -1,2 +1,4 @@
11module B where
2+
3+x :: Boolean
24x = 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
6565 input <- glob inputGlob
6666 modules <- readInput input
6767 case modules of
68− Left errs -> hPutStr stderr (P.prettyPrintMultipleErrors False errs) >> exitFailure
68+ Left errs -> hPutStr stderr (P.prettyPrintMultipleErrors P.defaultPPEOptions errs) >> exitFailure
6969 Right ms -> do
7070 for_ ms $ \(P.Module _ _ moduleName decls _) ->
7171 let name = runModuleName moduleName
psc-bundle/Main.hs+1−9
@@ -15,7 +15,7 @@ import Control.Monad.Error.Class
1515import Control.Monad.Trans.Except
1616import Control.Monad.IO.Class
1717
18−import System.FilePath (takeFileName, takeDirectory)
18+import System.FilePath (takeDirectory)
1919import System.FilePath.Glob (glob)
2020import System.Exit (exitFailure)
2121import System.IO (stderr, stdout, hPutStrLn, hSetEncoding, utf8)
@@ -37,14 +37,6 @@ data Options = Options
3737 , optionsNamespace :: String
3838 } deriving Show
3939
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−
4840-- | The main application function.
4941-- This function parses the input files, performs dead code elimination, filters empty modules
5042-- and generates and prints the final Javascript bundle.
psc-docs/Main.hs+1−1
@@ -95,7 +95,7 @@ docgen (PSCDocsOptions fmt inputGlob output) = do
9595 Right x ->
9696 return x
9797 Left err -> do
98− hPutStrLn stderr $ P.prettyPrintMultipleErrors False err
98+ hPutStrLn stderr $ P.prettyPrintMultipleErrors P.defaultPPEOptions err
9999 exitFailure
100100
101101 takeByName = takeModulesByName D.modName
psc-ide-client/Main.hs+6−16
@@ -5,16 +5,15 @@ import Prelude ()
55import Prelude.Compat
66
77import Control.Exception
8−import Data.Text (Text)
9−import qualified Data.Text as T
10−import qualified Data.Text.IO as T
11−import Data.Version (showVersion)
8+import qualified Data.ByteString.Char8 as BS8
9+import qualified Data.Text.IO as T
10+import Data.Version (showVersion)
1211import Network
1312import Options.Applicative
1413import System.Exit
1514import System.IO
1615
17−import qualified Paths_purescript as Paths
16+import qualified Paths_purescript as Paths
1817
1918data Options = Options
2019 { optionsPort :: PortID
@@ -41,16 +40,7 @@ client port = do
4140 ("Couldn't connect to psc-ide-server on port: " ++
4241 show port ++ " Error: " ++ show e) >>
4342 exitFailure)
44− cmd <- T.getLine
45− -- Temporary fix for emacs windows bug
46− let cleanedCmd = removeSurroundingTicks cmd
47− --
48− T.hPutStrLn h cleanedCmd
49− res <- T.hGetLine h
50− putStrLn (T.unpack res)
43+ T.hPutStrLn h =<< T.getLine
44+ BS8.putStrLn =<< BS8.hGetLine h
5145 hFlush stdout
5246 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 @@
1717{-# LANGUAGE OverloadedStrings #-}
1818{-# LANGUAGE PackageImports #-}
1919{-# LANGUAGE TemplateHaskell #-}
20+{-# LANGUAGE NoImplicitPrelude #-}
2021
2122module Main where
2223
23−import Prelude ()
24−import Prelude.Compat
24+import Protolude
2525
26−import Control.Concurrent (forkFinally)
26+import qualified Data.Aeson as Aeson
2727import Control.Concurrent.STM
28−import Control.Exception (bracketOnError, catchJust)
29−import Control.Monad
30−import Control.Monad.Error.Class
3128import "monad-logger" Control.Monad.Logger
32−import Control.Monad.Reader
33−import Control.Monad.Trans.Except
34−import qualified Data.Text as T
3529import qualified Data.Text.IO as T
30+import qualified Data.ByteString.Lazy.Char8 as BS8
3631import Data.Version (showVersion)
3732import Language.PureScript.Ide
3833import Language.PureScript.Ide.Util
@@ -43,19 +38,16 @@ import Network hiding (socketPort, accept)
4338import Network.BSD (getProtocolNumber)
4439import Network.Socket hiding (PortNumber, Type,
4540 sClose)
46−import Options.Applicative
41+import Options.Applicative hiding ((<>))
4742import System.Directory
4843import System.FilePath
49−import System.IO
44+import System.IO hiding (putStrLn, print)
5045import System.IO.Error (isEOFError)
5146
5247import qualified Paths_purescript as Paths
5348
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
58−listenOnLocalhost (PortNumber port) = do
49+listenOnLocalhost :: PortNumber -> IO Socket
50+listenOnLocalhost port = do
5951 proto <- getProtocolNumber "tcp"
6052 localhost <- inet_addr "127.0.0.1"
6153 bracketOnError
@@ -66,59 +58,59 @@ listenOnLocalhost (PortNumber port) = do
6658 bindSocket sock (SockAddrInet port localhost)
6759 listen sock maxListenQueue
6860 pure sock)
69−listenOnLocalhost _ = error "Wrong Porttype"
7061
7162data Options = Options
7263 { optionsDirectory :: Maybe FilePath
64+ , optionsGlobs :: [FilePath]
7365 , optionsOutputPath :: FilePath
74− , optionsPort :: PortID
66+ , optionsPort :: PortNumber
7567 , optionsNoWatch :: Bool
7668 , optionsDebug :: Bool
7769 }
7870
7971main :: IO ()
8072main = do
81− Options dir outputPath port noWatch debug <- execParser opts
73+ Options dir globs outputPath port noWatch debug <- execParser opts
8274 maybe (pure ()) setCurrentDirectory dir
83− serverState <- newTVarIO emptyPscIdeState
75+ ideState <- newTVarIO emptyIdeState
8476 cwd <- getCurrentDirectory
8577 let fullOutputPath = cwd </> outputPath
8678
87− doesDirectoryExist fullOutputPath
88− >>= flip unless
89− (do putStrLn ("Your output directory didn't exist. I'll create it at: " <> fullOutputPath)
90− createDirectory fullOutputPath
91− putStrLn "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)")
79+ unlessM (doesDirectoryExist fullOutputPath) $ do
80+ putStrLn ("Your output directory didn't exist. I'll create it at: " <> fullOutputPath)
81+ createDirectory fullOutputPath
82+ putText "This usually means you didn't compile your project yet."
83+ putText "psc-ide needs you to compile your project (for example by running pulp build)"
9384
9485 unless noWatch $
95− void (forkFinally (watcher serverState fullOutputPath) print)
86+ void (forkFinally (watcher ideState fullOutputPath) print)
9687
97− let conf = Configuration {confDebug = debug, confOutputPath = outputPath}
98− env = PscIdeEnvironment {envStateVar = serverState, envConfiguration = conf}
88+ let conf = Configuration {confDebug = debug, confOutputPath = outputPath, confGlobs = globs}
89+ env = IdeEnvironment {ideStateVar = ideState, ideConfiguration = conf}
9990 startServer port env
10091 where
10192 parser =
10293 Options
103− <$> optional (strOption (long "directory" <> short 'd'))
104− <*> strOption (long "output-directory" <> value "output/")
105− <*> (PortNumber . fromIntegral <$>
106− option auto (long "port" <> short 'p' <> value (4242 :: Integer)))
94+ <$> optional (strOption (long "directory" `mappend` short 'd'))
95+ <*> many (argument str (metavar "Source GLOBS..."))
96+ <*> strOption (long "output-directory" `mappend` value "output/")
97+ <*> (fromIntegral <$>
98+ option auto (long "port" `mappend` short 'p' `mappend` value (4242 :: Integer)))
10799 <*> switch (long "no-watch")
108100 <*> switch (long "debug")
109101 opts = info (version <*> helper <*> parser) mempty
110102 version = abortOption
111103 (InfoMsg (showVersion Paths.version))
112− (long "version" <> help "Show the version number")
104+ (long "version" `mappend` help "Show the version number")
113105
114−startServer :: PortID -> PscIdeEnvironment -> IO ()
106+startServer :: PortNumber -> IdeEnvironment -> IO ()
115107startServer port env = withSocketsDo $ do
116108 sock <- listenOnLocalhost port
117109 runLogger (runReaderT (forever (loop sock)) env)
118110 where
119− runLogger = runStdoutLoggingT . filterLogger (\_ _ -> confDebug (envConfiguration env))
111+ runLogger = runStdoutLoggingT . filterLogger (\_ _ -> confDebug (ideConfiguration env))
120112
121− loop :: (PscIde m, MonadLogger m) => Socket -> m ()
113+ loop :: (Ide m, MonadLogger m) => Socket -> m ()
122114 loop sock = do
123115 accepted <- runExceptT $ acceptCommand sock
124116 case accepted of
@@ -130,9 +122,8 @@ startServer port env = withSocketsDo $ do
130122 -- $(logDebug) ("Answer was: " <> T.pack (show result))
131123 liftIO (hFlush stdout)
132124 case result of
133− -- What function can I use to clean this up?
134− Right r -> liftIO $ T.hPutStrLn h (encodeT r)
135− Left err -> liftIO $ T.hPutStrLn h (encodeT err)
125+ Right r -> liftIO $ BS8.hPutStrLn h (Aeson.encode r)
126+ Left err -> liftIO $ BS8.hPutStrLn h (Aeson.encode err)
136127 Nothing -> do
137128 $(logDebug) ("Parsing the command failed. Command: " <> cmd)
138129 liftIO $ do
@@ -141,8 +132,8 @@ startServer port env = withSocketsDo $ do
141132 liftIO (hClose h)
142133
143134
144−acceptCommand :: (MonadIO m, MonadLogger m, MonadError T.Text m)
145− => Socket -> m (T.Text, Handle)
135+acceptCommand :: (MonadIO m, MonadLogger m, MonadError Text m)
136+ => Socket -> m (Text, Handle)
146137acceptCommand sock = do
147138 h <- acceptConnection
148139 $(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.
1414
1515**Params:**
1616 - `modules :: (optional) [ModuleName]`: A list of modules to load.
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.
17+ psc-ide-server will try to parse all the declarations in these modules
2118
2219```json
2320{
2421 "command": "load",
2522 "params": (optional) {
26− "modules": (optional)["Module.Name1", "Module.Name2"],
27− "dependencies": (optional)["Module.Name3"]
23+ "modules": (optional)["Module.Name1", "Module.Name2"]
2824 }
2925}
3026```
3127
3228**Result:**
3329
34−The Load Command returns a string.
30+The Load Command returns a string with a summary about the loading process.
3531
3632### 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.
3835
3936**Params:**
4037 - `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.
5451```
5552
5653**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+```
5875
5976### Complete
6077The `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.
1010* Vim integration is available here: https://github.com/FrigoEU/psc-ide-vim.
1111
1212## Running the Server
13−Start the server by running the `psc-ide-server` executable.
13+
14+Start the server by running the `psc-ide-server [SOURCEGLOBS]` executable, where
15+`SOURCEGLOBS` are (optional) globs that match your PureScript sourcefiles.
16+
1417It supports the following options:
1518
1619- `-p / --port` specify a port. Defaults to 4242
psc/Main.hs+6−2
@@ -11,6 +11,7 @@ import Control.Monad
1111import Control.Monad.Writer.Strict
1212
1313import qualified Data.Aeson as A
14+import Data.Bool (bool)
1415import qualified Data.ByteString.Lazy as B
1516import qualified Data.ByteString.UTF8 as BU8
1617import qualified Data.Map as M
@@ -24,6 +25,7 @@ import Options.Applicative as Opts
2425
2526import qualified Paths_purescript as Paths
2627
28+import qualified System.Console.ANSI as ANSI
2729import System.Exit (exitSuccess, exitFailure)
2830import System.FilePath.Glob (glob)
2931import System.IO (hSetEncoding, hPutStrLn, stdout, stderr, utf8)
@@ -40,11 +42,13 @@ data PSCMakeOptions = PSCMakeOptions
4042-- | Argumnets: verbose, use JSON, warnings, errors
4143printWarningsAndErrors :: Bool -> Bool -> P.MultipleErrors -> Either P.MultipleErrors a -> IO ()
4244printWarningsAndErrors 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 }
4347 when (P.nonEmpty warnings) $
44− hPutStrLn stderr (P.prettyPrintMultipleWarnings verbose warnings)
48+ hPutStrLn stderr (P.prettyPrintMultipleWarnings ppeOpts warnings)
4549 case errors of
4650 Left errs -> do
47− hPutStrLn stderr (P.prettyPrintMultipleErrors verbose errs)
51+ hPutStrLn stderr (P.prettyPrintMultipleErrors ppeOpts errs)
4852 exitFailure
4953 Right _ -> return ()
5054printWarningsAndErrors verbose True warnings errors = do
psci/Main.hs+259−27
@@ -1,9 +1,13 @@
11{-# LANGUAGE DataKinds #-}
22{-# LANGUAGE DoAndIfThenElse #-}
3+{-# LANGUAGE GADTs #-}
34{-# LANGUAGE GeneralizedNewtypeDeriving #-}
45{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE OverloadedStrings #-}
7+{-# LANGUAGE PatternGuards #-}
58{-# LANGUAGE RecordWildCards #-}
69{-# LANGUAGE ScopedTypeVariables #-}
10+{-# LANGUAGE TemplateHaskell #-}
711{-# LANGUAGE TupleSections #-}
812
913module Main (main) where
@@ -11,10 +15,22 @@ module Main (main) where
1115import Prelude ()
1216import Prelude.Compat
1317
18+import Data.FileEmbed (embedStringFile)
1419import Data.Monoid ((<>))
20+import Data.String (IsString(..))
21+import Data.Text (Text, unpack)
22+import Data.Traversable (for)
1523import Data.Version (showVersion)
1624
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)
1834import Control.Monad
1935import Control.Monad.IO.Class (liftIO)
2036import Control.Monad.Trans.Class
@@ -23,21 +39,33 @@ import Control.Monad.Trans.State.Strict (StateT, evalStateT)
2339import Control.Monad.Trans.Reader (ReaderT, runReaderT)
2440
2541import qualified Language.PureScript as P
42+import qualified Language.PureScript.Bundle as Bundle
2643import Language.PureScript.Interactive
2744
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+
2853import qualified Options.Applicative as Opts
2954
3055import qualified Paths_purescript as Paths
3156
3257import System.Console.Haskeline
58+import System.IO.UTF8 (readUTF8File)
3359import System.Exit
60+import System.FilePath ((</>))
3461import System.FilePath.Glob (glob)
62+import System.Process (readProcessWithExitCode)
3563
3664-- | Command line options
3765data PSCiOptions = PSCiOptions
3866 { psciMultiLineMode :: Bool
3967 , psciInputFile :: [FilePath]
40− , psciInputNodeFlags :: [String]
68+ , psciBackend :: Backend
4169 }
4270
4371multiLineMode :: Opts.Parser Bool
@@ -60,10 +88,21 @@ nodeFlagsFlag = Opts.option parser $
6088 where
6189 parser = words <$> Opts.str
6290
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+
63102psciOptions :: Opts.Parser PSCiOptions
64103psciOptions = PSCiOptions <$> multiLineMode
65104 <*> many inputFile
66− <*> nodeFlagsFlag
105+ <*> backend
67106
68107version :: Opts.Parser (a -> a)
69108version = Opts.abortOption (Opts.InfoMsg (showVersion Paths.version)) $
@@ -92,6 +131,195 @@ getCommand singleLineMode = handleInterrupt (return (Right Nothing)) $ do
92131 go :: [String] -> InputT m String
93132 go ls = maybe (return . unlines $ reverse ls) (go . (:ls)) =<< getInputLine " "
94133
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+
95323-- | Get command line options and drop into the REPL
96324main :: IO ()
97325main = getOpt >>= loop
@@ -106,27 +334,31 @@ main = getOpt >>= loop
106334 exitFailure
107335 (externs, env) <- ExceptT . runMake . make $ modules
108336 return (modules, externs, env)
109− case e of
110− Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> exitFailure
111− Right (modules, externs, env) -> do
112− historyFilename <- getHistoryFilename
113− let settings = defaultSettings { historyFile = Just historyFilename }
114− initialState = PSCiState [] [] (zip (map snd modules) externs)
115− config = PSCiConfig inputFiles psciInputNodeFlags env
116− runner = flip runReaderT config
117− . flip evalStateT initialState
118− . runInputT (setComplete completion settings)
119− putStrLn prologueMessage
120− runner go
121− where
122− go :: InputT (StateT PSCiState (ReaderT PSCiConfig IO)) ()
123− go = do
124− c <- getCommand (not psciMultiLineMode)
125− case c of
126− Left err -> outputStrLn err >> go
127− Right Nothing -> go
128− Right (Just QuitPSCi) -> outputStrLn quitMessage
129− Right (Just c') -> do
130− handleInterrupt (outputStrLn "Interrupted.")
131− (withInterrupt (lift (handleCommand c')))
132− go
337+ case psciBackend of
338+ Backend setup eval reload (shutdown :: state -> IO ()) -> do
339+ case e of
340+ Left errs -> putStrLn (P.prettyPrintMultipleErrors P.defaultPPEOptions errs) >> exitFailure
341+ Right (modules, externs, env) -> do
342+ historyFilename <- getHistoryFilename
343+ let settings = defaultSettings { historyFile = Just historyFilename }
344+ initialState = PSCiState [] [] (zip (map snd modules) externs)
345+ config = PSCiConfig inputFiles env
346+ runner = flip runReaderT config
347+ . flip evalStateT initialState
348+ . runInputT (setComplete completion settings)
349+
350+ go :: state -> InputT (StateT PSCiState (ReaderT PSCiConfig IO)) ()
351+ go state = do
352+ c <- getCommand (not psciMultiLineMode)
353+ case c of
354+ Left err -> outputStrLn err >> go state
355+ Right Nothing -> go state
356+ Right (Just QuitPSCi) -> do
357+ outputStrLn quitMessage
358+ liftIO $ shutdown state
359+ Right (Just c') -> do
360+ handleInterrupt (outputStrLn "Interrupted.")
361+ (withInterrupt (lift (handleCommand (liftIO . eval state) (liftIO (reload state)) c')))
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 @@
11name: purescript
2−version: 0.9.0
2+version: 0.9.2
33cabal-version: >=1.8
44build-type: Simple
55license: MIT
@@ -20,6 +20,7 @@ author: Phil Freeman <paf31@cantab.net>,
2020tested-with: GHC==7.10.3
2121
2222extra-source-files: examples/passing/*.purs
23+ , examples/passing/*.js
2324 , examples/passing/2018/*.purs
2425 , examples/passing/2138/*.purs
2526 , examples/passing/ClassRefSyntax/*.purs
@@ -59,6 +60,12 @@ extra-source-files: examples/passing/*.purs
5960 , examples/failing/ConflictingImports2/*.purs
6061 , examples/failing/ConflictingQualifiedImports/*.purs
6162 , 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
6269 , examples/failing/ExportExplicit1/*.purs
6370 , examples/failing/ExportExplicit3/*.purs
6471 , examples/failing/ImportExplicit/*.purs
@@ -67,12 +74,13 @@ extra-source-files: examples/passing/*.purs
6774 , examples/failing/ImportModule/*.purs
6875 , examples/failing/InstanceExport/*.purs
6976 , examples/failing/OrphanInstance/*.purs
70− , examples/failing/OverlappingReExport/*.purs
7177 , examples/warning/*.purs
7278 , examples/warning/*.js
7379 , examples/docs/bower_components/purescript-prelude/src/*.purs
7480 , examples/docs/bower.json
7581 , examples/docs/src/*.purs
82+ , psci/static/index.html
83+ , psci/static/index.js
7684 , tests/support/package.json
7785 , tests/support/bower.json
7886 , tests/support/setup-win.cmd
@@ -95,11 +103,13 @@ library
95103 build-depends: base >=4.8 && <5,
96104 aeson >= 0.8 && < 0.12,
97105 aeson-better-errors >= 0.8,
106+ ansi-terminal >= 0.6.2 && < 0.7,
98107 base-compat >=0.6.0,
99108 bower-json >= 0.8,
100109 boxes >= 0.1.4 && < 0.2.0,
101110 bytestring -any,
102111 containers -any,
112+ clock -any,
103113 directory >= 1.2,
104114 dlist -any,
105115 edit-distance -any,
@@ -116,9 +126,10 @@ library
116126 parallel >= 3.2 && < 3.3,
117127 parsec >=3.1.10,
118128 pattern-arrows >= 0.0.2 && < 0.1,
119− pipes >= 4.0.0 && < 4.2.0,
129+ pipes >= 4.0.0 && < 4.3.0,
120130 pipes-http -any,
121131 process >= 1.2.0 && < 1.5,
132+ protolude >= 0.1.5,
122133 regex-tdfa -any,
123134 safe >= 0.3.9 && < 0.4,
124135 semigroups >= 0.16.2 && < 0.19,
@@ -260,22 +271,23 @@ library
260271 Language.PureScript.Publish.BoxesHelpers
261272
262273 Language.PureScript.Ide
274+ Language.PureScript.Ide.CaseSplit
263275 Language.PureScript.Ide.Command
276+ Language.PureScript.Ide.Completion
277+ Language.PureScript.Ide.Conversions
264278 Language.PureScript.Ide.Externs
265279 Language.PureScript.Ide.Error
266− Language.PureScript.Ide.Pursuit
267− Language.PureScript.Ide.Completion
268− Language.PureScript.Ide.Matcher
280+ Language.PureScript.Ide.Imports
269281 Language.PureScript.Ide.Filter
270− Language.PureScript.Ide.Types
271− Language.PureScript.Ide.State
272− Language.PureScript.Ide.CaseSplit
273− Language.PureScript.Ide.SourceFile
274− Language.PureScript.Ide.Watcher
282+ Language.PureScript.Ide.Matcher
283+ Language.PureScript.Ide.Pursuit
284+ Language.PureScript.Ide.Rebuild
275285 Language.PureScript.Ide.Reexports
276− Language.PureScript.Ide.Imports
286+ Language.PureScript.Ide.SourceFile
287+ Language.PureScript.Ide.State
288+ Language.PureScript.Ide.Types
277289 Language.PureScript.Ide.Util
278− Language.PureScript.Ide.Rebuild
290+ Language.PureScript.Ide.Watcher
279291
280292 Language.PureScript.Interactive
281293 Language.PureScript.Interactive.Types
@@ -319,6 +331,7 @@ executable psc
319331 build-depends: base >=4 && <5,
320332 purescript -any,
321333 aeson >= 0.8 && < 0.12,
334+ ansi-terminal >= 0.6.2 && < 0.7,
322335 base-compat >=0.6.0,
323336 bytestring -any,
324337 containers -any,
@@ -343,18 +356,27 @@ executable psci
343356 purescript -any,
344357 base-compat >=0.6.0,
345358 boxes >= 0.1.4 && < 0.2.0,
359+ bytestring -any,
346360 containers -any,
347361 directory -any,
348362 filepath -any,
363+ file-embed -any,
349364 Glob -any,
350365 haskeline >= 0.7.0.0,
366+ http-types == 0.9.*,
351367 mtl -any,
352368 optparse-applicative >= 0.12.1,
353369 parsec -any,
354370 process -any,
371+ stm >= 0.2.4.0,
372+ text -any,
355373 time -any,
356374 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
358380 main-is: Main.hs
359381 buildable: True
360382 hs-source-dirs: psci
@@ -433,6 +455,8 @@ executable psc-ide-server
433455 other-modules: Paths_purescript
434456 other-extensions:
435457 build-depends: base >=4 && <5,
458+ aeson >= 0.8 && < 0.12,
459+ bytestring -any,
436460 purescript -any,
437461 base-compat >=0.6.0,
438462 directory -any,
@@ -441,6 +465,7 @@ executable psc-ide-server
441465 mtl -any,
442466 network -any,
443467 optparse-applicative >= 0.12.1,
468+ protolude >= 0.1.5,
444469 stm -any,
445470 text -any,
446471 transformers -any,
@@ -454,6 +479,7 @@ executable psc-ide-client
454479 other-extensions:
455480 build-depends: base >=4 && <5,
456481 base-compat >=0.6.0,
482+ bytestring -any,
457483 mtl -any,
458484 network -any,
459485 optparse-applicative >= 0.12.1,
@@ -506,6 +532,7 @@ test-suite tests
506532 optparse-applicative -any,
507533 parsec -any,
508534 process -any,
535+ protolude >= 0.1.5,
509536 silently -any,
510537 stm -any,
511538 text -any,
@@ -531,7 +558,8 @@ test-suite tests
531558 Language.PureScript.Ide.MatcherSpec
532559 Language.PureScript.Ide.RebuildSpec
533560 Language.PureScript.Ide.ReexportsSpec
534− Language.PureScript.IdeSpec
561+ Language.PureScript.Ide.SourceFile.IntegrationSpec
562+ Language.PureScript.Ide.SourceFileSpec
535563 buildable: True
536564 hs-source-dirs: tests
537565
src/Language/PureScript/AST/Declarations.hs+15−6
@@ -80,19 +80,25 @@ data DeclarationRef
8080 --
8181 | ModuleRef ModuleName
8282 -- |
83+ -- A value re-exported from another module. These will be inserted during
84+ -- elaboration in name desugaring.
85+ --
86+ | ReExportRef ModuleName DeclarationRef
87+ -- |
8388 -- A declaration reference with source position information
8489 --
8590 | PositionedDeclarationRef SourceSpan [Comment] DeclarationRef
8691 deriving (Show, Read)
8792
8893instance Eq DeclarationRef where
89− (TypeRef name dctors) == (TypeRef name' dctors') = name == name' && dctors == dctors'
90− (TypeOpRef name) == (TypeOpRef name') = name == name'
91− (ValueRef name) == (ValueRef name') = name == name'
92− (ValueOpRef name) == (ValueOpRef name') = name == name'
93− (TypeClassRef name) == (TypeClassRef name') = name == name'
94+ (TypeRef name dctors) == (TypeRef name' dctors') = name == name' && dctors == dctors'
95+ (TypeOpRef name) == (TypeOpRef name') = name == name'
96+ (ValueRef name) == (ValueRef name') = name == name'
97+ (ValueOpRef name) == (ValueOpRef name') = name == name'
98+ (TypeClassRef name) == (TypeClassRef name') = name == name'
9499 (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'
96102 (PositionedDeclarationRef _ _ r) == r' = r == r'
97103 r == (PositionedDeclarationRef _ _ r') = r == r'
98104 _ == _ = False
@@ -218,7 +224,10 @@ data ValueFixity = ValueFixity Fixity (Qualified (Either Ident (ProperName 'Cons
218224data TypeFixity = TypeFixity Fixity (Qualified (ProperName 'TypeName)) (OpName 'TypeOpName)
219225 deriving (Eq, Ord, Show, Read)
220226
227+pattern ValueFixityDeclaration :: Fixity -> Qualified (Either Ident (ProperName 'ConstructorName)) -> OpName 'ValueOpName -> Declaration
221228pattern ValueFixityDeclaration fixity name op = FixityDeclaration (Left (ValueFixity fixity name op))
229+
230+pattern TypeFixityDeclaration :: Fixity -> Qualified (ProperName 'TypeName) -> OpName 'TypeOpName -> Declaration
222231pattern TypeFixityDeclaration fixity name op = FixityDeclaration (Right (TypeFixity fixity name op))
223232
224233-- | The members of a type class instance declaration
src/Language/PureScript/Bundle.hs+39−4
@@ -6,6 +6,7 @@
66-- and generates the final Javascript bundle.
77module Language.PureScript.Bundle
88 ( bundle
9+ , guessModuleIdentifier
910 , ModuleIdentifier(..)
1011 , moduleName
1112 , ModuleType(..)
@@ -19,6 +20,7 @@ import Prelude.Compat
1920import Control.Monad
2021import Control.Monad.Error.Class
2122
23+import Data.Char (chr, digitToInt)
2224import Data.Generics (everything, everywhere, mkQ, mkT)
2325import Data.Graph
2426import Data.List (nub, stripPrefix)
@@ -31,6 +33,8 @@ import Language.JavaScript.Parser.AST
3133
3234import qualified Paths_purescript as Paths
3335
36+import System.FilePath (takeFileName, takeDirectory)
37+
3438-- | The type of error messages. We separate generation and rendering of errors using a data
3539-- type, in case we need to match on error types later.
3640data ErrorMessage
@@ -57,6 +61,14 @@ data ModuleIdentifier = ModuleIdentifier String ModuleType deriving (Show, Read,
5761moduleName :: ModuleIdentifier -> String
5862moduleName (ModuleIdentifier name _) = name
5963
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+
6072-- | A piece of code is identified by its module and its name. These keys are used to label vertices
6173-- in the dependency graph.
6274type Key = (ModuleIdentifier, String)
@@ -186,11 +198,34 @@ withDeps (Module modulePath es) = Module modulePath (map expandDeps es)
186198
187199-- String literals include the quote chars
188200fromStringLiteral :: JSExpression -> Maybe String
189−fromStringLiteral (JSStringLiteral _ str) = Just $ trimStringQuotes str
201+fromStringLiteral (JSStringLiteral _ str) = Just $ strValue str
190202fromStringLiteral _ = Nothing
191203
192−trimStringQuotes :: String -> String
193−trimStringQuotes str = reverse $ drop 1 $ reverse $ drop 1 $ str
204+strValue :: String -> String
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 "" = ""
194229
195230commaList :: JSCommaList a -> [a]
196231commaList JSLNil = []
@@ -332,7 +367,7 @@ matchExportsAssignment stmt
332367 = Nothing
333368
334369extractLabel :: JSPropertyName -> Maybe String
335−extractLabel (JSPropertyString _ nm) = Just (trimStringQuotes nm)
370+extractLabel (JSPropertyString _ nm) = Just $ strValue nm
336371extractLabel (JSPropertyIdent _ nm) = Just nm
337372extractLabel _ = Nothing
338373
src/Language/PureScript/CodeGen/JS/Optimizer.hs+2−2
@@ -39,12 +39,12 @@ import qualified Language.PureScript.Constants as C
3939-- |
4040-- Apply a series of optimizer passes to simplified Javascript code
4141--
42−optimize :: (Monad m, MonadReader Options m, MonadSupply m) => JS -> m JS
42+optimize :: (MonadReader Options m, MonadSupply m) => JS -> m JS
4343optimize js = do
4444 noOpt <- asks optionsNoOptimizations
4545 if noOpt then return js else optimize' js
4646
47−optimize' :: (Monad m, MonadReader Options m, MonadSupply m) => JS -> m JS
47+optimize' :: (MonadReader Options m, MonadSupply m) => JS -> m JS
4848optimize' js = do
4949 opts <- ask
5050 js' <- untilFixedPoint (inlineFnComposition . tidyUp . applyAll
src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs+1−1
@@ -216,7 +216,7 @@ inlineCommonOperators = applyAll $
216216
217217 isNFn :: String -> Int -> JS -> Bool
218218 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)
220220 isNFn _ _ _ = False
221221
222222 runFn :: Int -> JS -> JS
src/Language/PureScript/Constants.hs+6
@@ -327,6 +327,9 @@ partial = "Partial"
327327pattern Partial :: Qualified (ProperName 'ClassName)
328328pattern Partial = Qualified (Just (ModuleName [ProperName "Prim"])) (ProperName "Partial")
329329
330+pattern Fail :: Qualified (ProperName 'ClassName)
331+pattern Fail = Qualified (Just (ModuleName [ProperName "Prim"])) (ProperName "Fail")
332+
330333-- Code Generation
331334
332335__superclass_ :: String
@@ -388,5 +391,8 @@ dataEuclideanRing = "Data_EuclideanRing"
388391dataFunction :: String
389392dataFunction = "Data_Function"
390393
394+dataFunctionUncurried :: String
395+dataFunctionUncurried = "Data_Function_Uncurried"
396+
391397dataIntBits :: String
392398dataIntBits = "Data_Int_Bits"
src/Language/PureScript/Docs/ParseAndBookmark.hs+1−1
@@ -44,7 +44,7 @@ parseAndBookmark inputFiles depsFiles = do
4444 addBookmarks <$> parseFiles (inputFiles' ++ depsFiles')
4545
4646parseFiles ::
47− (MonadError P.MultipleErrors m, MonadIO m) =>
47+ (MonadError P.MultipleErrors m) =>
4848 [(FileInfo, FilePath)]
4949 -> m [(FileInfo, P.Module)]
5050parseFiles =
src/Language/PureScript/Environment.hs+4−1
@@ -240,6 +240,7 @@ primTypes =
240240 , (primName "Int", (Star, ExternData))
241241 , (primName "Boolean", (Star, ExternData))
242242 , (primName "Partial", (Star, ExternData))
243+ , (primName "Fail", (FunKind Symbol Star, ExternData))
243244 ]
244245
245246-- |
@@ -249,7 +250,9 @@ primTypes =
249250primClasses :: M.Map (Qualified (ProperName 'ClassName)) ([(String, Maybe Kind)], [(Ident, Type)], [Constraint])
250251primClasses =
251252 M.fromList
252− [ (primName "Partial", ([], [], [])) ]
253+ [ (primName "Partial", ([], [], []))
254+ , (primName "Fail", ([("message", Just Symbol)], [], []))
255+ ]
253256
254257-- |
255258-- Finds information about data constructors from the current environment.
src/Language/PureScript/Errors.hs+285−226
@@ -15,7 +15,7 @@ import Data.Char (isSpace)
1515import Data.Either (lefts, rights)
1616import Data.Foldable (fold)
1717import Data.List (intercalate, transpose, nub, nubBy, sortBy, partition)
18−import Data.Maybe (maybeToList)
18+import Data.Maybe (maybeToList, fromMaybe, mapMaybe)
1919import Data.Ord (comparing)
2020import qualified Data.Map as M
2121
@@ -26,9 +26,12 @@ import Language.PureScript.Names
2626import Language.PureScript.Pretty
2727import Language.PureScript.Traversals
2828import Language.PureScript.Types
29+import Language.PureScript.Pretty.Common (endWith)
2930import qualified Language.PureScript.Bundle as Bundle
3031import qualified Language.PureScript.Constants as C
3132
33+import qualified System.Console.ANSI as ANSI
34+
3235import qualified Text.Parsec as P
3336import qualified Text.Parsec.Error as PE
3437import qualified Text.PrettyPrint.Boxes as Box
@@ -62,17 +65,9 @@ data SimpleErrorMessage
6265 | UnknownExportDataConstructor (ProperName 'TypeName) (ProperName 'ConstructorName)
6366 | ScopeConflict Name [ModuleName]
6467 | ScopeShadowing Name (Maybe ModuleName) [ModuleName]
65− | ConflictingTypeDecls (ProperName 'TypeName)
66− | ConflictingCtorDecls (ProperName 'ConstructorName)
67− | TypeConflictsWithClass (ProperName 'TypeName)
68− | CtorConflictsWithClass (ProperName 'ConstructorName)
69− | ClassConflictsWithType (ProperName 'ClassName)
70− | ClassConflictsWithCtor (ProperName 'ClassName)
68+ | DeclConflict Name Name
69+ | ExportConflict (Qualified Name) (Qualified Name)
7170 | DuplicateModuleName ModuleName
72− | DuplicateClassExport (ProperName 'ClassName)
73− | DuplicateValueExport Ident
74− | DuplicateValueOpExport (OpName 'ValueOpName)
75− | DuplicateTypeOpExport (OpName 'TypeOpName)
7671 | DuplicateTypeArgument String
7772 | InvalidDoBind
7873 | InvalidDoLet
@@ -231,17 +226,9 @@ errorCode em = case unwrapErrorMessage em of
231226 UnknownExportDataConstructor{} -> "UnknownExportDataConstructor"
232227 ScopeConflict{} -> "ScopeConflict"
233228 ScopeShadowing{} -> "ScopeShadowing"
234− ConflictingTypeDecls{} -> "ConflictingTypeDecls"
235− ConflictingCtorDecls{} -> "ConflictingCtorDecls"
236− TypeConflictsWithClass{} -> "TypeConflictsWithClass"
237− CtorConflictsWithClass{} -> "CtorConflictsWithClass"
238− ClassConflictsWithType{} -> "ClassConflictsWithType"
239− ClassConflictsWithCtor{} -> "ClassConflictsWithCtor"
229+ DeclConflict{} -> "DeclConflict"
230+ ExportConflict{} -> "ExportConflict"
240231 DuplicateModuleName{} -> "DuplicateModuleName"
241− DuplicateClassExport{} -> "DuplicateClassExport"
242− DuplicateValueExport{} -> "DuplicateValueExport"
243− DuplicateValueOpExport{} -> "DuplicateValueOpExport"
244− DuplicateTypeOpExport{} -> "DuplicateTypeOpExport"
245232 DuplicateTypeArgument{} -> "DuplicateTypeArgument"
246233 InvalidDoBind -> "InvalidDoBind"
247234 InvalidDoLet -> "InvalidDoLet"
@@ -435,7 +422,7 @@ errorSuggestion err = case err of
435422
436423 importSuggestion :: ModuleName -> [ DeclarationRef ] -> Maybe ModuleName -> String
437424 importSuggestion mn refs qual =
438− "import " ++ runModuleName mn ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ")" ++ qstr qual
425+ "import " ++ runModuleName mn ++ " (" ++ intercalate ", " (mapMaybe prettyPrintRef refs) ++ ")" ++ qstr qual
439426
440427 qstr :: Maybe ModuleName -> String
441428 qstr (Just mn) = " as " ++ runModuleName mn
@@ -457,15 +444,65 @@ showSuggestion suggestion = case errorSuggestion suggestion of
457444 Just (ErrorSuggestion x) -> x
458445 _ -> ""
459446
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+
460496-- |
461497-- Pretty print a single error, simplifying if necessary
462498--
463−prettyPrintSingleError :: Bool -> Level -> Bool -> ErrorMessage -> Box.Box
464−prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap $ do
499+prettyPrintSingleError :: PPEOptions -> ErrorMessage -> Box.Box
500+prettyPrintSingleError (PPEOptions codeColor full level showWiki) e = flip evalState defaultUnknownMap $ do
465501 em <- onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
466502 um <- get
467503 return (prettyPrintErrorMessage um em)
468504 where
505+ (markCode, markCodeBox) = (colorCode &&& colorCodeBox) codeColor
469506
470507 -- Pretty print an ErrorMessage
471508 prettyPrintErrorMessage :: TypeMap -> ErrorMessage -> Box.Box
@@ -474,9 +511,10 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
474511 [ foldr renderHint (indent (renderSimpleErrorMessage simple)) hints
475512 ] ++
476513 maybe [] (return . Box.moveDown 1) typeInformation ++
477− [ Box.moveDown 1 $ paras [ line $ "See " ++ wikiUri e ++ " for more information, "
478− , line $ "or to contribute content related to this " ++ levelText ++ "."
479− ]
514+ [ Box.moveDown 1 $ paras
515+ [ line $ "See " ++ wikiUri e ++ " for more information, "
516+ , line $ "or to contribute content related to this " ++ levelText ++ "."
517+ ]
480518 | showWiki
481519 ]
482520 where
@@ -491,11 +529,11 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
491529 skolemInfo :: (String, Int, Maybe SourceSpan) -> Box.Box
492530 skolemInfo (name, s, ss) =
493531 paras $
494− line (name ++ show s ++ " is a rigid type variable")
532+ line (markCode (name ++ show s) ++ " is a rigid type variable")
495533 : foldMap (return . line . (" bound at " ++) . displayStartEndPos) ss
496534
497535 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"
499537
500538 renderSimpleErrorMessage :: SimpleErrorMessage -> Box.Box
501539 renderSimpleErrorMessage (CannotGetFileInfo path) =
@@ -520,29 +558,29 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
520558 , prettyPrintParseError err
521559 ]
522560 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."
524562 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) ++ ": "
526564 , 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."
528566 ]
529567 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) ++ ": "
531569 , indent . paras $ map (line . runIdent) idents
532570 ]
533571 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: "
535573 , indent . paras $ map (line . runIdent) idents
536574 ]
537575 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) ++ ":"
539577 , indent . paras $
540− [ line $ "The identifier `" ++ ident ++ "` is not valid in PureScript."
578+ [ line $ "The identifier " ++ markCode ident ++ " is not valid in PureScript."
541579 , line "Note that exported identifiers in FFI modules must be valid PureScript identifiers."
542580 ]
543581 ]
544582 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) ++ ": "
546584 , indent . paras $ map line paths
547585 ]
548586 renderSimpleErrorMessage InvalidDoBind =
@@ -553,94 +591,78 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
553591 line "The same name was used more than once in a let binding."
554592 renderSimpleErrorMessage (InfiniteType ty) =
555593 paras [ line "An infinite type was inferred for an expression: "
556− , indent $ typeAsBox ty
594+ , markCodeBox $ indent $ typeAsBox ty
557595 ]
558596 renderSimpleErrorMessage (InfiniteKind ki) =
559597 paras [ line "An infinite kind was inferred for a type: "
560− , indent $ line $ prettyPrintKind ki
598+ , indent $ line $ markCode $ prettyPrintKind ki
561599 ]
562600 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)
564602 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)
566604 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."
568606 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:")
570608 , indent . paras $ map (line . displaySourceSpan) filenames
571609 ]
572610 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"
574612 renderSimpleErrorMessage (UnknownName name) =
575613 line $ "Unknown " ++ printName name
576614 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)
578616 , line "It either does not exist or the module does not export it."
579617 ]
580618 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)
582620 renderSimpleErrorMessage (UnknownExport name) =
583621 line $ "Cannot export unknown " ++ printName (Qualified Nothing name)
584622 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."
586624 renderSimpleErrorMessage (ScopeConflict nm ms) =
587625 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
589627 ]
590628 renderSimpleErrorMessage (ScopeShadowing nm exmn ms) =
591629 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
593631 , 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."
595633 Nothing -> "local declaration will be used."
596634 ]
597− renderSimpleErrorMessage (ConflictingTypeDecls nm) =
598− line $ "Conflicting type declarations for " ++ runProperName nm
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) =
606− line $ "Type class " ++ runProperName nm ++ " conflicts with a type declaration with the same name."
607− renderSimpleErrorMessage (ClassConflictsWithCtor nm) =
608− line $ "Type class " ++ runProperName nm ++ " conflicts with a data constructor declaration with the same name."
635+ renderSimpleErrorMessage (DeclConflict new existing) =
636+ line $ "Declaration for " ++ printName (Qualified Nothing new) ++ " conflicts with an existing " ++ nameType existing ++ " of the same name."
637+ renderSimpleErrorMessage (ExportConflict new existing) =
638+ line $ "Export for " ++ printName new ++ " conflicts with " ++ runName existing
609639 renderSimpleErrorMessage (DuplicateModuleName mn) =
610− line $ "Module " ++ 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
640+ line $ "Module " ++ markCode (runModuleName mn) ++ " has been defined multiple times."
619641 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."
621643 renderSimpleErrorMessage (CycleInModules mns) =
622644 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)
624646 ]
625647 renderSimpleErrorMessage (CycleInTypeSynonym name) =
626648 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)
628650 Nothing -> "A cycle appears in a set of type synonym definitions."
629651 , line "Cycles are disallowed because they can lead to loops in the type checker."
630652 , line "Consider using a 'newtype' instead."
631653 ]
632654 renderSimpleErrorMessage (NameIsUndefined ident) =
633− line $ "Value " ++ showIdent ident ++ " is undefined."
655+ line $ "Value " ++ markCode (showIdent ident) ++ " is undefined."
634656 renderSimpleErrorMessage (UndefinedTypeVariable name) =
635− line $ "Type variable " ++ runProperName name ++ " is undefined."
657+ line $ "Type variable " ++ markCode (runProperName name) ++ " is undefined."
636658 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."
638660 , line "Type synonyms must be applied to all of their type arguments."
639661 ]
640662 renderSimpleErrorMessage (EscapedSkolem binding) =
641663 paras $ [ line "A type variable has escaped its scope." ]
642664 <> foldMap (\expr -> [ line "Relevant expression: "
643− , indent $ prettyPrintValue valueDepth expr
665+ , markCodeBox $ indent $ prettyPrintValue valueDepth expr
644666 ]) binding
645667 renderSimpleErrorMessage (TypesDoNotUnify u1 u2)
646668 = let (sorted1, sorted2) = sortRows u1 u2
@@ -662,34 +684,39 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
662684 , rowFromList (sortBy (comparing fst) sd2 ++ map (fst &&& snd . snd) common, r2)
663685 )
664686 in paras [ line "Could not match type"
665− , indent $ typeAsBox sorted1
687+ , markCodeBox $ indent $ typeAsBox sorted1
666688 , line "with type"
667− , indent $ typeAsBox sorted2
689+ , markCodeBox $ indent $ typeAsBox sorted2
668690 ]
669691
670692 renderSimpleErrorMessage (KindsDoNotUnify k1 k2) =
671693 paras [ line "Could not match kind"
672− , indent $ line $ prettyPrintKind k1
694+ , indent $ line $ markCode $ prettyPrintKind k1
673695 , line "with kind"
674− , indent $ line $ prettyPrintKind k2
696+ , indent $ line $ markCode $ prettyPrintKind k2
675697 ]
676698 renderSimpleErrorMessage (ConstrainedTypeUnified t1 t2) =
677699 paras [ line "Could not match constrained type"
678− , indent $ typeAsBox t1
700+ , markCodeBox $ indent $ typeAsBox t1
679701 , line "with type"
680− , indent $ typeAsBox t2
702+ , markCodeBox $ indent $ typeAsBox t2
681703 ]
682704 renderSimpleErrorMessage (OverlappingInstances nm ts (d : ds)) =
683705 paras [ line "Overlapping type class instances found for"
684− , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
685− , Box.vcat Box.left (map typeAtomAsBox ts)
686− ]
706+ , markCodeBox $ indent $ Box.hsep 1 Box.left
707+ [ line (showQualified runProperName nm)
708+ , Box.vcat Box.left (map typeAtomAsBox ts)
709+ ]
687710 , line "The following instances were found:"
688711 , indent $ paras (line (showQualified showIdent d ++ " (chosen)") : map (line . showQualified showIdent) ds)
689712 , line "Overlapping type class instances can lead to different behavior based on the order of module imports, and for that reason are not recommended."
690713 , line "They may be disallowed completely in a future version of the compiler."
691714 ]
692715 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+ ]
693720 renderSimpleErrorMessage (NoInstanceFound (Constraint C.Partial
694721 _
695722 (Just (PartialConstraintData bs b)))) =
@@ -697,15 +724,16 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
697724 , line "The following additional cases are required to cover all inputs:\n"
698725 , indent $ paras $
699726 Box.hsep 1 Box.left
700− (map (paras . map line) (transpose bs))
727+ (map (paras . map (line . markCode)) (transpose bs))
701728 : [line "..." | not b]
702729 , line "Alternatively, add a Partial constraint to the type of the enclosing value."
703730 ]
704731 renderSimpleErrorMessage (NoInstanceFound (Constraint nm ts _)) =
705732 paras [ line "No type class instance was found for"
706− , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
707− , Box.vcat Box.left (map typeAtomAsBox ts)
708− ]
733+ , markCodeBox $ indent $ Box.hsep 1 Box.left
734+ [ line (showQualified runProperName nm)
735+ , Box.vcat Box.left (map typeAtomAsBox ts)
736+ ]
709737 , paras [ line "The instance head contains unknown type variables. Consider adding a type annotation."
710738 | any containsUnknowns ts
711739 ]
@@ -718,125 +746,128 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
718746 go _ = False
719747 renderSimpleErrorMessage (PossiblyInfiniteInstance nm ts) =
720748 paras [ line "Type class instance for"
721− , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
722− , Box.vcat Box.left (map typeAtomAsBox ts)
723− ]
749+ , markCodeBox $ indent $ Box.hsep 1 Box.left
750+ [ line (showQualified runProperName nm)
751+ , Box.vcat Box.left (map typeAtomAsBox ts)
752+ ]
724753 , line "is possibly infinite."
725754 ]
726755 renderSimpleErrorMessage (CannotDerive nm ts) =
727756 paras [ line "Cannot derive a type class instance for"
728− , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName nm)
729− , Box.vcat Box.left (map typeAtomAsBox ts)
730− ]
757+ , markCodeBox $ indent $ Box.hsep 1 Box.left
758+ [ line (showQualified runProperName nm)
759+ , Box.vcat Box.left (map typeAtomAsBox ts)
760+ ]
731761 ]
732762 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."
734764 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." ]
736766 <> foldMap (\expr' -> [ line "Relevant expression: "
737− , indent $ prettyPrintValue valueDepth expr'
767+ , markCodeBox $ indent $ prettyPrintValue valueDepth expr'
738768 ]) expr
739769 renderSimpleErrorMessage (DuplicateTypeArgument name) =
740− line $ "Type argument " ++ show name ++ " appears more than once."
770+ line $ "Type argument " ++ markCode name ++ " appears more than once."
741771 renderSimpleErrorMessage (DuplicateValueDeclaration nm) =
742− line $ "Multiple value declarations exist for " ++ showIdent nm ++ "."
772+ line $ "Multiple value declarations exist for " ++ markCode (showIdent nm) ++ "."
743773 renderSimpleErrorMessage (ArgListLengthsDiffer ident) =
744− line $ "Argument list lengths differ in declaration " ++ showIdent ident
774+ line $ "Argument list lengths differ in declaration " ++ markCode (showIdent ident)
745775 renderSimpleErrorMessage (OverlappingArgNames ident) =
746776 line $ "Overlapping names in function/binder" ++ foldMap ((" in declaration " ++) . showIdent) ident
747777 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."
749779 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)
751781 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 "*" ++ "."
753783 , line "The error arises from the type"
754− , indent $ typeAsBox ty
784+ , markCodeBox $ indent $ typeAsBox ty
755785 , line "having the kind"
756− , indent $ line $ prettyPrintKind kind
786+ , indent $ line $ markCode $ prettyPrintKind kind
757787 , line "instead."
758788 ]
759789 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."
761791 renderSimpleErrorMessage (ExprDoesNotHaveType expr ty) =
762792 paras [ line "Expression"
763− , indent $ prettyPrintValue valueDepth expr
793+ , markCodeBox $ indent $ prettyPrintValue valueDepth expr
764794 , line "does not have type"
765− , indent $ typeAsBox ty
795+ , markCodeBox $ indent $ typeAsBox ty
766796 ]
767797 renderSimpleErrorMessage (PropertyIsMissing prop) =
768− line $ "Type of expression lacks required label " ++ show prop ++ "."
798+ line $ "Type of expression lacks required label " ++ markCode prop ++ "."
769799 renderSimpleErrorMessage (AdditionalProperty prop) =
770− line $ "Type of expression contains additional label " ++ show prop ++ "."
800+ line $ "Type of expression contains additional label " ++ markCode prop ++ "."
771801 renderSimpleErrorMessage (CannotApplyFunction fn arg) =
772802 paras [ line "A function of type"
773− , indent $ typeAsBox fn
803+ , markCodeBox $ indent $ typeAsBox fn
774804 , line "can not be applied to the argument"
775− , indent $ prettyPrintValue valueDepth arg
805+ , markCodeBox $ indent $ prettyPrintValue valueDepth arg
776806 ]
777807 renderSimpleErrorMessage TypeSynonymInstance =
778808 line "Type class instances for type synonyms are disallowed."
779809 renderSimpleErrorMessage (OrphanInstance nm cnm ts) =
780− paras [ line $ "Type class instance " ++ showIdent nm ++ " for "
781− , indent $ Box.hsep 1 Box.left [ line (showQualified runProperName cnm)
782− , Box.vcat Box.left (map typeAtomAsBox ts)
783− ]
810+ paras [ line $ "Type class instance " ++ markCode (showIdent nm) ++ " for "
811+ , markCodeBox $ indent $ Box.hsep 1 Box.left
812+ [ line (showQualified runProperName cnm)
813+ , Box.vcat Box.left (map typeAtomAsBox ts)
814+ ]
784815 , line "is an orphan instance."
785816 , line "An orphan instance is an instance which is defined in neither the class module nor the data type module."
786817 , line "Consider moving the instance, if possible, or using a newtype wrapper."
787818 ]
788819 renderSimpleErrorMessage (InvalidNewtype name) =
789− paras [ line $ "Newtype " ++ runProperName name ++ " is invalid."
820+ paras [ line $ "Newtype " ++ markCode (runProperName name) ++ " is invalid."
790821 , line "Newtypes must define a single constructor with a single argument."
791822 ]
792823 renderSimpleErrorMessage (InvalidInstanceHead ty) =
793824 paras [ line "Type class instance head is invalid due to use of type"
794− , indent $ typeAsBox ty
825+ , markCodeBox $ indent $ typeAsBox ty
795826 , 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."
796827 ]
797828 renderSimpleErrorMessage (TransitiveExportError x ys) =
798− paras [ line $ "An export for " ++ prettyPrintExport x ++ " requires the following to also be exported: "
799− , indent $ paras $ map (line . prettyPrintExport) ys
829+ paras [ line $ "An export for " ++ markCode (prettyPrintExport x) ++ " requires the following to also be exported: "
830+ , indent $ paras $ map (line . markCode . prettyPrintExport) ys
800831 ]
801832 renderSimpleErrorMessage (TransitiveDctorExportError x ctor) =
802− paras [ line $ "An export for " ++ prettyPrintExport x ++ " requires the following data constructor to also be exported: "
803− , indent $ line $ runProperName ctor
833+ paras [ line $ "An export for " ++ markCode (prettyPrintExport x) ++ " requires the following data constructor to also be exported: "
834+ , indent $ line $ markCode $ runProperName ctor
804835 ]
805836 renderSimpleErrorMessage (ShadowedName nm) =
806− line $ "Name '" ++ showIdent nm ++ "' was shadowed."
837+ line $ "Name " ++ markCode (showIdent nm) ++ " was shadowed."
807838 renderSimpleErrorMessage (ShadowedTypeVar tv) =
808− line $ "Type variable '" ++ tv ++ "' was shadowed."
839+ line $ "Type variable " ++ markCode tv ++ " was shadowed."
809840 renderSimpleErrorMessage (UnusedTypeVar tv) =
810− line $ "Type variable '" ++ tv ++ "' was declared but not used."
841+ line $ "Type variable " ++ markCode tv ++ " was declared but not used."
811842 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."
813844 renderSimpleErrorMessage (ImportHidingModule name) =
814− paras [ line "'hiding' imports cannot be used to hide modules."
815− , line $ "An attempt was made to hide the import of " ++ runModuleName name
845+ paras [ line "hiding imports cannot be used to hide modules."
846+ , line $ "An attempt was made to hide the import of " ++ markCode (runModuleName name)
816847 ]
817848 renderSimpleErrorMessage (WildcardInferredType ty) =
818849 paras [ line "Wildcard type definition has the inferred type "
819− , indent $ typeAsBox ty
850+ , markCodeBox $ indent $ typeAsBox ty
820851 ]
821852 renderSimpleErrorMessage (HoleInferredType name ty env) =
822− paras $ [ line $ "Hole '" ++ name ++ "' has the inferred type "
823− , indent $ typeAsBox ty
853+ paras $ [ line $ "Hole '" ++ markCode name ++ "' has the inferred type "
854+ , markCodeBox $ indent $ typeAsBox ty
824855 ] ++ if null env then [] else envInfo
825856 where
826857 envInfo :: [Box.Box]
827858 envInfo = [ line "in the following context:"
828859 , indent $ paras
829860 [ Box.hcat Box.left [ Box.text (showIdent ident <> " :: ")
830− , typeAsBox ty'
861+ , markCodeBox $ typeAsBox ty'
831862 ]
832863 | (ident, ty') <- take 5 env
833864 ]
834865 ]
835866 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) ++ "."
837868 , line "It is good practice to provide type declarations as a form of documentation."
838− , line $ "The inferred type of " ++ showIdent ident ++ " was:"
839− , indent $ typeAsBox ty
869+ , line $ "The inferred type of " ++ markCode (showIdent ident) ++ " was:"
870+ , markCodeBox $ indent $ typeAsBox ty
840871 ]
841872 renderSimpleErrorMessage (OverlappingPattern bs b) =
842873 paras $ [ line "A case expression contains unreachable cases:\n"
@@ -848,26 +879,26 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
848879 , line "You may want to decompose your data types into smaller types."
849880 ]
850881 renderSimpleErrorMessage (UnusedImport name) =
851− line $ "The import of module " ++ runModuleName name ++ " is redundant"
882+ line $ "The import of module " ++ markCode (runModuleName name) ++ " is redundant"
852883
853884 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:"
855886 , indent $ paras $ map line names
856887 , line "It could be replaced with:"
857− , indent $ line $ showSuggestion msg ]
888+ , indent $ line $ markCode $ showSuggestion msg ]
858889
859890 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"
861892
862893 renderSimpleErrorMessage (UnusedDctorExplicitImport name names) =
863− paras [ line $ "The import of type " ++ runProperName name ++ " includes the following unused data constructors:"
864− , indent $ paras $ map (line .runProperName) names ]
894+ paras [ line $ "The import of type " ++ markCode (runProperName name) ++ " includes the following unused data constructors:"
895+ , indent $ paras $ map (line . markCode . runProperName) names ]
865896
866897 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"
868899
869900 renderSimpleErrorMessage (DuplicateImport name imp qual) =
870− line $ "Duplicate import of " ++ prettyPrintImport name imp qual
901+ line $ "Duplicate import of " ++ markCode (prettyPrintImport name imp qual)
871902
872903 renderSimpleErrorMessage (DuplicateImportRef name) =
873904 line $ "Import list contains multiple references to " ++ printName (Qualified Nothing name)
@@ -876,23 +907,23 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
876907 line $ "Export list contains multiple references to " ++ printName (Qualified Nothing name)
877908
878909 renderSimpleErrorMessage (IntOutOfRange value backend lo hi) =
879− paras [ line $ "Integer value " ++ show value ++ " is out of range for the " ++ backend ++ " backend."
880− , line $ "Acceptable values fall within the range " ++ show lo ++ " to " ++ show hi ++ " (inclusive)." ]
910+ paras [ line $ "Integer value " ++ markCode (show value) ++ " is out of range for the " ++ backend ++ " backend."
911+ , line $ "Acceptable values fall within the range " ++ markCode (show lo) ++ " to " ++ markCode (show hi) ++ " (inclusive)." ]
881912
882913 renderSimpleErrorMessage msg@(ImplicitQualifiedImport importedModule asModule _) =
883− paras [ line $ "Module " ++ runModuleName importedModule ++ " was imported as " ++ runModuleName asModule ++ " with unspecified imports."
884− , line $ "As there are multiple modules being imported as " ++ runModuleName asModule ++ ", consider using the explicit form:"
885− , indent $ line $ showSuggestion msg
914+ paras [ line $ "Module " ++ markCode (runModuleName importedModule) ++ " was imported as " ++ markCode (runModuleName asModule) ++ " with unspecified imports."
915+ , line $ "As there are multiple modules being imported as " ++ markCode (runModuleName asModule) ++ ", consider using the explicit form:"
916+ , indent $ line $ markCode $ showSuggestion msg
886917 ]
887918
888919 renderSimpleErrorMessage msg@(ImplicitImport mn _) =
889− paras [ line $ "Module " ++ runModuleName mn ++ " has unspecified imports, consider using the explicit form: "
890− , indent $ line $ showSuggestion msg
920+ paras [ line $ "Module " ++ markCode (runModuleName mn) ++ " has unspecified imports, consider using the explicit form: "
921+ , indent $ line $ markCode $ showSuggestion msg
891922 ]
892923
893924 renderSimpleErrorMessage msg@(HidingImport mn _) =
894− paras [ line $ "Module " ++ runModuleName mn ++ " has unspecified imports, consider using the inclusive form: "
895− , indent $ line $ showSuggestion msg
925+ paras [ line $ "Module " ++ markCode (runModuleName mn) ++ " has unspecified imports, consider using the inclusive form: "
926+ , indent $ line $ markCode $ showSuggestion msg
896927 ]
897928
898929 renderSimpleErrorMessage (CaseBinderLengthDiffers l bs) =
@@ -905,7 +936,7 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
905936 line "An anonymous function argument appears in an invalid context."
906937
907938 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 ++ "."
909940 , line "Only aliases for data constructors may be used in patterns."
910941 ]
911942
@@ -913,9 +944,9 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
913944 line "The require-path option is deprecated and will be removed in PureScript 0.9."
914945
915946 renderSimpleErrorMessage (CannotGeneralizeRecursiveFunction ident ty) =
916− paras [ line $ "Unable to generalize the type of the recursive function " ++ showIdent ident ++ "."
917− , line $ "The inferred type of " ++ showIdent ident ++ " was:"
918− , indent $ typeAsBox ty
947+ paras [ line $ "Unable to generalize the type of the recursive function " ++ markCode (showIdent ident) ++ "."
948+ , line $ "The inferred type of " ++ markCode (showIdent ident) ++ " was:"
949+ , markCodeBox $ indent $ typeAsBox ty
919950 , line "Try adding a type signature."
920951 ]
921952
@@ -923,42 +954,43 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
923954 renderHint (ErrorUnifyingTypes t1 t2) detail =
924955 paras [ detail
925956 , Box.hsep 1 Box.top [ line "while trying to match type"
926− , typeAsBox t1
957+ , markCodeBox $ typeAsBox t1
927958 ]
928959 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "with type"
929− , typeAsBox t2
960+ , markCodeBox $ typeAsBox t2
930961 ]
931962 ]
932963 renderHint (ErrorInExpression expr) detail =
933964 paras [ detail
934965 , Box.hsep 1 Box.top [ Box.text "in the expression"
935− , prettyPrintValue valueDepth expr
966+ , markCodeBox $ markCodeBox $ prettyPrintValue valueDepth expr
936967 ]
937968 ]
938969 renderHint (ErrorInModule mn) detail =
939− paras [ line $ "in module " ++ runModuleName mn
970+ paras [ line $ "in module " ++ markCode (runModuleName mn)
940971 , detail
941972 ]
942973 renderHint (ErrorInSubsumption t1 t2) detail =
943974 paras [ detail
944975 , Box.hsep 1 Box.top [ line "while checking that type"
945− , typeAsBox t1
976+ , markCodeBox $ typeAsBox t1
946977 ]
947978 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "is at least as general as type"
948− , typeAsBox t2
979+ , markCodeBox $ typeAsBox t2
949980 ]
950981 ]
951982 renderHint (ErrorInInstance nm ts) detail =
952983 paras [ detail
953− , Box.hsep 1 Box.top [ line "in type class instance"
954− , line (showQualified runProperName nm)
955− , Box.vcat Box.left (map typeAtomAsBox ts)
956− ]
984+ , line "in type class instance"
985+ , markCodeBox $ indent $ Box.hsep 1 Box.top
986+ [ line $ showQualified runProperName nm
987+ , Box.vcat Box.left (map typeAtomAsBox ts)
988+ ]
957989 ]
958990 renderHint (ErrorCheckingKind ty) detail =
959991 paras [ detail
960992 , Box.hsep 1 Box.top [ line "while checking the kind of"
961− , typeAsBox ty
993+ , markCodeBox $ typeAsBox ty
962994 ]
963995 ]
964996 renderHint ErrorCheckingGuard detail =
@@ -968,43 +1000,43 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
9681000 renderHint (ErrorInferringType expr) detail =
9691001 paras [ detail
9701002 , Box.hsep 1 Box.top [ line "while inferring the type of"
971− , prettyPrintValue valueDepth expr
1003+ , markCodeBox $ prettyPrintValue valueDepth expr
9721004 ]
9731005 ]
9741006 renderHint (ErrorCheckingType expr ty) detail =
9751007 paras [ detail
9761008 , Box.hsep 1 Box.top [ line "while checking that expression"
977− , prettyPrintValue valueDepth expr
1009+ , markCodeBox $ prettyPrintValue valueDepth expr
9781010 ]
9791011 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "has type"
980− , typeAsBox ty
1012+ , markCodeBox $ typeAsBox ty
9811013 ]
9821014 ]
9831015 renderHint (ErrorCheckingAccessor expr prop) detail =
9841016 paras [ detail
9851017 , 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)
9871019 ]
9881020 ]
9891021 renderHint (ErrorInApplication f t a) detail =
9901022 paras [ detail
9911023 , Box.hsep 1 Box.top [ line "while applying a function"
992− , prettyPrintValue valueDepth f
1024+ , markCodeBox $ prettyPrintValue valueDepth f
9931025 ]
9941026 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "of type"
995− , typeAsBox t
1027+ , markCodeBox $ typeAsBox t
9961028 ]
9971029 , Box.moveRight 2 $ Box.hsep 1 Box.top [ line "to argument"
998− , prettyPrintValue valueDepth a
1030+ , markCodeBox $ prettyPrintValue valueDepth a
9991031 ]
10001032 ]
10011033 renderHint (ErrorInDataConstructor nm) detail =
10021034 paras [ detail
1003− , line $ "in data constructor " ++ runProperName nm
1035+ , line $ "in data constructor " ++ markCode (runProperName nm)
10041036 ]
10051037 renderHint (ErrorInTypeConstructor nm) detail =
10061038 paras [ detail
1007− , line $ "in type constructor " ++ runProperName nm
1039+ , line $ "in type constructor " ++ markCode (runProperName nm)
10081040 ]
10091041 renderHint (ErrorInBindingGroup nms) detail =
10101042 paras [ detail
@@ -1016,19 +1048,19 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
10161048 ]
10171049 renderHint (ErrorInTypeSynonym name) detail =
10181050 paras [ detail
1019− , line $ "in type synonym " ++ runProperName name
1051+ , line $ "in type synonym " ++ markCode (runProperName name)
10201052 ]
10211053 renderHint (ErrorInValueDeclaration n) detail =
10221054 paras [ detail
1023− , line $ "in value declaration " ++ showIdent n
1055+ , line $ "in value declaration " ++ markCode (showIdent n)
10241056 ]
10251057 renderHint (ErrorInTypeDeclaration n) detail =
10261058 paras [ detail
1027− , line $ "in type declaration for " ++ showIdent n
1059+ , line $ "in type declaration for " ++ markCode (showIdent n)
10281060 ]
10291061 renderHint (ErrorInForeignImport nm) detail =
10301062 paras [ detail
1031− , line $ "in foreign import " ++ showIdent nm
1063+ , line $ "in foreign import " ++ markCode (showIdent nm)
10321064 ]
10331065 renderHint (PositionedError srcSpan) detail =
10341066 paras [ line $ "at " ++ displaySourceSpan srcSpan
@@ -1036,22 +1068,34 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
10361068 ]
10371069
10381070 printName :: Qualified Name -> String
1039− printName (Qualified mn (IdentName name)) =
1040− "value " ++ showQualified showIdent (Qualified mn name)
1041− printName (Qualified mn (ValOpName op)) =
1042− "operator " ++ showQualified showOp (Qualified mn op)
1043− printName (Qualified mn (TyName name)) =
1044− "type " ++ showQualified runProperName (Qualified mn name)
1045− printName (Qualified mn (TyOpName op)) =
1046− "type operator " ++ showQualified showOp (Qualified mn op)
1047− printName (Qualified mn (DctorName name)) =
1048− "data constructor " ++ showQualified runProperName (Qualified mn name)
1049− printName (Qualified mn (TyClassName name)) =
1050− "type class " ++ showQualified runProperName (Qualified mn name)
1051− printName (Qualified Nothing (ModName name)) =
1052− "module " ++ runModuleName name
1053− printName (Qualified _ ModName{}) =
1054− internalError "qualified ModName in printName"
1071+ printName qn = nameType (disqualify qn) ++ " " ++ markCode (runName qn)
1072+
1073+ nameType :: Name -> String
1074+ nameType (IdentName _) = "value"
1075+ nameType (ValOpName _) = "operator"
1076+ nameType (TyName _) = "type"
1077+ nameType (TyOpName _) = "type operator"
1078+ nameType (DctorName _) = "data constructor"
1079+ nameType (TyClassName _) = "type class"
1080+ nameType (ModName _) = "module"
1081+
1082+ runName :: Qualified Name -> String
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)) =
1096+ runModuleName name
1097+ runName (Qualified _ ModName{}) =
1098+ internalError "qualified ModName in runName"
10551099
10561100 valueDepth :: Int
10571101 valueDepth | full = 1000
@@ -1119,57 +1163,72 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
11191163-- Pretty print and export declaration
11201164prettyPrintExport :: DeclarationRef -> String
11211165prettyPrintExport (TypeRef pn _) = runProperName pn
1122−prettyPrintExport ref = prettyPrintRef ref
1166+prettyPrintExport ref =
1167+ fromMaybe
1168+ (internalError "prettyPrintRef returned Nothing in prettyPrintExport")
1169+ (prettyPrintRef ref)
11231170
11241171prettyPrintImport :: ModuleName -> ImportDeclarationType -> Maybe ModuleName -> String
11251172prettyPrintImport mn idt qual =
11261173 let i = case idt of
11271174 Implicit -> runModuleName mn
1128− Explicit refs -> runModuleName mn ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ")"
1129− Hiding refs -> runModuleName mn ++ " hiding (" ++ intercalate "," (map prettyPrintRef refs) ++ ")"
1175+ Explicit refs -> runModuleName mn ++ " (" ++ intercalate ", " (mapMaybe prettyPrintRef refs) ++ ")"
1176+ Hiding refs -> runModuleName mn ++ " hiding (" ++ intercalate "," (mapMaybe prettyPrintRef refs) ++ ")"
11301177 in i ++ maybe "" (\q -> " as " ++ runModuleName q) qual
11311178
1132−prettyPrintRef :: DeclarationRef -> String
1133−prettyPrintRef (TypeRef pn Nothing) = runProperName pn ++ "(..)"
1134−prettyPrintRef (TypeRef pn (Just [])) = runProperName pn
1135−prettyPrintRef (TypeRef pn (Just dctors)) = runProperName pn ++ "(" ++ intercalate ", " (map runProperName dctors) ++ ")"
1136−prettyPrintRef (TypeOpRef op) = "type " ++ showOp op
1137−prettyPrintRef (ValueRef ident) = showIdent ident
1138−prettyPrintRef (ValueOpRef op) = showOp op
1139−prettyPrintRef (TypeClassRef pn) = "class " ++ runProperName pn
1140−prettyPrintRef (TypeInstanceRef ident) = showIdent ident
1141−prettyPrintRef (ModuleRef name) = "module " ++ runModuleName name
1142−prettyPrintRef (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref
1179+prettyPrintRef :: DeclarationRef -> Maybe String
1180+prettyPrintRef (TypeRef pn Nothing) =
1181+ Just $ runProperName pn ++ "(..)"
1182+prettyPrintRef (TypeRef pn (Just [])) =
1183+ Just $ runProperName pn
1184+prettyPrintRef (TypeRef pn (Just dctors)) =
1185+ Just $ runProperName pn ++ "(" ++ intercalate ", " (map runProperName dctors) ++ ")"
1186+prettyPrintRef (TypeOpRef op) =
1187+ Just $ "type " ++ showOp op
1188+prettyPrintRef (ValueRef ident) =
1189+ Just $ showIdent ident
1190+prettyPrintRef (ValueOpRef op) =
1191+ Just $ showOp op
1192+prettyPrintRef (TypeClassRef pn) =
1193+ Just $ "class " ++ runProperName pn
1194+prettyPrintRef (TypeInstanceRef ident) =
1195+ Just $ showIdent ident
1196+prettyPrintRef (ModuleRef name) =
1197+ Just $ "module " ++ runModuleName name
1198+prettyPrintRef (ReExportRef _ _) =
1199+ Nothing
1200+prettyPrintRef (PositionedDeclarationRef _ _ ref) =
1201+ prettyPrintRef ref
11431202
11441203-- |
11451204-- Pretty print multiple errors
11461205--
1147−prettyPrintMultipleErrors :: Bool -> MultipleErrors -> String
1148−prettyPrintMultipleErrors full = unlines . map renderBox . prettyPrintMultipleErrorsBox full
1206+prettyPrintMultipleErrors :: PPEOptions -> MultipleErrors -> String
1207+prettyPrintMultipleErrors ppeOptions = unlines . map renderBox . prettyPrintMultipleErrorsBox ppeOptions
11491208
11501209-- |
11511210-- Pretty print multiple warnings
11521211--
1153−prettyPrintMultipleWarnings :: Bool -> MultipleErrors -> String
1154−prettyPrintMultipleWarnings full = unlines . map renderBox . prettyPrintMultipleWarningsBox full
1212+prettyPrintMultipleWarnings :: PPEOptions -> MultipleErrors -> String
1213+prettyPrintMultipleWarnings ppeOptions = unlines . map renderBox . prettyPrintMultipleWarningsBox ppeOptions
11551214
11561215-- | Pretty print warnings as a Box
1157−prettyPrintMultipleWarningsBox :: Bool -> MultipleErrors -> [Box.Box]
1158−prettyPrintMultipleWarningsBox = prettyPrintMultipleErrorsWith Warning "Warning found:" "Warning"
1216+prettyPrintMultipleWarningsBox :: PPEOptions -> MultipleErrors -> [Box.Box]
1217+prettyPrintMultipleWarningsBox ppeOptions = prettyPrintMultipleErrorsWith (ppeOptions { ppeLevel = Warning }) "Warning found:" "Warning"
11591218
11601219-- | Pretty print errors as a Box
1161−prettyPrintMultipleErrorsBox :: Bool -> MultipleErrors -> [Box.Box]
1162−prettyPrintMultipleErrorsBox = prettyPrintMultipleErrorsWith Error "Error found:" "Error"
1220+prettyPrintMultipleErrorsBox :: PPEOptions -> MultipleErrors -> [Box.Box]
1221+prettyPrintMultipleErrorsBox ppeOptions = prettyPrintMultipleErrorsWith (ppeOptions { ppeLevel = Error }) "Error found:" "Error"
11631222
1164−prettyPrintMultipleErrorsWith :: Level -> String -> String -> Bool -> MultipleErrors -> [Box.Box]
1165−prettyPrintMultipleErrorsWith level intro _ full (MultipleErrors [e]) =
1166− let result = prettyPrintSingleError full level True e
1223+prettyPrintMultipleErrorsWith :: PPEOptions -> String -> String -> MultipleErrors -> [Box.Box]
1224+prettyPrintMultipleErrorsWith ppeOptions intro _ (MultipleErrors [e]) =
1225+ let result = prettyPrintSingleError ppeOptions e
11671226 in [ Box.vcat Box.left [ Box.text intro
11681227 , result
11691228 ]
11701229 ]
1171−prettyPrintMultipleErrorsWith level _ intro full (MultipleErrors es) =
1172− let result = map (prettyPrintSingleError full level True) es
1230+prettyPrintMultipleErrorsWith ppeOptions _ intro (MultipleErrors es) =
1231+ let result = map (prettyPrintSingleError ppeOptions) es
11731232 in concat $ zipWith withIntro [1 :: Int ..] result
11741233 where
11751234 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
4747toJSONError :: Bool -> P.Level -> P.ErrorMessage -> JSONError
4848toJSONError verbose level e =
4949 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)))
5151 (P.errorCode e)
5252 (P.wikiUri e)
5353 (P.spanName <$> sspan)
src/Language/PureScript/Ide.hs+129−178
@@ -18,24 +18,11 @@
1818
1919module Language.PureScript.Ide
2020 ( handleCommand
21− -- for tests
22− , printModules
2321 ) where
2422
25−import Prelude ()
26−import Prelude.Compat
23+import Protolude
2724
28−import Control.Monad (unless)
29−import Control.Monad.Error.Class
30−import Control.Monad.IO.Class
3125import "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
3926import qualified Language.PureScript as P
4027import qualified Language.PureScript.Ide.CaseSplit as CS
4128import Language.PureScript.Ide.Command
@@ -47,199 +34,163 @@ import Language.PureScript.Ide.Imports hiding (Import)
4734import Language.PureScript.Ide.Matcher
4835import Language.PureScript.Ide.Pursuit
4936import Language.PureScript.Ide.Rebuild
50−import Language.PureScript.Ide.Reexports
5137import Language.PureScript.Ide.SourceFile
5238import Language.PureScript.Ide.State
5339import Language.PureScript.Ide.Types
5440import Language.PureScript.Ide.Util
5541import System.Directory
56−import System.Exit
5742import System.FilePath
43+import System.FilePath.Glob
5844
59−handleCommand :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
45+-- | Accepts a Commmand and runs it against psc-ide's State. This is the main
46+-- entry point for the server.
47+handleCommand :: (Ide m, MonadLogger m, MonadError PscIdeError m) =>
6048 Command -> m Success
61−handleCommand (Load [] []) = loadAllModules
62−handleCommand (Load modules deps) =
63− loadModulesAndDeps modules deps
64−handleCommand (Type search filters currentModule) =
65− findType search filters currentModule
66−handleCommand (Complete filters matcher currentModule) =
67− findCompletions filters matcher currentModule
68−handleCommand (Pursuit query Package) =
69− findPursuitPackages query
70−handleCommand (Pursuit query Identifier) =
71− findPursuitCompletions query
72−handleCommand (List LoadedModules) =
73− printModules
74−handleCommand (List AvailableModules) =
75− listAvailableModules
76−handleCommand (List (Imports fp)) =
77− importsForFile fp
78−handleCommand (CaseSplit l b e wca t) =
79− caseSplit l b e wca t
80−handleCommand (AddClause l wca) =
81− pure $ addClause l wca
82−handleCommand (Import fp outfp _ (AddImplicitImport mn)) = do
83− rs <- addImplicitImport fp mn
84− answerRequest outfp rs
85−handleCommand (Import fp outfp filters (AddImportForIdentifier ident)) = do
86− rs <- addImportForIdentifier fp ident filters
87− case rs of
88− Right rs' -> answerRequest outfp rs'
89− Left question -> pure $ CompletionResult (mapMaybe completionFromMatch question)
90−handleCommand (Rebuild file) =
91− rebuildFile file
92−handleCommand Cwd =
93− TextResult . T.pack <$> liftIO getCurrentDirectory
94−handleCommand Reset = resetPscIdeState *> pure (TextResult "State has been reset.")
95−handleCommand Quit = liftIO exitSuccess
96−
97−findCompletions :: (PscIde m, MonadLogger m) =>
98− [Filter] -> Matcher -> Maybe P.ModuleName -> m Success
49+handleCommand c = case c of
50+ Load [] ->
51+ findAvailableExterns >>= loadModules
52+ Load modules ->
53+ loadModules modules
54+ Type search filters currentModule ->
55+ findType search filters currentModule
56+ Complete filters matcher currentModule ->
57+ findCompletions filters matcher currentModule
58+ Pursuit query Package ->
59+ findPursuitPackages query
60+ Pursuit query Identifier ->
61+ findPursuitCompletions query
62+ List LoadedModules ->
63+ printModules
64+ List AvailableModules ->
65+ listAvailableModules
66+ List (Imports fp) ->
67+ ImportList <$> getImportsForFile fp
68+ CaseSplit l b e wca t ->
69+ caseSplit l b e wca t
70+ AddClause l wca ->
71+ MultilineTextResult <$> CS.addClause l wca
72+ Import fp outfp _ (AddImplicitImport mn) -> do
73+ rs <- addImplicitImport fp mn
74+ answerRequest outfp rs
75+ Import fp outfp filters (AddImportForIdentifier ident) -> do
76+ rs <- addImportForIdentifier fp ident filters
77+ case rs of
78+ Right rs' -> answerRequest outfp rs'
79+ Left question ->
80+ pure (CompletionResult (map completionFromMatch question))
81+ Rebuild file ->
82+ rebuildFile file
83+ Cwd ->
84+ TextResult . toS <$> liftIO getCurrentDirectory
85+ Reset ->
86+ resetIdeState $> TextResult "State has been reset."
87+ Quit ->
88+ liftIO exitSuccess
89+
90+findCompletions :: Ide m =>
91+ [Filter] -> Matcher IdeDeclaration -> Maybe P.ModuleName -> m Success
9992findCompletions filters matcher currentModule = do
100− modules <- getAllModulesWithReexportsAndCache currentModule
101− pure . CompletionResult . mapMaybe completionFromMatch . getCompletions filters matcher $ modules
93+ modules <- getAllModules currentModule
94+ pure . CompletionResult . map completionFromMatch . getCompletions filters matcher $ modules
10295
103−findType :: (PscIde m, MonadLogger m) =>
104− DeclIdent -> [Filter] -> Maybe P.ModuleName -> m Success
96+findType :: Ide m =>
97+ Text -> [Filter] -> Maybe P.ModuleName -> m Success
10598findType search filters currentModule = do
106− modules <- getAllModulesWithReexportsAndCache currentModule
107− pure . CompletionResult . mapMaybe completionFromMatch . getExactMatches search filters $ modules
99+ modules <- getAllModules currentModule
100+ pure . InfoResult . map infoFromMatch . getExactMatches search filters $ modules
108101
109−findPursuitCompletions :: (MonadIO m, MonadLogger m) =>
102+findPursuitCompletions :: MonadIO m =>
110103 PursuitQuery -> m Success
111104findPursuitCompletions (PursuitQuery q) =
112105 PursuitResult <$> liftIO (searchPursuitForDeclarations q)
113106
114−findPursuitPackages :: (MonadIO m, MonadLogger m) =>
107+findPursuitPackages :: MonadIO m =>
115108 PursuitQuery -> m Success
116109findPursuitPackages (PursuitQuery q) =
117110 PursuitResult <$> liftIO (findPackagesForModuleIdent q)
118111
119−loadExtern :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
120− FilePath -> m ()
121−loadExtern fp = do
122− m <- readExternFile fp
123− insertModule m
112+printModules :: Ide m => m Success
113+printModules = ModuleList . map runModuleNameT <$> getLoadedModulenames
124114
125−printModules :: (PscIde m) => m Success
126−printModules = printModules' . pscIdeStateModules <$> getPscIdeState
127−
128−printModules' :: M.Map ModuleIdent [ExternDecl] -> Success
129−printModules' = ModuleList . M.keys
115+outputDirectory :: Ide m => m FilePath
116+outputDirectory = do
117+ outputPath <- confOutputPath . ideConfiguration <$> ask
118+ cwd <- liftIO getCurrentDirectory
119+ pure (cwd </> outputPath)
130120
131−listAvailableModules :: PscIde m => m Success
121+listAvailableModules :: Ide m => m Success
132122listAvailableModules = do
133− outputPath <- confOutputPath . envConfiguration <$> ask
123+ oDir <- outputDirectory
134124 liftIO $ do
135− cwd <- getCurrentDirectory
136− dirs <- getDirectoryContents (cwd </> outputPath)
137− return (ModuleList (listAvailableModules' dirs))
138−
139−listAvailableModules' :: [FilePath] -> [Text]
140−listAvailableModules' dirs =
141− let cleanedModules = filter (`notElem` [".", ".."]) dirs
142− in map T.pack cleanedModules
125+ contents <- getDirectoryContents oDir
126+ let cleaned = filter (`notElem` [".", ".."]) contents
127+ return (ModuleList (map toS cleaned))
143128
144−caseSplit :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
129+caseSplit :: (Ide m, MonadError PscIdeError m) =>
145130 Text -> Int -> Int -> CS.WildcardAnnotations -> Text -> m Success
146131caseSplit l b e csa t = do
147132 patterns <- CS.makePattern l b e csa <$> CS.caseSplit t
148133 pure (MultilineTextResult patterns)
149134
150−addClause :: Text -> CS.WildcardAnnotations -> Success
151−addClause t wca = MultilineTextResult (CS.addClause t wca)
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) =>
186− Module -> m [ModuleIdent]
187−loadReexports m = case getReexports m of
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)
220− >>= flip unless (throwError (GeneralError "Couldn't locate your output directory"))
221− liftIO (getDirectoryContents outputDirectory)
222− >>= liftIO . traverse (getExternsPath outputDirectory)
223− >>= traverse_ loadExtern . catMaybes
224− pure (TextResult "All modules loaded.")
135+-- | Finds all the externs.json files inside the output folder and returns the
136+-- corresponding Modulenames
137+findAvailableExterns :: (Ide m, MonadError PscIdeError m) => m [P.ModuleName]
138+findAvailableExterns = do
139+ oDir <- outputDirectory
140+ unlessM (liftIO (doesDirectoryExist oDir))
141+ (throwError (GeneralError "Couldn't locate your output directory."))
142+ liftIO $ do
143+ directories <- getDirectoryContents oDir
144+ moduleNames <- filterM (containsExterns oDir) directories
145+ pure (P.moduleNameFromString <$> moduleNames)
225146 where
226− getExternsPath :: FilePath -> FilePath -> IO (Maybe FilePath)
227− getExternsPath outputDirectory d
228− | d `elem` [".", ".."] = pure Nothing
147+ -- Takes the output directory and a filepath like "Monad.Control.Eff" and
148+ -- looks up, whether that folder contains an externs.json
149+ containsExterns :: FilePath -> FilePath -> IO Bool
150+ containsExterns oDir d
151+ | d `elem` [".", ".."] = pure False
229152 | otherwise = do
230− let file = outputDirectory </> d </> "externs.json"
231− ex <- doesFileExist file
232− if ex
233− then pure (Just file)
234− else pure Nothing
235−
236−filePathFromModule :: (PscIde m, MonadError PscIdeError m) =>
237− ModuleIdent -> m FilePath
238−filePathFromModule moduleName = do
239− outputPath <- confOutputPath . envConfiguration <$> ask
240− cwd <- liftIO getCurrentDirectory
241− let path = cwd </> outputPath </> T.unpack moduleName </> "externs.json"
242− ex <- liftIO $ doesFileExist path
243− if ex
244− then pure path
245− else throwError (ModuleFileNotFound moduleName)
153+ let file = oDir </> d </> "externs.json"
154+ doesFileExist file
155+
156+-- | Finds all matches for the globs specified at the commandline
157+findAllSourceFiles :: Ide m => m [FilePath]
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
167+ :: (Ide m, MonadError PscIdeError m, MonadLogger m)
168+ => [P.ModuleName]
169+ -> m Success
170+loadModules moduleNames = do
171+ -- We resolve all the modulenames to externs files and load these into memory.
172+ oDir <- outputDirectory
173+ let efPaths =
174+ map (\mn -> oDir </> P.runModuleName mn </> "externs.json") moduleNames
175+ efiles <- traverse readExternFile efPaths
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 @@
1313-----------------------------------------------------------------------------
1414
1515{-# LANGUAGE OverloadedStrings #-}
16−{-# LANGUAGE PackageImports #-}
1716
1817module Language.PureScript.Ide.CaseSplit
1918 ( WildcardAnnotations()
@@ -24,26 +23,19 @@ module Language.PureScript.Ide.CaseSplit
2423 , caseSplit
2524 ) where
2625
27−import Prelude ()
28−import Prelude.Compat hiding (lex)
26+import Protolude hiding (Constructor)
2927
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)
3628import qualified Data.Text as T
3729import qualified Language.PureScript as P
3830
3931import Language.PureScript.Externs
4032import Language.PureScript.Ide.Error
41−import Language.PureScript.Ide.Externs (unwrapPositioned)
4233import Language.PureScript.Ide.State
4334import Language.PureScript.Ide.Types
4435import Language.PureScript.Ide.Util
4536
4637import Text.Parsec as Parsec
38+import qualified Text.PrettyPrint.Boxes as Box
4739
4840type Constructor = (P.ProperName 'P.ConstructorName, [P.Type])
4941
@@ -55,17 +47,17 @@ explicitAnnotations = WildcardAnnotations True
5547noAnnotations :: WildcardAnnotations
5648noAnnotations = WildcardAnnotations False
5749
58−caseSplit :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
50+caseSplit :: (Ide m, MonadError PscIdeError m) =>
5951 Text -> m [Constructor]
6052caseSplit q = do
61− type' <- parseType' (T.unpack q)
53+ type' <- parseType' q
6254 (tc, args) <- splitTypeConstructor type'
6355 (EDType _ _ (P.DataType typeVars ctors)) <- findTypeDeclaration tc
6456 let applyTypeVars = P.everywhereOnTypes (P.replaceAllTypeVars (zip (map fst typeVars) args))
6557 let appliedCtors = map (second (map applyTypeVars)) ctors
6658 pure appliedCtors
6759
68−findTypeDeclaration :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
60+findTypeDeclaration :: (Ide m, MonadError PscIdeError m) =>
6961 P.ProperName 'P.TypeName -> m ExternsDeclaration
7062findTypeDeclaration q = do
7163 efs <- getExternFiles
@@ -115,39 +107,41 @@ makePattern t x y wsa = makePattern' (T.take x t) (T.drop y t)
115107 where
116108 makePattern' lhs rhs = map (\ctor -> lhs <> prettyCtor wsa ctor <> rhs)
117109
118−addClause :: Text -> WildcardAnnotations -> [Text]
119−addClause s wca =
120− let (fName, fType) = parseTypeDeclaration' (T.unpack s)
121− (args, _) = splitFunctionType fType
110+addClause :: (MonadError PscIdeError m) => Text -> WildcardAnnotations -> m [Text]
111+addClause s wca = do
112+ (fName, fType) <- parseTypeDeclaration' s
113+ let args = splitFunctionType fType
122114 template = runIdentT fName <> " " <>
123115 T.unwords (map (prettyPrintWildcard wca) args) <>
124116 " = ?" <> (T.strip . runIdentT $ fName)
125− in [s, template]
117+ pure [s, template]
126118
127119parseType' :: (MonadError PscIdeError m) =>
128− String -> m P.Type
120+ Text -> m P.Type
129121parseType' 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
131123 Right type' -> pure type'
132124 Left err ->
133125 throwError (GeneralError ("Parsing the splittype failed with:"
134− ++ show err))
126+ <> show err))
135127
136−parseTypeDeclaration' :: String -> (P.Ident, P.Type)
128+parseTypeDeclaration' :: (MonadError PscIdeError m) => Text -> m (P.Ident, P.Type)
137129parseTypeDeclaration' s =
138130 let x = do
139− ts <- P.lex "" s
131+ ts <- P.lex "" (toS s)
140132 P.runTokenParser "" (P.parseDeclaration <* Parsec.eof) ts
141133 in
142134 case unwrapPositioned <$> x of
143− Right (P.TypeDeclaration i t) -> (i, t)
144− y -> error (show y)
145−
146−splitFunctionType :: P.Type -> ([P.Type], P.Type)
147−splitFunctionType t = (arguments, returns)
135+ Right (P.TypeDeclaration i t) -> pure (i, t)
136+ Right _ -> throwError (GeneralError "Found a non-type-declaration")
137+ Left err ->
138+ throwError (GeneralError ("Parsing the type signature failed with: "
139+ <> toS (Box.render (P.prettyPrintParseError err))))
140+
141+splitFunctionType :: P.Type -> [P.Type]
142+splitFunctionType t = fromMaybe [] arguments
148143 where
149− returns = last splitted
150− arguments = init splitted
144+ arguments = initMay splitted
151145 splitted = splitType' t
152146 splitType' (P.ForAll _ t' _) = splitType' t'
153147 splitType' (P.ConstrainedType _ t') = splitType' t'
src/Language/PureScript/Ide/Command.hs+11−18
@@ -16,31 +16,26 @@
1616
1717module Language.PureScript.Ide.Command where
1818
19−import Prelude ()
20−import Prelude.Compat
19+import Protolude
2120
22−import Control.Monad
2321import Data.Aeson
24−import Data.Text (Text)
2522import qualified Language.PureScript as P
2623import Language.PureScript.Ide.CaseSplit
2724import Language.PureScript.Ide.Filter
2825import Language.PureScript.Ide.Matcher
2926import Language.PureScript.Ide.Types
27+import System.FilePath
3028
3129data Command
32− = Load
33− { loadModules :: [ModuleIdent]
34− , loadDependencies :: [ModuleIdent]
35− }
30+ = Load [P.ModuleName]
3631 | Type
37− { typeSearch :: DeclIdent
32+ { typeSearch :: Text
3833 , typeFilters :: [Filter]
3934 , typeCurrentModule :: Maybe P.ModuleName
4035 }
4136 | Complete
4237 { completeFilters :: [Filter]
43− , completeMatcher :: Matcher
38+ , completeMatcher :: Matcher IdeDeclaration
4439 , completeCurrentModule :: Maybe P.ModuleName
4540 }
4641 | Pursuit
@@ -68,12 +63,12 @@ data Command
6863
6964data ImportCommand
7065 = AddImplicitImport P.ModuleName
71− | AddImportForIdentifier DeclIdent
66+ | AddImportForIdentifier Text
7267 deriving (Show, Eq)
7368
7469instance FromJSON ImportCommand where
7570 parseJSON = withObject "ImportCommand" $ \o -> do
76− (command :: String) <- o .: "importCommand"
71+ (command :: Text) <- o .: "importCommand"
7772 case command of
7873 "addImplicitImport" ->
7974 AddImplicitImport <$> (P.moduleNameFromString <$> o .: "module")
@@ -85,7 +80,7 @@ data ListType = LoadedModules | Imports FilePath | AvailableModules
8580
8681instance FromJSON ListType where
8782 parseJSON = withObject "ListType" $ \o -> do
88− (listType' :: String) <- o .: "type"
83+ (listType' :: Text) <- o .: "type"
8984 case listType' of
9085 "import" -> Imports <$> o .: "file"
9186 "loadedModules" -> pure LoadedModules
@@ -94,7 +89,7 @@ instance FromJSON ListType where
9489
9590instance FromJSON Command where
9691 parseJSON = withObject "command" $ \o -> do
97− (command :: String) <- o .: "command"
92+ (command :: Text) <- o .: "command"
9893 case command of
9994 "list" -> List <$> o .:? "params" .!= LoadedModules
10095 "cwd" -> pure Cwd
@@ -103,11 +98,9 @@ instance FromJSON Command where
10398 "load" -> do
10499 params' <- o .:? "params"
105100 case params' of
106− Nothing -> pure (Load [] [])
101+ Nothing -> pure (Load [])
107102 Just params ->
108− Load
109− <$> params .:? "modules" .!= []
110− <*> params .:? "dependencies" .!= []
103+ Load <$> (map P.moduleNameFromString <$> params .:? "modules" .!= [])
111104 "type" -> do
112105 params <- o .: "params"
113106 Type
src/Language/PureScript/Ide/Completion.hs+17−17
@@ -1,32 +1,32 @@
11{-# LANGUAGE OverloadedStrings #-}
22module Language.PureScript.Ide.Completion
3− (getCompletions, getExactMatches)
4− where
3+ ( getCompletions
4+ , getExactMatches
5+ ) where
56
6−import Prelude ()
7−import Prelude.Compat
7+import Protolude
88
9−import Data.Maybe (mapMaybe)
109import Language.PureScript.Ide.Filter
1110import Language.PureScript.Ide.Matcher
1211import Language.PureScript.Ide.Types
12+import Language.PureScript.Ide.Util
1313
1414-- | Applies the CompletionFilters and the Matcher to the given Modules
1515-- 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]
1721getCompletions filters matcher modules =
18− runMatcher matcher $ completionsFromModules (applyFilters filters modules)
22+ runMatcher matcher (completionsFromModules discardAnn (applyFilters filters modules))
1923
20−getExactMatches :: DeclIdent -> [Filter] -> [Module] -> [Match]
24+getExactMatches :: Text -> [Filter] -> [Module] -> [Match IdeDeclarationAnn]
2125getExactMatches search filters modules =
22− completionsFromModules $
23− applyFilters (equalityFilter search : filters) modules
26+ completionsFromModules identity (applyFilters (equalityFilter search : filters) modules)
2427
25−completionsFromModules :: [Module] -> [Match]
26−completionsFromModules = foldMap completionFromModule
28+completionsFromModules :: (IdeDeclarationAnn -> a) -> [Module] -> [Match a]
29+completionsFromModules f = foldMap completionFromModule
2730 where
28− completionFromModule :: Module -> [Match]
29− completionFromModule (moduleIdent, decls) = mapMaybe (matchFromDecl moduleIdent) decls
30−
31−matchFromDecl :: ModuleIdent -> ExternDecl -> Maybe Match
32−matchFromDecl mi = Just . Match mi
31+ completionFromModule (moduleName, decls) =
32+ map (\x -> Match (moduleName, f x)) decls
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 @@
1414
1515{-# LANGUAGE OverloadedStrings #-}
1616module Language.PureScript.Ide.Error
17− (ErrorMsg, PscIdeError(..), textError)
18− where
17+ ( PscIdeError(..)
18+ ) where
1919
20−import Prelude.Compat
20+import Protolude
2121import Data.Aeson
22−import Data.Monoid
23−import Data.Text (Text, pack)
2422import Language.PureScript.Errors.JSON
2523import Language.PureScript.Ide.Types (ModuleIdent)
2624import qualified Text.Parsec.Error as P
2725
28−type ErrorMsg = String
29−
3026data PscIdeError
31− = GeneralError ErrorMsg
27+ = GeneralError Text
3228 | NotFound Text
3329 | ModuleNotFound ModuleIdent
3430 | ModuleFileNotFound ModuleIdent
35− | ParseError P.ParseError ErrorMsg
31+ | ParseError P.ParseError Text
3632 | RebuildError [JSONError]
3733
3834instance ToJSON PscIdeError where
@@ -46,7 +42,7 @@ instance ToJSON PscIdeError where
4642 ]
4743
4844textError :: PscIdeError -> Text
49−textError (GeneralError msg) = pack msg
45+textError (GeneralError msg) = msg
5046textError (NotFound ident) = "Symbol '" <> ident <> "' not found."
5147textError (ModuleNotFound ident) = "Module '" <> ident <> "' not found."
5248textError (ModuleFileNotFound ident) = "Extern file for module " <> ident <>" could not be found"
@@ -54,5 +50,5 @@ textError (ParseError parseError msg) = let escape = show
5450 -- escape newlines and other special
5551 -- chars so we can send the error
5652 -- over the socket as a single line
57− in pack $ msg <> ": " <> show (escape parseError)
58−textError (RebuildError err) = pack (show err)
53+ in msg <> ": " <> escape parseError
54+textError (RebuildError err) = show err
src/Language/PureScript/Ide/Externs.hs+62−63
@@ -12,115 +12,114 @@
1212-- Handles externs files for psc-ide
1313-----------------------------------------------------------------------------
1414
15−{-# LANGUAGE OverloadedStrings #-}
15+{-# LANGUAGE OverloadedStrings #-}
16+{-# LANGUAGE RecordWildCards #-}
17+{-# LANGUAGE FlexibleContexts #-}
1618
1719module Language.PureScript.Ide.Externs
18− ( ExternDecl(..),
19− ModuleIdent,
20− DeclIdent,
21− readExternFile,
20+ ( readExternFile,
2221 convertExterns,
23− unwrapPositioned,
24− unwrapPositionedRef
22+ annotateLocations
2523 ) where
2624
27−import Prelude ()
28−import Prelude.Compat
25+import Protolude
2926
30−import Control.Monad.Error.Class
31−import Control.Monad.IO.Class
3227import Data.Aeson (decodeStrict)
3328import 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
3830import qualified Data.ByteString as BS
3931import Language.PureScript.Ide.Error (PscIdeError (..))
4032import Language.PureScript.Ide.Types
4133import Language.PureScript.Ide.Util
4234
4335import qualified Language.PureScript as P
36+import System.FilePath
4437
4538readExternFile :: (MonadIO m, MonadError PscIdeError m) =>
4639 FilePath -> m P.ExternsFile
4740readExternFile fp = do
4841 parseResult <- liftIO (decodeStrict <$> BS.readFile fp)
4942 case parseResult of
50− Nothing -> throwError . GeneralError $ "Parsing the extern at: " ++ fp ++ " failed"
43+ Nothing -> throwError . GeneralError $ "Parsing the extern at: " <> toS fp <> " failed"
5144 Just externs -> pure externs
5245
53−moduleNameToText :: P.ModuleName -> Text
54−moduleNameToText = T.pack . P.runModuleName
55−
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)
46+convertExterns :: P.ExternsFile -> (Module, [(P.ModuleName, P.DeclarationRef)])
47+convertExterns ef =
48+ ((P.efModuleName ef, decls), exportDecls)
6149 where
62− moduleName = moduleNameToText (P.efModuleName ef)
63− importDecls = convertImport <$> P.efImports ef
50+ decls = map
51+ (IdeDeclarationAnn emptyAnn)
52+ (cleanDeclarations ++ operatorDecls ++ tyOperatorDecls)
6453 exportDecls = mapMaybe (convertExport . unwrapPositionedRef) (P.efExports ef)
6554 operatorDecls = convertOperator <$> P.efFixities ef
6655 tyOperatorDecls = convertTypeOperator <$> P.efTypeFixities ef
67− otherDecls = mapMaybe convertDecl (P.efDeclarations ef)
56+ declarations = mapMaybe convertDecl (P.efDeclarations ef)
6857
69− typeClassFilter = foldMap removeTypeDeclarationsForClass (filter isTypeClassDeclaration otherDecls)
70− decls = nub $ appEndo typeClassFilter otherDecls
58+ typeClassFilter = foldMap removeTypeDeclarationsForClass (filter isTypeClassDeclaration declarations)
59+ cleanDeclarations = nub $ appEndo typeClassFilter declarations
7160
72−removeTypeDeclarationsForClass :: ExternDecl -> Endo [ExternDecl]
73−removeTypeDeclarationsForClass (TypeClassDeclaration n) = Endo (filter notDuplicate)
74− where notDuplicate (TypeDeclaration n' _) = runProperNameT n /= runProperNameT n'
75− notDuplicate (TypeSynonymDeclaration n' _) = runProperNameT n /= runProperNameT n'
61+removeTypeDeclarationsForClass :: IdeDeclaration -> Endo [IdeDeclaration]
62+removeTypeDeclarationsForClass (IdeTypeClass n) = Endo (filter notDuplicate)
63+ where notDuplicate (IdeType n' _) = runProperNameT n /= runProperNameT n'
64+ notDuplicate (IdeTypeSynonym n' _) = runProperNameT n /= runProperNameT n'
7665 notDuplicate _ = True
7766removeTypeDeclarationsForClass _ = mempty
7867
79−isTypeClassDeclaration :: ExternDecl -> Bool
80−isTypeClassDeclaration TypeClassDeclaration{} = True
68+isTypeClassDeclaration :: IdeDeclaration -> Bool
69+isTypeClassDeclaration IdeTypeClass{} = True
8170isTypeClassDeclaration _ = False
8271
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
90−convertExport (P.ModuleRef mn) = Just (Export (moduleNameToText mn))
72+convertExport :: P.DeclarationRef -> Maybe (P.ModuleName, P.DeclarationRef)
73+convertExport (P.ReExportRef m r) = Just (m, r)
9174convertExport _ = Nothing
9275
93−convertDecl :: P.ExternsDeclaration -> Maybe ExternDecl
94−convertDecl P.EDType{..} = Just $ TypeDeclaration edTypeName edTypeKind
95−convertDecl P.EDTypeSynonym{..} = Just $
96− TypeSynonymDeclaration edTypeSynonymName edTypeSynonymType
76+convertDecl :: P.ExternsDeclaration -> Maybe IdeDeclaration
77+convertDecl P.EDType{..} = Just (IdeType edTypeName edTypeKind)
78+convertDecl P.EDTypeSynonym{..} =
79+ Just (IdeTypeSynonym edTypeSynonymName edTypeSynonymType)
9780convertDecl P.EDDataConstructor{..} = Just $
98− DataConstructor (runProperNameT edDataCtorName) edDataCtorTypeCtor edDataCtorType
81+ IdeDataConstructor edDataCtorName edDataCtorTypeCtor edDataCtorType
9982convertDecl P.EDValue{..} = Just $
100− ValueDeclaration (identToText edValueName) edValueType
101−convertDecl P.EDClass{..} = Just $ TypeClassDeclaration edClassName
83+ IdeValue edValueName edValueType
84+convertDecl P.EDClass{..} = Just (IdeTypeClass edClassName)
10285convertDecl P.EDInstance{} = Nothing
10386
104−convertOperator :: P.ExternsFixity -> ExternDecl
87+convertOperator :: P.ExternsFixity -> IdeDeclaration
10588convertOperator P.ExternsFixity{..} =
106− ValueOperator
89+ IdeValueOperator
10790 efOperator
108− (T.pack (P.showQualified (either P.runIdent P.runProperName) efAlias))
91+ (toS (P.showQualified (either P.runIdent P.runProperName) efAlias))
10992 efPrecedence
11093 efAssociativity
11194
112−convertTypeOperator :: P.ExternsTypeFixity -> ExternDecl
95+convertTypeOperator :: P.ExternsTypeFixity -> IdeDeclaration
11396convertTypeOperator P.ExternsTypeFixity{..} =
114− TypeOperator
97+ IdeTypeOperator
11598 efTypeOperator
116− (T.pack (P.showQualified P.runProperName efTypeAlias))
99+ (toS (P.showQualified P.runProperName efTypeAlias))
117100 efTypePrecedence
118101 efTypeAssociativity
119102
120−unwrapPositioned :: P.Declaration -> P.Declaration
121−unwrapPositioned (P.PositionedDeclaration _ _ x) = x
122−unwrapPositioned x = x
123−
124−unwrapPositionedRef :: P.DeclarationRef -> P.DeclarationRef
125−unwrapPositionedRef (P.PositionedDeclarationRef _ _ x) = x
126−unwrapPositionedRef x = x
103+annotateLocations :: Map (Either Text Text) P.SourceSpan -> Module -> Module
104+annotateLocations ast (moduleName, decls) =
105+ (moduleName, map convertDeclaration decls)
106+ where
107+ convertDeclaration :: IdeDeclarationAnn -> IdeDeclarationAnn
108+ convertDeclaration (IdeDeclarationAnn ann d) = case d of
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
2020 , moduleFilter
2121 , prefixFilter
2222 , equalityFilter
23− , dependencyFilter
24− , runFilter
2523 , applyFilters
2624 ) where
2725
28−import Prelude ()
29−import Prelude.Compat
26+import Protolude hiding (isPrefixOf)
3027
31−import Control.Monad
3228import 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)
3730import Language.PureScript.Ide.Types
3831import Language.PureScript.Ide.Util
32+import qualified Language.PureScript as P
3933
4034newtype Filter = Filter (Endo [Module]) deriving(Monoid)
4135
@@ -43,69 +37,46 @@ mkFilter :: ([Module] -> [Module]) -> Filter
4337mkFilter = Filter . Endo
4438
4539-- | Only keeps the given Modules
46−moduleFilter :: [ModuleIdent] -> Filter
40+moduleFilter :: [P.ModuleName] -> Filter
4741moduleFilter =
4842 mkFilter . moduleFilter'
4943
50−moduleFilter' :: [ModuleIdent] -> [Module] -> [Module]
44+moduleFilter' :: [P.ModuleName] -> [Module] -> [Module]
5145moduleFilter' moduleIdents = filter (flip elem moduleIdents . fst)
5246
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−
7447-- | Only keeps Identifiers that start with the given prefix
7548prefixFilter :: Text -> Filter
76−prefixFilter "" = mkFilter id
49+prefixFilter "" = mkFilter identity
7750prefixFilter t = mkFilter $ identFilter prefix t
7851 where
79− prefix :: ExternDecl -> Text -> Bool
80− prefix Export{} _ = False
81− prefix Dependency{} _ = False
82− prefix ed search = search `isPrefixOf` identifierFromExternDecl ed
83−
52+ prefix :: IdeDeclaration -> Text -> Bool
53+ prefix ed search = search `isPrefixOf` identifierFromIdeDeclaration ed
8454
8555-- | Only keeps Identifiers that are equal to the search string
8656equalityFilter :: Text -> Filter
8757equalityFilter = mkFilter . identFilter equality
8858 where
89− equality :: ExternDecl -> Text -> Bool
90− equality ed search = identifierFromExternDecl ed == search
59+ equality :: IdeDeclaration -> Text -> Bool
60+ equality ed search = identifierFromIdeDeclaration ed == search
9161
92−identFilter :: (ExternDecl -> Text -> Bool ) -> Text -> [Module] -> [Module]
62+identFilter :: (IdeDeclaration -> Text -> Bool) -> Text -> [Module] -> [Module]
9363identFilter predicate search =
9464 filter (not . null . snd) . fmap filterModuleDecls
9565 where
9666 filterModuleDecls :: Module -> Module
97− filterModuleDecls (moduleIdent,decls) =
98− (moduleIdent, filter (`predicate` search) decls)
67+ filterModuleDecls (moduleIdent, decls) =
68+ (moduleIdent, filter (flip predicate search . getDeclaration) decls)
69+ getDeclaration (IdeDeclarationAnn _ d) = d
9970
10071runFilter :: Filter -> [Module] -> [Module]
101−runFilter (Filter f)= appEndo f
72+runFilter (Filter f) = appEndo f
10273
10374applyFilters :: [Filter] -> [Module] -> [Module]
10475applyFilters = runFilter . fold
10576
10677instance FromJSON Filter where
10778 parseJSON = withObject "filter" $ \o -> do
108− (filter' :: String) <- o .: "filter"
79+ (filter' :: Text) <- o .: "filter"
10980 case filter' of
11081 "exact" -> do
11182 params <- o .: "params"
@@ -117,10 +88,6 @@ instance FromJSON Filter where
11788 return $ prefixFilter search
11889 "modules" -> do
11990 params <- o .: "params"
120− modules <- params .: "modules"
91+ modules <- map P.moduleNameFromString <$> params .: "modules"
12192 return $ moduleFilter modules
122− "dependencies" -> do
123− params <- o .: "params"
124− deps <- params .: "modules"
125− return $ dependencyFilter deps
12693 _ -> mzero
src/Language/PureScript/Ide/Imports.hs+37−51
@@ -13,7 +13,6 @@
1313-----------------------------------------------------------------------------
1414
1515{-# LANGUAGE OverloadedStrings #-}
16−{-# LANGUAGE PackageImports #-}
1716
1817module Language.PureScript.Ide.Imports
1918 ( addImplicitImport
@@ -30,28 +29,18 @@ module Language.PureScript.Ide.Imports
3029 )
3130 where
3231
33−import Prelude.Compat
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)
32+import Protolude
4433import qualified Data.Text as T
34+import Data.List (nubBy, findIndex)
4535import qualified Data.Text.IO as TIO
4636import qualified Language.PureScript as P
4737import Language.PureScript.Ide.Completion
4838import Language.PureScript.Ide.Error
49−import Language.PureScript.Ide.Externs (unwrapPositioned,
50− unwrapPositionedRef)
5139import Language.PureScript.Ide.Filter
5240import Language.PureScript.Ide.State
5341import Language.PureScript.Ide.Types
5442import Language.PureScript.Ide.Util
43+import System.FilePath
5544
5645data Import = Import P.ModuleName P.ImportDeclarationType (Maybe P.ModuleName)
5746 deriving (Eq, Show)
@@ -87,7 +76,7 @@ parseImportsFromFile fp = do
8776 Right res -> pure res
8877 Left err -> throwError (GeneralError err)
8978
90−parseImportsWithModuleName :: [Text] -> Either String (P.ModuleName, [Import])
79+parseImportsWithModuleName :: [Text] -> Either Text (P.ModuleName, [Import])
9180parseImportsWithModuleName ls = do
9281 (P.Module _ _ mn decls _) <- moduleParse ls
9382 pure (mn, concatMap mkImport (unwrapPositioned <$> decls))
@@ -97,13 +86,13 @@ parseImportsWithModuleName ls = do
9786 mkImport (P.ImportDeclaration mn it qual) = [Import mn it qual]
9887 mkImport _ = []
9988
100−sliceImportSection :: [Text] -> Either String (P.ModuleName, [Text], [Import], [Text])
89+sliceImportSection :: [Text] -> Either Text (P.ModuleName, [Text], [Import], [Text])
10190sliceImportSection ts =
10291 case foldl step (ModuleHeader 0) (zip [0..] ts) of
10392 Res start end ->
10493 let
10594 (moduleHeader, (importSection, remainingFile)) =
106− List.splitAt (succ (end - start)) `second` List.splitAt start ts
95+ splitAt (succ (end - start)) `second` splitAt start ts
10796 in
10897 (\(mn, is) -> (mn, moduleHeader, is, remainingFile)) <$>
10998 parseImportsWithModuleName (moduleHeader <> importSection)
@@ -111,7 +100,7 @@ sliceImportSection ts =
111100 -- If we don't find any imports, we insert a newline after the module
112101 -- declaration and begin a new importsection
113102 ModuleHeader ix ->
114− let (moduleHeader, remainingFile) = List.splitAt (succ ix) ts
103+ let (moduleHeader, remainingFile) = splitAt (succ ix) ts
115104 in
116105 (\(mn, is) -> (mn, moduleHeader ++ [""], is, remainingFile)) <$>
117106 parseImportsWithModuleName moduleHeader
@@ -153,7 +142,7 @@ step (ImportSection start lastImportLine) (ix, l)
153142 | otherwise = Res start lastImportLine
154143step (Res start end) _ = Res start end
155144
156−moduleParse :: [Text] -> Either String P.Module
145+moduleParse :: [Text] -> Either Text P.Module
157146moduleParse t = first show $ do
158147 tokens <- (P.lex "" . T.unpack . T.unlines) t
159148 P.runTokenParser "<psc-ide>" P.parseModule tokens
@@ -182,8 +171,8 @@ addImplicitImport' imports mn =
182171-- So @addExplicitImport "/File.purs" "bind" "Prelude"@ with an already existing
183172-- @import Prelude (bind)@ in the file File.purs returns @["import Prelude
184173-- (bind, unit)"]@
185−addExplicitImport :: (MonadIO m, MonadError PscIdeError m, MonadLogger m) =>
186− FilePath -> ExternDecl -> P.ModuleName -> m [Text]
174+addExplicitImport :: (MonadIO m, MonadError PscIdeError m) =>
175+ FilePath -> IdeDeclaration -> P.ModuleName -> m [Text]
187176addExplicitImport fp decl moduleName = do
188177 (mn, pre, imports, post) <- parseImportsFromFile fp
189178 let newImportSection =
@@ -194,7 +183,7 @@ addExplicitImport fp decl moduleName = do
194183 else addExplicitImport' decl moduleName imports
195184 pure (pre ++ prettyPrintImportSection newImportSection ++ post)
196185
197−addExplicitImport' :: ExternDecl -> P.ModuleName -> [Import] -> [Import]
186+addExplicitImport' :: IdeDeclaration -> P.ModuleName -> [Import] -> [Import]
198187addExplicitImport' decl moduleName imports =
199188 let
200189 isImplicitlyImported =
@@ -209,37 +198,34 @@ addExplicitImport' decl moduleName imports =
209198 then imports
210199 else updateAtFirstOrPrepend matches (insertDeclIntoImport decl) freshImport imports
211200 where
212− refFromDeclaration (TypeClassDeclaration n) =
201+ refFromDeclaration (IdeTypeClass n) =
213202 P.TypeClassRef n
214− refFromDeclaration (DataConstructor n tn _) =
215− P.TypeRef tn (Just [P.ProperName (T.unpack n)])
216− refFromDeclaration (TypeDeclaration n _) =
203+ refFromDeclaration (IdeDataConstructor n tn _) =
204+ P.TypeRef tn (Just [n])
205+ refFromDeclaration (IdeType n _) =
217206 P.TypeRef n (Just [])
218− refFromDeclaration (ValueOperator op _ _ _) =
207+ refFromDeclaration (IdeValueOperator op _ _ _) =
219208 P.ValueOpRef op
220− refFromDeclaration (TypeOperator op _ _ _) =
209+ refFromDeclaration (IdeTypeOperator op _ _ _) =
221210 P.TypeOpRef op
222211 refFromDeclaration d =
223− P.ValueRef $ P.Ident $ T.unpack (identifierFromExternDecl d)
212+ P.ValueRef $ P.Ident $ T.unpack (identifierFromIdeDeclaration d)
224213
225214 -- | Adds a declaration to an import:
226215 -- TypeDeclaration "Maybe" + Data.Maybe (maybe) -> Data.Maybe(Maybe, maybe)
227− insertDeclIntoImport :: ExternDecl -> Import -> Import
216+ insertDeclIntoImport :: IdeDeclaration -> Import -> Import
228217 insertDeclIntoImport decl' (Import mn (P.Explicit refs) Nothing) =
229218 Import mn (P.Explicit (insertDeclIntoRefs decl' refs)) Nothing
230219 insertDeclIntoImport _ is = is
231220
232− insertDeclIntoRefs :: ExternDecl -> [P.DeclarationRef] -> [P.DeclarationRef]
233− insertDeclIntoRefs (DataConstructor 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
238− insertDeclIntoRefs dr refs = List.nubBy ((==) `on` P.prettyPrintRef) (refFromDeclaration dr : refs)
221+ insertDeclIntoRefs :: IdeDeclaration -> [P.DeclarationRef] -> [P.DeclarationRef]
222+ insertDeclIntoRefs (IdeDataConstructor dtor tn _) refs =
223+ updateAtFirstOrPrepend (matchType tn) (insertDtor dtor) (P.TypeRef tn (Just [dtor])) refs
224+ insertDeclIntoRefs dr refs = nubBy ((==) `on` P.prettyPrintRef) (refFromDeclaration dr : refs)
239225
240226 insertDtor dtor (P.TypeRef tn' dtors) =
241227 case dtors of
242− Just dtors' -> P.TypeRef tn' (Just (List.nub (dtor : dtors')))
228+ Just dtors' -> P.TypeRef tn' (Just (ordNub (dtor : dtors')))
243229 -- This means the import was opened. We don't add anything in this case
244230 -- import Data.Maybe (Maybe(..)) -> import Data.Maybe (Maybe(Just))
245231 Nothing -> P.TypeRef tn' Nothing
@@ -251,10 +237,10 @@ addExplicitImport' decl moduleName imports =
251237
252238updateAtFirstOrPrepend :: (a -> Bool) -> (a -> a) -> a -> [a] -> [a]
253239updateAtFirstOrPrepend p t d l =
254− case List.findIndex p l of
240+ case findIndex p l of
255241 Nothing -> d : l
256242 Just ix ->
257− let (x, a : y) = List.splitAt ix l
243+ let (x, a : y) = splitAt ix l
258244 in x ++ [t a] ++ y
259245
260246-- | Looks up the given identifier in the currently loaded modules.
@@ -265,30 +251,30 @@ updateAtFirstOrPrepend p t d l =
265251--
266252-- * If more than one possible imports are found, reports the possibilities as a
267253-- list of completions.
268−addImportForIdentifier :: (PscIde m, MonadError PscIdeError m, MonadLogger m)
254+addImportForIdentifier :: (Ide m, MonadError PscIdeError m)
269255 => FilePath -- ^ The Sourcefile to read from
270256 -> Text -- ^ The identifier to import
271257 -> [Filter] -- ^ Filters to apply before searching for
272258 -- the identifier
273− -> m (Either [Match] [Text])
259+ -> m (Either [Match IdeDeclaration] [Text])
274260addImportForIdentifier fp ident filters = do
275− modules <- getAllModulesWithReexports
276− case getExactMatches ident filters modules of
261+ modules <- getAllModules Nothing
262+ case map (fmap discardAnn) (getExactMatches ident filters modules) of
277263 [] ->
278264 throwError (NotFound "Couldn't find the given identifier. \
279265 \Have you loaded the corresponding module?")
280266
281267 -- Only one match was found for the given identifier, so we can insert it
282268 -- right away
283− [Match m decl] ->
284− Right <$> addExplicitImport fp decl (P.moduleNameFromString (T.unpack m))
269+ [Match (m, decl)] ->
270+ Right <$> addExplicitImport fp decl m
285271
286272 -- This case comes up for newtypes and dataconstructors. Because values and
287273 -- types don't share a namespace we can get multiple matches from the same
288274 -- module. This also happens for parameterized types, as these generate both
289275 -- a type aswell as a type synonym.
290276
291− ms@[Match m1 d1, Match m2 d2] ->
277+ ms@[Match (m1, d1), Match (m2, d2)] ->
292278 if m1 /= m2
293279 -- If the modules don't line up we just ask the user to specify the
294280 -- module
@@ -298,7 +284,7 @@ addImportForIdentifier fp ident filters = do
298284 -- dataconstructor as that will give us an unnecessary import warning at
299285 -- worst
300286 Just decl ->
301− Right <$> addExplicitImport fp decl (P.moduleNameFromString (T.unpack m1))
287+ Right <$> addExplicitImport fp decl m1
302288 -- Here we need the user to specify whether he wanted a dataconstructor
303289 -- or a type
304290 Nothing ->
@@ -309,9 +295,9 @@ addImportForIdentifier fp ident filters = do
309295 xs ->
310296 pure $ Left xs
311297 where
312− decideRedundantCase dtor@(DataConstructor _ t _) (TypeDeclaration t' _) =
298+ decideRedundantCase dtor@(IdeDataConstructor _ t _) (IdeType t' _) =
313299 if t == t' then Just dtor else Nothing
314− decideRedundantCase TypeDeclaration{} ts@TypeSynonymDeclaration{} =
300+ decideRedundantCase IdeType{} ts@IdeTypeSynonym{} =
315301 Just ts
316302 decideRedundantCase _ _ = Nothing
317303
@@ -323,7 +309,7 @@ prettyPrintImport' (Import mn idt qual) =
323309 T.pack $ "import " ++ P.prettyPrintImport mn idt qual
324310
325311prettyPrintImportSection :: [Import] -> [Text]
326−prettyPrintImportSection imports = map prettyPrintImport' (List.sort imports)
312+prettyPrintImportSection imports = map prettyPrintImport' (sort imports)
327313
328314-- | Writes a list of lines to @Just filepath@ and responds with a @TextResult@,
329315-- 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 @@
1414
1515{-# LANGUAGE GeneralizedNewtypeDeriving #-}
1616{-# LANGUAGE OverloadedStrings #-}
17+{-# LANGUAGE FlexibleInstances #-}
1718
1819module Language.PureScript.Ide.Matcher
1920 ( Matcher
20− , flexMatcher
2121 , runMatcher
22+ -- for tests
23+ , flexMatcher
2224 ) where
2325
24−import Prelude ()
25−import Prelude.Compat
26+import Protolude
2627
27−import Control.Monad
2828import 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)
3429import qualified Data.Text as T
3530import qualified Data.Text.Encoding as TE
3631import Language.PureScript.Ide.Types
@@ -39,23 +34,22 @@ import Text.EditDistance
3934import Text.Regex.TDFA ((=~))
4035
4136
42−type ScoredMatch = (Match, Double)
37+type ScoredMatch a = (Match a, Double)
4338
44−newtype Matcher = Matcher (Endo [Match]) deriving(Monoid)
39+newtype Matcher a = Matcher (Endo [Match a]) deriving (Monoid)
4540
46−instance FromJSON Matcher where
41+instance FromJSON (Matcher IdeDeclaration) where
4742 parseJSON = withObject "matcher" $ \o -> do
48− (matcher :: Maybe String) <- o .:? "matcher"
43+ (matcher :: Maybe Text) <- o .:? "matcher"
4944 case matcher of
5045 Just "flex" -> do
5146 params <- o .: "params"
52− search <- params .: "search"
53− pure $ flexMatcher search
47+ flexMatcher <$> params .: "search"
5448 Just "distance" -> do
5549 params <- o .: "params"
56− search <- params .: "search"
57− maxDist <- params .: "maximumDistance"
58− pure $ distanceMatcher search maxDist
50+ distanceMatcher
51+ <$> params .: "search"
52+ <*> params .: "maximumDistance"
5953 Just _ -> mzero
6054 Nothing -> return mempty
6155
@@ -66,37 +60,37 @@ instance FromJSON Matcher where
6660-- Examples:
6761-- flMa matches flexMatcher. Score: 14.28
6862-- sons matches sortCompletions. Score: 6.25
69−flexMatcher :: Text -> Matcher
63+flexMatcher :: Text -> Matcher IdeDeclaration
7064flexMatcher p = mkMatcher (flexMatch p)
7165
72−distanceMatcher :: Text -> Int -> Matcher
66+distanceMatcher :: Text -> Int -> Matcher IdeDeclaration
7367distanceMatcher q maxDist = mkMatcher (distanceMatcher' q maxDist)
7468
75−distanceMatcher' :: Text -> Int -> [Match] -> [ScoredMatch]
69+distanceMatcher' :: Text -> Int -> [Match IdeDeclaration] -> [ScoredMatch IdeDeclaration]
7670distanceMatcher' q maxDist = mapMaybe go
7771 where
7872 go m = let d = dist (T.unpack y)
79− y = identifierFromMatch m
73+ y = identifierFromIdeDeclaration (unwrapMatch m)
8074 in if d <= maxDist
8175 then Just (m, 1 / fromIntegral d)
8276 else Nothing
8377 dist = levenshteinDistance defaultEditCosts (T.unpack q)
8478
85−mkMatcher :: ([Match] -> [ScoredMatch]) -> Matcher
79+mkMatcher :: ([Match a] -> [ScoredMatch a]) -> Matcher a
8680mkMatcher matcher = Matcher . Endo $ fmap fst . sortCompletions . matcher
8781
88−runMatcher :: Matcher -> [Match] -> [Match]
82+runMatcher :: Matcher a -> [Match a] -> [Match a]
8983runMatcher (Matcher m)= appEndo m
9084
91−sortCompletions :: [ScoredMatch] -> [ScoredMatch]
85+sortCompletions :: [ScoredMatch a] -> [ScoredMatch a]
9286sortCompletions = sortBy (flip compare `on` snd)
9387
94−flexMatch :: Text -> [Match] -> [ScoredMatch]
88+flexMatch :: Text -> [Match IdeDeclaration] -> [ScoredMatch IdeDeclaration]
9589flexMatch = mapMaybe . flexRate
9690
97−flexRate :: Text -> Match -> Maybe ScoredMatch
91+flexRate :: Text -> Match IdeDeclaration -> Maybe (ScoredMatch IdeDeclaration)
9892flexRate p c = do
99− score <- flexScore p (identifierFromMatch c)
93+ score <- flexScore p (identifierFromIdeDeclaration (unwrapMatch c))
10094 return (c, score)
10195
10296-- FlexMatching ala Sublime.
@@ -105,11 +99,11 @@ flexRate p c = do
10599-- By string =~ pattern we'll get the start of the match and the length of
106100-- the matchas a (start, length) tuple if there's a match.
107101-- If match fails then it would be (-1,0)
108−flexScore :: Text -> DeclIdent -> Maybe Double
102+flexScore :: Text -> Text -> Maybe Double
109103flexScore pat str =
110104 case T.uncons pat of
111105 Nothing -> Nothing
112− Just (first, p) ->
106+ Just (first', p) ->
113107 case TE.encodeUtf8 str =~ TE.encodeUtf8 pat' :: (Int, Int) of
114108 (-1,0) -> Nothing
115109 (start,len) -> Just $ calcScore start (start + len)
@@ -120,11 +114,11 @@ flexScore pat str =
120114 -- escape prepends a backslash to "regexy" characters to prevent the
121115 -- matcher from crashing when trying to build the regex
122116 escape :: Char -> Text
123− escape c = if c `elem` ("[\\^$.|?*+(){}" :: String)
117+ escape c = if c `elem` T.unpack "[\\^$.|?*+(){}"
124118 then T.pack ['\\', c]
125119 else T.singleton c
126120 -- This just interleaves the search pattern with .*
127121 -- abcd[*] -> a.*b.*c.*d.*[*]
128− pat' = escape first <> foldMap (<> ".*") escapedPattern
122+ pat' = escape first' <> foldMap (<> ".*") escapedPattern
129123 calcScore start end =
130124 100.0 / fromIntegral ((1 + start) * (end - start + 1))
src/Language/PureScript/Ide/Pursuit.hs+9−12
@@ -14,20 +14,17 @@
1414
1515{-# LANGUAGE OverloadedStrings #-}
1616
17−module Language.PureScript.Ide.Pursuit where
17+module Language.PureScript.Ide.Pursuit
18+ ( searchPursuitForDeclarations
19+ , findPackagesForModuleIdent
20+ ) where
1821
19−import Prelude ()
20−import Prelude.Compat
22+import Protolude
2123
2224import qualified Control.Exception as E
2325import Data.Aeson
24−import Data.ByteString (ByteString)
2526import Data.ByteString.Lazy (fromStrict)
26−import Data.Foldable (toList)
27−import Data.Maybe (mapMaybe)
28−import Data.Monoid ((<>))
2927import Data.String
30−import Data.Text (Text)
3128import qualified Data.Text as T
3229import Language.PureScript.Ide.Types
3330import Network.HTTP.Types.Header (hAccept)
@@ -41,12 +38,12 @@ queryPursuit q = do
4138 let qClean = T.dropWhileEnd (== '.') q
4239 req' <- parseUrl "http://pursuit.purescript.org/search"
4340 let req = req'
44− { queryString=("q=" <> (fromString . T.unpack) qClean)
41+ { queryString= "q=" <> (fromString . T.unpack) qClean
4542 , requestHeaders=[(hAccept, "application/json")]
4643 }
4744 m <- newManager tlsManagerSettings
4845 withHTTP req m $ \resp ->
49− P.fold (<>) "" id $ responseBody resp
46+ P.fold (<>) "" identity (responseBody resp)
5047
5148
5249handler :: HttpException -> IO [a]
@@ -59,7 +56,7 @@ searchPursuitForDeclarations query =
5956 let results' = decode (fromStrict r) :: Maybe Array
6057 case results' of
6158 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`
6360 handler
6461 where
6562 isDeclarationResponse (Success a@DeclarationResponse{}) = Just a
@@ -71,7 +68,7 @@ findPackagesForModuleIdent query =
7168 let results' = decode (fromStrict r) :: Maybe Array
7269 case results' of
7370 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`
7572 handler
7673 where
7774 isModuleResponse (Success a@ModuleResponse{}) = Just a
src/Language/PureScript/Ide/Rebuild.hs+16−18
@@ -8,14 +8,12 @@ module Language.PureScript.Ide.Rebuild
88 ( rebuildFile
99 ) where
1010
11−import Control.Monad.Error.Class
12−import Control.Monad.IO.Class
11+import Protolude
12+
1313import "monad-logger" Control.Monad.Logger
14−import Control.Monad.Reader
15−import Control.Monad.Trans.Except
14+import qualified Data.List as List
1615import qualified Data.Map.Lazy as M
17−import Data.Maybe (fromJust, mapMaybe)
18−import Data.Monoid ((<>))
16+import Data.Maybe (fromJust)
1917import qualified Data.Set as S
2018import qualified Language.PureScript as P
2119import Language.PureScript.Errors.JSON
@@ -23,8 +21,8 @@ import Language.PureScript.Ide.Error
2321import Language.PureScript.Ide.State
2422import Language.PureScript.Ide.Types
2523import Language.PureScript.Ide.Util
26−import Prelude.Compat
2724import System.IO.UTF8 (readUTF8File)
25+import System.FilePath
2826
2927-- | Given a filepath performs the following steps:
3028--
@@ -42,14 +40,14 @@ import System.IO.UTF8 (readUTF8File)
4240-- warnings, and if rebuilding fails, returns a @RebuildError@ with the
4341-- generated errors.
4442rebuildFile
45− :: (PscIde m, MonadLogger m, MonadError PscIdeError m)
43+ :: (Ide m, MonadLogger m, MonadError PscIdeError m)
4644 => FilePath
4745 -> m Success
4846rebuildFile path = do
4947
5048 input <- liftIO (readUTF8File path)
5149
52− m <- case snd <$> P.parseModuleFromFile id (path, input) of
50+ m <- case snd <$> P.parseModuleFromFile identity (path, input) of
5351 Left parseError -> throwError
5452 . RebuildError
5553 . toJSONErrors False P.Error
@@ -60,7 +58,7 @@ rebuildFile path = do
6058 -- correctly to the 'Environment'.
6159 externs <- sortExterns m =<< getExternFiles
6260
63− outputDirectory <- confOutputPath . envConfiguration <$> ask
61+ outputDirectory <- confOutputPath . ideConfiguration <$> ask
6462
6563 -- For rebuilding, we want to 'RebuildAlways', but for inferring foreign
6664 -- modules using their file paths, we need to specify the path in the 'Map'.
@@ -82,7 +80,7 @@ rebuildFile path = do
8280-- | Rebuilds a module but opens up its export list first and stores the result
8381-- inside the rebuild cache
8482rebuildModuleOpen
85− :: (PscIde m, MonadLogger m, MonadError PscIdeError m)
83+ :: (Ide m, MonadLogger m, MonadError PscIdeError m)
8684 => MakeActionsEnv
8785 -> [P.ExternsFile]
8886 -> P.Module
@@ -100,14 +98,14 @@ rebuildModuleOpen makeEnv externs m = do
10098 Right result -> do
10199 $(logDebug)
102100 ("Setting Rebuild cache: " <> runModuleNameT (P.efModuleName result))
103− setCachedRebuild result
101+ cacheRebuild result
104102
105103-- | Parameters we can access while building our @MakeActions@
106104data MakeActionsEnv =
107105 MakeActionsEnv
108106 { maeOutputDirectory :: FilePath
109− , maeFilePathMap :: M.Map P.ModuleName (Either P.RebuildPolicy FilePath)
110− , maeForeignPathMap :: M.Map P.ModuleName FilePath
107+ , maeFilePathMap :: Map P.ModuleName (Either P.RebuildPolicy FilePath)
108+ , maeForeignPathMap :: Map P.ModuleName FilePath
111109 , maePrefixComment :: Bool
112110 }
113111
@@ -135,9 +133,9 @@ shushCodegen ma MakeActionsEnv{..} =
135133-- module. Throws an error if there is a cyclic dependency within the
136134-- ExternsFiles
137135sortExterns
138− :: (PscIde m, MonadError PscIdeError m)
136+ :: (Ide m, MonadError PscIdeError m)
139137 => P.Module
140− -> M.Map P.ModuleName P.ExternsFile
138+ -> Map P.ModuleName P.ExternsFile
141139 -> m [P.ExternsFile]
142140sortExterns m ex = do
143141 sorted' <- runExceptT
@@ -149,11 +147,11 @@ sortExterns m ex = do
149147 case sorted' of
150148 Left _ -> throwError (GeneralError "There was a cycle in the dependencies")
151149 Right (sorted, graph) -> do
152− let deps = fromJust (lookup (P.getModuleName m) graph)
150+ let deps = fromJust (List.lookup (P.getModuleName m) graph)
153151 pure $ mapMaybe getExtern (deps `inOrderOf` map P.getModuleName sorted)
154152 where
155153 mkShallowModule P.ExternsFile{..} =
156− P.Module undefined [] efModuleName (map mkImport efImports) Nothing
154+ P.Module (P.internalModuleSourceSpan "<rebuild>") [] efModuleName (map mkImport efImports) Nothing
157155 mkImport (P.ExternsImport mn it iq) =
158156 P.ImportDeclaration mn it iq
159157 getExtern mn = M.lookup mn ex
src/Language/PureScript/Ide/Reexports.hs+93−64
@@ -14,76 +14,105 @@
1414-----------------------------------------------------------------------------
1515
1616{-# LANGUAGE OverloadedStrings #-}
17+{-# LANGUAGE PackageImports #-}
18+{-# LANGUAGE TemplateHaskell #-}
19+{-# LANGUAGE RecordWildCards #-}
1720
18−module Language.PureScript.Ide.Reexports where
21+module Language.PureScript.Ide.Reexports
22+ ( resolveReexports
23+ , prettyPrintReexportResult
24+ , reexportHasFailures
25+ , ReexportResult(..)
26+ ) where
1927
28+import Protolude
2029
21−import Prelude ()
22−import Prelude.Compat
23−
24−import Data.List (union)
25−import Data.Map (Map)
2630import qualified Data.Map as Map
27−import Data.Maybe
2831import Language.PureScript.Ide.Types
29−
30−getReexports :: Module -> [ExternDecl]
31−getReexports (mn, decls)= concatMap getExport decls
32− where getExport d
33− | (Export mn') <- d
34− , mn /= mn' = replaceExportWithAliases decls mn'
35− | otherwise = []
36−
37−dependencyToExport :: ExternDecl -> ExternDecl
38−dependencyToExport (Dependency m _ _) = Export m
39−dependencyToExport decl = decl
40−
41−replaceExportWithAliases :: [ExternDecl] -> ModuleIdent -> [ExternDecl]
42−replaceExportWithAliases decls ident =
43− case filter isMatch decls of
44− [] -> [Export ident]
45− aliases -> map dependencyToExport aliases
46− where isMatch d
47− | Dependency _ _ (Just alias) <- d
48− , alias == ident = True
49− | otherwise = False
50−
51−replaceReexport :: ExternDecl -> Module -> Module -> Module
52−replaceReexport e@(Export _) (m, decls) (_, newDecls) =
53− (m, filter (/= e) decls `union` newDecls)
54−replaceReexport _ _ _ = error "Should only get Exports here."
55−
56−emptyModule :: Module
57−emptyModule = ("Empty", [])
58−
59−isExport :: ExternDecl -> Bool
60−isExport (Export _) = True
61−isExport _ = False
62−
63−removeExportDecls :: Module -> Module
64−removeExportDecls = fmap (filter (not . isExport))
65−
66−replaceReexports :: Module -> Map ModuleIdent [ExternDecl] -> Module
67−replaceReexports m db = result
32+import Language.PureScript.Ide.Util
33+import qualified Language.PureScript as P
34+
35+-- | Contains the module with resolved reexports, and eventual failures
36+data ReexportResult a
37+ = ReexportResult
38+ { reResolved :: a
39+ , reFailed :: [(P.ModuleName, P.DeclarationRef)]
40+ } deriving (Show, Eq, Functor)
41+
42+-- | Uses the passed formatter to format the resolved module, and adds eventual
43+-- failures
44+prettyPrintReexportResult
45+ :: (a -> Text)
46+ -- ^ Formatter for the resolved result
47+ -> ReexportResult a
48+ -- ^ The Result to be pretty printed
49+ -> Text
50+prettyPrintReexportResult f ReexportResult{..}
51+ | null reFailed =
52+ "Successfully resolved reexports for " <> f reResolved
53+ | otherwise =
54+ "Failed to resolve reexports for "
55+ <> f reResolved
56+ <> foldMap (\(mn, ref) -> runModuleNameT mn <> show ref) reFailed
57+
58+-- | Whether any Refs couldn't be resolved
59+reexportHasFailures :: ReexportResult a -> Bool
60+reexportHasFailures = not . null . reFailed
61+
62+-- | Resolves Reexports for a given Module, by looking up the reexported values
63+-- from the passed in Map
64+resolveReexports
65+ :: Map P.ModuleName [IdeDeclarationAnn]
66+ -- ^ Modules to search for the reexported declarations
67+ -> (Module, [(P.ModuleName, P.DeclarationRef)])
68+ -- ^ The module to resolve reexports for, aswell as the references to resolve
69+ -> ReexportResult Module
70+resolveReexports modules ((moduleName, decls), refs) =
71+ ReexportResult (moduleName, decls <> concat resolvedRefs) failedRefs
6872 where
69− reexports = getReexports m
70− result = foldl go (removeExportDecls m) reexports
73+ (failedRefs, resolvedRefs) = partitionEithers (resolveRef' <$> refs)
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
71107
72− go :: Module -> ExternDecl -> Module
73− go m' re@(Export name) = replaceReexport re m' (getModule name)
74− go _ _ = error "partiality! woohoo"
108+ lookupDtor name =
109+ findRef (\case IdeDataConstructor name' _ _ -> name == name'
110+ _ -> False)
75111
76− getModule :: ModuleIdent -> Module
77− getModule name = clean res
112+ findDtors tn = filter (f . discardAnn) decls
78113 where
79− res = fromMaybe emptyModule $ (name , ) <$> Map.lookup name db
80− -- we have to do this because keeping self exports in will result in
81− -- infinite loops
82− clean (mn, decls) = (mn,) (filter (/= Export mn) decls)
83−
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
114+ f :: IdeDeclaration -> Bool
115+ f decl
116+ | (IdeDataConstructor _ tn' _) <- decl
117+ , tn == tn' = True
118+ | otherwise = False
src/Language/PureScript/Ide/SourceFile.hs+73−88
@@ -14,107 +14,92 @@
1414
1515{-# LANGUAGE OverloadedStrings #-}
1616
17−module Language.PureScript.Ide.SourceFile where
17+module Language.PureScript.Ide.SourceFile
18+ ( parseModule
19+ , getImportsForFile
20+ , extractSpans
21+ ) where
1822
19−import Prelude
23+import Protolude
2024
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
28−import qualified Language.PureScript.AST.SourcePos as SP
25+import qualified Language.PureScript as P
2926import Language.PureScript.Ide.Error
30−import Language.PureScript.Ide.Externs (unwrapPositioned,
31− unwrapPositionedRef)
27+import Language.PureScript.Ide.Util
3228import Language.PureScript.Ide.Types
33−import qualified Language.PureScript.Names as N
34−import qualified Language.PureScript.Parser as P
35−import System.Directory
29+import System.FilePath
3630import System.IO.UTF8 (readUTF8File)
3731
38−parseModuleFromFile :: (MonadIO m, MonadError PscIdeError m) =>
39− FilePath -> m D.Module
40−parseModuleFromFile fp = do
41− exists <- liftIO (doesFileExist fp)
42− if exists
43− then do
44− content <- liftIO (readUTF8File fp)
45− let m = do tokens <- P.lex fp content
46− P.runTokenParser "" P.parseModule tokens
47− either (throwError . (`ParseError` "File could not be parsed.")) pure m
48− else throwError (NotFound "File does not exist.")
32+parseModule
33+ :: (MonadIO m)
34+ => FilePath
35+ -> m (Either FilePath (FilePath, P.Module) )
36+parseModule path = do
37+ contents <- liftIO (readUTF8File path)
38+ case P.parseModuleFromFile identity (path, contents) of
39+ Left _ -> pure (Left path)
40+ Right m -> pure (Right m)
4941
50−-- data Module = Module SourceSpan [Comment] ModuleName [Declaration] (Maybe [DeclarationRef])
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 _) =
42+getImports :: P.Module -> [(P.ModuleName, P.ImportDeclarationType, Maybe P.ModuleName)]
43+getImports (P.Module _ _ _ declarations _) =
5744 mapMaybe isImport declarations
5845 where
59− isImport (D.PositionedDeclaration _ _ (i@D.ImportDeclaration{})) = Just i
46+ isImport (P.PositionedDeclaration _ _ (P.ImportDeclaration a b c)) = Just (a, b, c)
6047 isImport _ = Nothing
6148
6249getImportsForFile :: (MonadIO m, MonadError PscIdeError m) =>
6350 FilePath -> m [ModuleImport]
6451getImportsForFile fp = do
65− module' <- parseModuleFromFile fp
66− let imports = getImports module'
67− pure (mkModuleImport . unwrapPositionedImport <$> imports)
68− where
69− mkModuleImport (D.ImportDeclaration mn importType' qualifier) =
70− ModuleImport
71− (T.pack (N.runModuleName mn))
72− importType'
73− (T.pack . N.runModuleName <$> qualifier)
74− mkModuleImport _ = error "Shouldn't have gotten anything but Imports here"
75− unwrapPositionedImport (D.ImportDeclaration mn importType' qualifier) =
76− D.ImportDeclaration mn (unwrapImportType importType') qualifier
77− unwrapPositionedImport x = x
78− unwrapImportType (D.Explicit decls) = D.Explicit (map unwrapPositionedRef decls)
79− unwrapImportType (D.Hiding decls) = D.Hiding (map unwrapPositionedRef decls)
80− unwrapImportType D.Implicit = D.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
52+ moduleE <- parseModule fp
53+ case moduleE of
54+ Left _ -> throwError (GeneralError "Failed to parse sourcefile.")
55+ Right (_, module') ->
56+ pure (mkModuleImport . unwrapPositionedImport <$> getImports module')
57+ where
58+ mkModuleImport (mn, importType', qualifier) =
59+ ModuleImport
60+ (runModuleNameT mn)
61+ importType'
62+ (runModuleNameT <$> qualifier)
63+ unwrapPositionedImport (mn, it, q) = (mn, unwrapImportType it, q)
64+ unwrapImportType (P.Explicit decls) = P.Explicit (map unwrapPositionedRef decls)
65+ unwrapImportType (P.Hiding decls) = P.Hiding (map unwrapPositionedRef decls)
66+ unwrapImportType P.Implicit = P.Implicit
8867
89−getDeclPosition :: D.Module -> String -> Maybe SP.SourceSpan
90−getDeclPosition m ident = getFirst (foldMap (match ident) decls)
68+-- | Given a surrounding Sourcespan and a Declaration from the PS AST, extracts
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+ _ -> []
9195 where
92− decls = getDeclarations m
93− match q (D.PositionedDeclaration ss _ decl) = First (if go q decl
94− then Just ss
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− go q (D.ValueDeclaration ident' _ _ _) = identEqual ident' q
104− go q (D.ExternDeclaration ident' _) = identEqual ident' q
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
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
101+ P.PositionedDeclaration ssP' _ dP' ->
102+ extractSpans' ssP' dP'
103+ P.TypeDeclaration ident _ ->
104+ [(Left (runIdentT ident), ssP)]
105+ _ -> []
src/Language/PureScript/Ide/State.hs+168−97
@@ -17,127 +17,198 @@
1717{-# LANGUAGE TemplateHaskell #-}
1818
1919module Language.PureScript.Ide.State
20− ( getPscIdeState
20+ ( getLoadedModulenames
2121 , getExternFiles
22− , getModule
23− , getModuleWithReexports
24− , getAllModulesWithReexports
25− , getAllModulesWithReexportsAndCache
22+ , resetIdeState
23+ , cacheRebuild
24+ , insertExterns
2625 , insertModule
27− , insertModuleSTM
28− , getCachedRebuild
29− , resetPscIdeState
30− , setCachedRebuild
26+ , insertExternsSTM
27+ , getAllModules
28+ , populateStage2
29+ , populateStage3
30+ , populateStage3STM
3131 ) where
3232
33−import Prelude ()
34−import Prelude.Compat
33+import Protolude
34+import qualified Prelude
3535
3636import Control.Concurrent.STM
37−import Control.Monad.IO.Class
3837import "monad-logger" Control.Monad.Logger
39−import Control.Monad.Reader.Class
4038import qualified Data.Map.Lazy as M
41−import Data.Maybe (mapMaybe)
42−import Data.Monoid
4339import Language.PureScript.Externs
4440import Language.PureScript.Ide.Externs
4541import Language.PureScript.Ide.Reexports
42+import Language.PureScript.Ide.SourceFile
4643import Language.PureScript.Ide.Types
4744import Language.PureScript.Ide.Util
4845import qualified Language.PureScript as P
46+import System.Clock
47+import System.FilePath
4948
50−-- | Resets the PscIdeState to emptyPscIdeState
51−resetPscIdeState :: PscIde m => m ()
52−resetPscIdeState = do
53− stateVar <- envStateVar <$> ask
54− liftIO $ atomically (writeTVar stateVar emptyPscIdeState)
49+-- | Resets all State inside psc-ide
50+resetIdeState :: Ide m => m ()
51+resetIdeState = do
52+ ideVar <- ideStateVar <$> ask
53+ liftIO . atomically $ do
54+ writeTVar ideVar emptyIdeState
55+ setStage3STM ideVar emptyStage3
5556
56−-- | Gets the entire PscIdeState
57−getPscIdeState :: PscIde m => m PscIdeState
58−getPscIdeState = do
59− stateVar <- envStateVar <$> ask
60− liftIO (readTVarIO stateVar)
57+-- | Gets the loaded Modulenames
58+getLoadedModulenames :: Ide m => m [P.ModuleName]
59+getLoadedModulenames = M.keys <$> getExternFiles
6160
6261-- | Gets all loaded ExternFiles
63−getExternFiles :: (PscIde m) => m (M.Map P.ModuleName ExternsFile)
64−getExternFiles = do
65− stateVar <- envStateVar <$> ask
66− liftIO (pscIdeStateExternsFiles <$> readTVarIO stateVar)
62+getExternFiles :: Ide m => m (M.Map P.ModuleName ExternsFile)
63+getExternFiles = s1Externs <$> getStage1
6764
68−-- | Gets all loaded Modules and resolves Reexports
69−getAllModulesWithReexports :: (PscIde m) => m [Module]
70−getAllModulesWithReexports = getAllModulesWithReexports' <$> getPscIdeState
65+-- | Insert a Module into Stage1 of the State
66+insertModule :: Ide m => (FilePath, P.Module) -> m ()
67+insertModule module' = do
68+ stateVar <- ideStateVar <$> ask
69+ liftIO . atomically $ insertModuleSTM stateVar module'
7170
72−-- | Pure version of @getAllModulesWithReexports@
73−getAllModulesWithReexports' :: PscIdeState -> [Module]
74−getAllModulesWithReexports' state =
75− mapMaybe (getModuleWithReexports' state) (M.keys (pscIdeStateModules state))
71+-- | STM version of insertModule
72+insertModuleSTM :: TVar IdeState -> (FilePath, P.Module) -> STM ()
73+insertModuleSTM ref (fp, module') =
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 ()
76121
77122-- | Checks if the given ModuleName matches the last rebuild cache and if it
78−-- does, runs @getAllModulesWithReexports@ with the cached module replacing the
79−-- loaded module
80−getAllModulesWithReexportsAndCache
81− :: (PscIde m)
82− => Maybe P.ModuleName
83− -> m [Module]
84−getAllModulesWithReexportsAndCache Nothing = getAllModulesWithReexports
85−getAllModulesWithReexportsAndCache (Just mn) = do
86− state <- getPscIdeState
87− cachedRebuild <- getCachedRebuild
88− case cachedRebuild of
89− Just (cachedIdent, ef) | cachedIdent == mn ->
90− pure (getAllModulesWithReexports' (insertModule' ef state))
91− _ -> getAllModulesWithReexports
92−
93−-- | Looks up a single Module inside the loaded Modules
94−getModule :: (PscIde m, MonadLogger m) => ModuleIdent -> m (Maybe Module)
95−getModule m = getModule' <$> getPscIdeState <*> pure m
96−
97−-- | Pure version of @getModule@
98−getModule' :: PscIdeState -> ModuleIdent -> Maybe Module
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
112−insertModule :: (PscIde m, MonadLogger m) =>
113− ExternsFile -> m ()
114−insertModule externsFile = do
115− stateVar <- envStateVar <$> ask
116− let moduleName = efModuleName externsFile
117− $(logDebug) $ "Inserting Module: " <> runModuleNameT moduleName
118− liftIO . atomically $ insertModuleSTM stateVar externsFile
119−
120−-- | STM version of insertModule
121−insertModuleSTM :: TVar PscIdeState -> ExternsFile -> STM ()
122−insertModuleSTM st ef = modifyTVar st (insertModule' ef)
123−
124−-- | Pure version of insertModule
125−insertModule' :: ExternsFile -> PscIdeState -> PscIdeState
126−insertModule' ef state =
127− state
128− { pscIdeStateExternsFiles =
129− M.insert (efModuleName ef) ef (pscIdeStateExternsFiles state)
130− , pscIdeStateModules = let (mn, decls) = convertExterns ef
131− in M.insert mn decls (pscIdeStateModules state)
132− }
123+-- does returns all loaded definitions + the definitions inside the rebuild
124+-- cache
125+getAllModules :: Ide m => Maybe P.ModuleName -> m [Module]
126+getAllModules mmoduleName = do
127+ declarations <- s3Declarations <$> getStage3
128+ rebuild <- cachedRebuild
129+ case mmoduleName of
130+ Nothing -> pure (M.toList declarations)
131+ Just moduleName ->
132+ case rebuild of
133+ Just (cachedModulename, ef)
134+ | cachedModulename == moduleName -> do
135+ (AstData asts) <- s2AstData <$> getStage2
136+ let ast = fromMaybe M.empty (M.lookup moduleName asts)
137+ pure . M.toList $
138+ M.insert moduleName
139+ (snd . annotateLocations ast . fst . convertExterns $ ef) declarations
140+ _ -> pure (M.toList declarations)
141+
142+-- | Adds an ExternsFile into psc-ide's State Stage1. This does not populate the
143+-- following Stages, which needs to be done after all the necessary Exterms have
144+-- been loaded.
145+insertExterns :: Ide m => ExternsFile -> m ()
146+insertExterns ef = do
147+ st <- ideStateVar <$> ask
148+ liftIO (atomically (insertExternsSTM st ef))
149+
150+-- | STM version of insertExterns
151+insertExternsSTM :: TVar IdeState -> ExternsFile -> STM ()
152+insertExternsSTM ref ef =
153+ modifyTVar ref $ \x ->
154+ x { ideStage1 = (ideStage1 x) {
155+ s1Externs = M.insert (efModuleName ef) ef (s1Externs (ideStage1 x))}}
133156
134157-- | Sets rebuild cache to the given ExternsFile
135−setCachedRebuild :: PscIde m => ExternsFile -> m ()
136−setCachedRebuild ef = do
137− st <- envStateVar <$> ask
158+cacheRebuild :: Ide m => ExternsFile -> m ()
159+cacheRebuild ef = do
160+ st <- ideStateVar <$> ask
138161 liftIO . atomically . modifyTVar st $ \x ->
139− x { pscIdeStateCachedRebuild = Just (efModuleName ef, ef) }
162+ x { ideStage3 = (ideStage3 x) {
163+ s3CachedRebuild = Just (efModuleName ef, ef)}}
140164
141165-- | Retrieves the rebuild cache
142−getCachedRebuild :: PscIde m => m (Maybe (P.ModuleName, ExternsFile))
143−getCachedRebuild = pscIdeStateCachedRebuild <$> getPscIdeState
166+cachedRebuild :: Ide m => m (Maybe (P.ModuleName, ExternsFile))
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 @@
1212-- Type definitions for psc-ide
1313-----------------------------------------------------------------------------
1414
15−{-# LANGUAGE OverloadedStrings #-}
15+{-# LANGUAGE OverloadedStrings #-}
16+{-# LANGUAGE DeriveFoldable #-}
1617
1718module Language.PureScript.Ide.Types where
1819
19−import Prelude ()
20−import Prelude.Compat
20+import Protolude
2121
2222import Control.Concurrent.STM
23−import Control.Monad
24−import Control.Monad.Reader.Class
25−import Control.Monad.Trans
2623import Data.Aeson
2724import 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
3225import qualified Language.PureScript.Errors.JSON as P
33−import qualified Language.PureScript.Names as N
3426import qualified Language.PureScript as P
35−
36−import Text.Parsec
27+import Language.PureScript.Ide.Conversions
28+import System.FilePath
29+import Text.Parsec as Parsec
3730import Text.Parsec.Text
3831
39−type Ident = Text
40−type DeclIdent = Text
4132type ModuleIdent = Text
4233
43−data ExternDecl
44− -- | A function/value declaration
45− = ValueDeclaration Ident P.Type
46− | TypeDeclaration (P.ProperName 'P.TypeName) P.Kind
47− | TypeSynonymDeclaration (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)
61− P.Type -- The "type"
62− -- | An exported module
63− | TypeClassDeclaration (P.ProperName 'P.ClassName)
64− | ValueOperator (P.OpName 'P.ValueOpName) Ident P.Precedence P.Associativity
65− | TypeOperator (P.OpName 'P.TypeOpName) Ident P.Precedence P.Associativity
66− | Export ModuleIdent -- The exported Modules name
67− deriving (Show,Eq,Ord)
68−
69−type Module = (ModuleIdent, [ExternDecl])
34+data IdeDeclaration
35+ = IdeValue P.Ident P.Type
36+ | IdeType (P.ProperName 'P.TypeName) P.Kind
37+ | IdeTypeSynonym (P.ProperName 'P.TypeName) P.Type
38+ | IdeDataConstructor (P.ProperName 'P.ConstructorName) (P.ProperName 'P.TypeName) P.Type
39+ | IdeTypeClass (P.ProperName 'P.ClassName)
40+ | IdeValueOperator (P.OpName 'P.ValueOpName) Text P.Precedence P.Associativity
41+ | IdeTypeOperator (P.OpName 'P.TypeOpName) Text P.Precedence P.Associativity
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
51+ } deriving (Show, Eq, Ord)
52+
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)
7061
7162data Configuration =
7263 Configuration
7364 { confOutputPath :: FilePath
7465 , confDebug :: Bool
66+ , confGlobs :: [FilePath]
7567 }
7668
77−data PscIdeEnvironment =
78− PscIdeEnvironment
79− { envStateVar :: TVar PscIdeState
80− , envConfiguration :: Configuration
69+data IdeEnvironment =
70+ IdeEnvironment
71+ { ideStateVar :: TVar IdeState
72+ , ideConfiguration :: Configuration
8173 }
8274
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+ }
8482
85−data PscIdeState =
86− PscIdeState
87− { pscIdeStateModules :: M.Map Text [ExternDecl]
88− , pscIdeStateExternsFiles :: M.Map P.ModuleName ExternsFile
89− , pscIdeStateCachedRebuild :: Maybe (P.ModuleName, ExternsFile)
90− } deriving Show
83+emptyIdeState :: IdeState
84+emptyIdeState = IdeState emptyStage1 emptyStage2 emptyStage3
9185
92−emptyPscIdeState :: PscIdeState
93−emptyPscIdeState = PscIdeState M.empty M.empty Nothing
86+emptyStage1 :: Stage1
87+emptyStage1 = Stage1 M.empty M.empty
9488
95−data Match = Match ModuleIdent ExternDecl
96− deriving (Show, Eq)
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)
110+ deriving (Show, Eq, Functor)
97111
98112newtype 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)
100118 deriving (Show,Eq)
101119
120+instance ToJSON Info where
121+ toJSON (Info (m, d, t, sourceSpan)) =
122+ object ["module" .= m, "identifier" .= d, "type" .= t, "definedAt" .= sourceSpan]
123+
102124instance ToJSON Completion where
103− toJSON (Completion (m,d,t)) =
125+ toJSON (Completion (m, d, t)) =
104126 object ["module" .= m, "identifier" .= d, "type" .= t]
105127
106128data ModuleImport =
107129 ModuleImport
108130 { importModuleName :: ModuleIdent
109− , importType :: D.ImportDeclarationType
131+ , importType :: P.ImportDeclarationType
110132 , importQualifier :: Maybe Text
111133 } deriving(Show)
112134
@@ -116,29 +138,30 @@ instance Eq ModuleImport where
116138 && importQualifier mi1 == importQualifier mi2
117139
118140instance ToJSON ModuleImport where
119− toJSON (ModuleImport mn D.Implicit qualifier) =
141+ toJSON (ModuleImport mn P.Implicit qualifier) =
120142 object $ [ "module" .= mn
121143 , "importType" .= ("implicit" :: Text)
122144 ] ++ fmap (\x -> "qualifier" .= x) (maybeToList qualifier)
123− toJSON (ModuleImport mn (D.Explicit refs) _) =
145+ toJSON (ModuleImport mn (P.Explicit refs) _) =
124146 object [ "module" .= mn
125147 , "importType" .= ("explicit" :: Text)
126148 , "identifiers" .= (identifierFromDeclarationRef <$> refs)
127149 ]
128− toJSON (ModuleImport mn (D.Hiding refs) _) =
150+ toJSON (ModuleImport mn (P.Hiding refs) _) =
129151 object [ "module" .= mn
130152 , "importType" .= ("hiding" :: Text)
131153 , "identifiers" .= (identifierFromDeclarationRef <$> refs)
132154 ]
133155
134−identifierFromDeclarationRef :: D.DeclarationRef -> String
135−identifierFromDeclarationRef (D.TypeRef name _) = N.runProperName name
136−identifierFromDeclarationRef (D.ValueRef ident) = N.runIdent ident
137−identifierFromDeclarationRef (D.TypeClassRef name) = N.runProperName name
156+identifierFromDeclarationRef :: P.DeclarationRef -> Text
157+identifierFromDeclarationRef (P.TypeRef name _) = runProperNameT name
158+identifierFromDeclarationRef (P.ValueRef ident) = runIdentT ident
159+identifierFromDeclarationRef (P.TypeClassRef name) = runProperNameT name
138160identifierFromDeclarationRef _ = ""
139161
140162data Success =
141163 CompletionResult [Completion]
164+ | InfoResult [Info]
142165 | TextResult Text
143166 | MultilineTextResult [Text]
144167 | PursuitResult [PursuitResponse]
@@ -153,6 +176,7 @@ encodeSuccess res =
153176
154177instance ToJSON Success where
155178 toJSON (CompletionResult cs) = encodeSuccess cs
179+ toJSON (InfoResult i) = encodeSuccess i
156180 toJSON (TextResult t) = encodeSuccess t
157181 toJSON (MultilineTextResult ts) = encodeSuccess ts
158182 toJSON (PursuitResult resp) = encodeSuccess resp
@@ -182,14 +206,14 @@ data PursuitResponse =
182206 ModuleResponse ModuleIdent Text
183207 -- | A Pursuit Response for a declaration. Consist of the declarations type,
184208 -- module, name and package
185− | DeclarationResponse Text ModuleIdent DeclIdent Text
209+ | DeclarationResponse Text ModuleIdent Text Text
186210 deriving (Show,Eq)
187211
188212instance FromJSON PursuitResponse where
189213 parseJSON (Object o) = do
190214 package <- o .: "package"
191215 info <- o .: "info"
192− (type' :: String) <- info .: "type"
216+ (type' :: Text) <- info .: "type"
193217 case type' of
194218 "module" -> do
195219 name <- info .: "module"
@@ -204,26 +228,26 @@ instance FromJSON PursuitResponse where
204228
205229typeParse :: Text -> Either Text (Text, Text)
206230typeParse t = case parse parseType "" t of
207− Right (x,y) -> Right (pack x, pack y)
208− Left err -> Left (pack (show err))
231+ Right (x,y) -> Right (x, y)
232+ Left err -> Left (show err)
209233 where
210− parseType :: Parser (String, String)
234+ parseType :: Parser (Text, Text)
211235 parseType = do
212236 name <- identifier
213237 _ <- string "::"
214238 spaces
215239 type' <- many1 anyChar
216− pure (unpack name, type')
240+ pure (name, toS type')
217241
218242 identifier :: Parser Text
219243 identifier = do
220244 spaces
221245 ident <-
222246 -- necessary for being able to parse the following ((++), concat)
223− between (char '(') (char ')') (many1 (noneOf ", )")) <|>
247+ between (char '(') (char ')') (many1 (noneOf ", )")) Parsec.<|>
224248 many1 (noneOf ", )")
225249 spaces
226− pure (pack ident)
250+ pure (toS ident)
227251
228252instance ToJSON PursuitResponse where
229253 toJSON (ModuleResponse name package) =
src/Language/PureScript/Ide/Util.hs+58−46
@@ -9,75 +9,87 @@
99-- Stability : experimental
1010--
1111-- |
12−-- Generally useful functions and conversions
12+-- Generally useful functions
1313-----------------------------------------------------------------------------
1414
1515{-# LANGUAGE OverloadedStrings #-}
1616
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
1829
19−import Prelude.Compat
30+import Protolude
2031import Data.Aeson
21−import Data.Text (Text)
2232import qualified Data.Text as T
23−import Data.Text.Lazy (fromStrict, toStrict)
2433import Data.Text.Lazy.Encoding (decodeUtf8, encodeUtf8)
2534import qualified Language.PureScript as P
2635import Language.PureScript.Ide.Types
36+import Language.PureScript.Ide.Conversions
2737
28−runProperNameT :: P.ProperName a -> Text
29−runProperNameT = T.pack . P.runProperName
38+identifierFromIdeDeclaration :: IdeDeclaration -> Text
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
3047
31−runIdentT :: P.Ident -> Text
32−runIdentT = T.pack . P.runIdent
48+discardAnn :: IdeDeclarationAnn -> IdeDeclaration
49+discardAnn (IdeDeclarationAnn _ d) = d
3350
34−runOpNameT :: P.OpName a -> Text
35−runOpNameT = T.pack . P.runOpName
51+unwrapMatch :: Match a -> a
52+unwrapMatch (Match (_, ed)) = ed
3653
37−runModuleNameT :: P.ModuleName -> Text
38−runModuleNameT = T.pack . P.runModuleName
54+completionFromMatch :: Match IdeDeclaration -> Completion
55+completionFromMatch = Completion . completionFromMatch'
3956
40−prettyTypeT :: P.Type -> 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
59−completionFromMatch (Match m d) = case d of
60− ValueDeclaration name type' -> Just $ Completion (m, name, prettyTypeT type')
61− TypeDeclaration name kind -> Just $ Completion (m, runProperNameT name, T.pack $ P.prettyPrintKind kind)
62− TypeSynonymDeclaration name kind -> Just $ Completion (m, runProperNameT name, prettyTypeT kind)
63− DataConstructor name _ type' -> Just $ Completion (m, name, prettyTypeT type')
64− TypeClassDeclaration name -> Just $ Completion (m, runProperNameT name, "class")
65− ModuleDecl name _ -> Just $ Completion ("module", name, "module")
66− ValueOperator op ref precedence associativity -> Just $ Completion (m, runOpNameT op, showFixity precedence associativity ref op)
67− TypeOperator op ref precedence associativity -> Just $ Completion (m, runOpNameT op, showFixity precedence associativity ref op)
68− Dependency{} -> Nothing
69− Export{} -> Nothing
57+completionFromMatch' :: Match IdeDeclaration -> (Text, Text, Text)
58+completionFromMatch' (Match (m', d)) = case d of
59+ IdeValue name type' -> (m, runIdentT name, prettyTypeT type')
60+ IdeType name kind -> (m, runProperNameT name, toS (P.prettyPrintKind kind))
61+ IdeTypeSynonym name kind -> (m, runProperNameT name, prettyTypeT kind)
62+ IdeDataConstructor name _ type' -> (m, runProperNameT name, prettyTypeT type')
63+ IdeTypeClass name -> (m, runProperNameT name, "class")
64+ IdeValueOperator op ref precedence associativity ->
65+ (m, runOpNameT op, showFixity precedence associativity ref op)
66+ IdeTypeOperator op ref precedence associativity ->
67+ (m, runOpNameT op, showFixity precedence associativity ref op)
7068 where
69+ m = runModuleNameT m'
7170 showFixity p a r o =
7271 let asso = case a of
7372 P.Infix -> "infix"
7473 P.Infixl -> "infixl"
7574 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]
7776
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))
7882
7983encodeT :: (ToJSON a) => a -> Text
80−encodeT = toStrict . decodeUtf8 . encode
84+encodeT = toS . decodeUtf8 . encode
8185
8286decodeT :: (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 @@
1212-- File watcher for externs files
1313-----------------------------------------------------------------------------
1414
15−module Language.PureScript.Ide.Watcher where
15+module Language.PureScript.Ide.Watcher
16+ ( watcher
17+ ) where
18+
19+import Protolude
1620
17−import Control.Concurrent (threadDelay)
1821import Control.Concurrent.STM
19−import Control.Monad
20−import Control.Monad.Trans.Except
2122import Language.PureScript.Ide.Externs
2223import Language.PureScript.Ide.State
2324import Language.PureScript.Ide.Types
24−import Prelude
2525import System.FilePath
2626import System.FSNotify
2727
2828-- | Reloads an ExternsFile from Disc. If the Event indicates the ExternsFile
2929-- was deleted we don't do anything.
30−reloadFile :: TVar PscIdeState -> Event -> IO ()
30+reloadFile :: TVar IdeState -> Event -> IO ()
3131reloadFile _ Removed{} = pure ()
32−reloadFile stateVar ev = do
32+reloadFile ref ev = do
3333 let fp = eventPath ev
3434 ef' <- runExceptT (readExternFile fp)
3535 case ef' of
3636 Left _ -> pure ()
3737 Right ef -> do
38− atomically (insertModuleSTM stateVar ef)
38+ void $ atomically (insertExternsSTM ref ef *> populateStage3STM ref)
3939 putStrLn ("Reloaded File at: " ++ fp)
4040
4141-- | Installs filewatchers for the given directory and reloads ExternsFiles when
4242-- they change on disc
43−watcher :: TVar PscIdeState -> FilePath -> IO ()
43+watcher :: TVar IdeState -> FilePath -> IO ()
4444watcher stateVar fp =
4545 withManagerConf (defaultConfig { confDebounce = NoDebounce }) $ \mgr -> do
4646 _ <- watchTree mgr fp
src/Language/PureScript/Interactive.hs+47−41
@@ -1,8 +1,6 @@
11{-# LANGUAGE DoAndIfThenElse #-}
22{-# LANGUAGE FlexibleContexts #-}
3−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
43{-# LANGUAGE MultiParamTypeClasses #-}
5−{-# LANGUAGE RecordWildCards #-}
64{-# LANGUAGE TupleSections #-}
75{-# LANGUAGE DataKinds #-}
86
@@ -19,6 +17,7 @@ import Prelude ()
1917import Prelude.Compat
2018
2119import Data.List (intercalate, nub, sort, find, foldl')
20+import Data.Maybe (mapMaybe)
2221import qualified Data.Map as M
2322
2423import Control.Monad.IO.Class (MonadIO, liftIO)
@@ -39,12 +38,11 @@ import Language.PureScript.Interactive.Parser as Interactive
3938import Language.PureScript.Interactive.Printer as Interactive
4039import Language.PureScript.Interactive.Types as Interactive
4140
42−import System.Exit
43−import System.Process (readProcessWithExitCode)
41+import System.FilePath ((</>))
4442
4543-- | Pretty-print errors
4644printErrors :: MonadIO m => P.MultipleErrors -> m ()
47−printErrors = liftIO . putStrLn . P.prettyPrintMultipleErrors False
45+printErrors = liftIO . putStrLn . P.prettyPrintMultipleErrors P.defaultPPEOptions
4846
4947-- | This is different than the runMake in 'Language.PureScript.Make' in that it specifies the
5048-- options and ignores the warning messages.
@@ -92,25 +90,28 @@ make ms = do
9290-- | Performs a PSCi command
9391handleCommand
9492 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
95− => Command
93+ => (String -> m ())
9694 -> m ()
97−handleCommand ShowHelp = liftIO $ putStrLn helpMessage
98−handleCommand ResetState = handleResetState
99−handleCommand (Expression val) = handleExpression val
100−handleCommand (Import im) = handleImport im
101−handleCommand (Decls l) = handleDecls l
102−handleCommand (TypeOf val) = handleTypeOf val
103−handleCommand (KindOf typ) = handleKindOf typ
104−handleCommand (BrowseModule moduleName) = handleBrowse moduleName
105−handleCommand (ShowInfo QueryLoaded) = handleShowLoadedModules
106−handleCommand (ShowInfo QueryImport) = handleShowImportedModules
107−handleCommand QuitPSCi = P.internalError "`handleCommand QuitPSCi` was called. This is a bug."
95+ -> Command
96+ -> m ()
97+handleCommand _ _ ShowHelp = liftIO $ putStrLn helpMessage
98+handleCommand _ r ResetState = handleResetState r
99+handleCommand c _ (Expression val) = handleExpression c val
100+handleCommand _ _ (Import im) = handleImport im
101+handleCommand _ _ (Decls l) = handleDecls l
102+handleCommand _ _ (TypeOf val) = handleTypeOf val
103+handleCommand _ _ (KindOf typ) = handleKindOf typ
104+handleCommand _ _ (BrowseModule moduleName) = handleBrowse moduleName
105+handleCommand _ _ (ShowInfo QueryLoaded) = handleShowLoadedModules
106+handleCommand _ _ (ShowInfo QueryImport) = handleShowImportedModules
107+handleCommand _ _ QuitPSCi = P.internalError "`handleCommand QuitPSCi` was called. This is a bug."
108108
109109-- | Reset the application state
110110handleResetState
111111 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
112112 => m ()
113−handleResetState = do
113+ -> m ()
114+handleResetState reload = do
114115 modify $ updateImportedModules (const [])
115116 . updateLets (const [])
116117 files <- asks psciLoadedFiles
@@ -120,30 +121,25 @@ handleResetState = do
120121 return (map snd modules, externs)
121122 case e of
122123 Left errs -> printErrors errs
123− Right (modules, externs) -> modify (updateLoadedExterns (const (zip modules externs)))
124+ Right (modules, externs) -> do
125+ modify (updateLoadedExterns (const (zip modules externs)))
126+ reload
124127
125128-- | 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.
128129handleExpression
129130 :: (MonadReader PSCiConfig m, MonadState PSCiState m, MonadIO m)
130− => P.Expr
131+ => (String -> m ())
132+ -> P.Expr
131133 -> m ()
132−handleExpression val = do
134+handleExpression evaluate val = do
133135 st <- get
134136 let m = createTemporaryModule True st val
135− nodeArgs <- asks ((++ [indexFile]) . psciNodeFlags)
136137 e <- liftIO . runMake $ rebuild (map snd (psciLoadedExterns st)) m
137138 case e of
138139 Left errs -> printErrors errs
139140 Right _ -> do
140− liftIO $ writeFile indexFile "require('$PSCI')['$main']();"
141− process <- liftIO findNodeProcess
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"
141+ js <- liftIO $ readFile (modulesDir </> "$PSCI" </> "index.js")
142+ evaluate js
147143
148144-- |
149145-- Takes a list of declarations and updates the environment, then run a make. If the declaration fails,
@@ -188,17 +184,27 @@ handleShowImportedModules = do
188184 showDeclType P.Implicit = ""
189185 showDeclType (P.Explicit refs) = refsList refs
190186 showDeclType (P.Hiding refs) = " hiding " ++ refsList refs
191− refsList refs = " (" ++ commaList (map showRef refs) ++ ")"
187+ refsList refs = " (" ++ commaList (mapMaybe showRef refs) ++ ")"
192188
193− showRef :: P.DeclarationRef -> String
194− showRef (P.TypeRef pn dctors) = N.runProperName pn ++ "(" ++ maybe ".." (commaList . map N.runProperName) dctors ++ ")"
195− showRef (P.TypeOpRef op) = "type " ++ N.showOp op
196− showRef (P.ValueRef ident) = N.runIdent ident
197− showRef (P.ValueOpRef op) = N.showOp op
198− showRef (P.TypeClassRef pn) = "class " ++ N.runProperName pn
199− showRef (P.TypeInstanceRef ident) = N.runIdent ident
200− showRef (P.ModuleRef name) = "module " ++ N.runModuleName name
201− showRef (P.PositionedDeclarationRef _ _ ref) = showRef ref
189+ showRef :: P.DeclarationRef -> Maybe String
190+ showRef (P.TypeRef pn dctors) =
191+ Just $ N.runProperName pn ++ "(" ++ maybe ".." (commaList . map N.runProperName) dctors ++ ")"
192+ showRef (P.TypeOpRef op) =
193+ Just $ "type " ++ N.showOp op
194+ showRef (P.ValueRef ident) =
195+ Just $ N.runIdent ident
196+ showRef (P.ValueOpRef op) =
197+ Just $ N.showOp op
198+ showRef (P.TypeClassRef pn) =
199+ Just $ "class " ++ N.runProperName pn
200+ showRef (P.TypeInstanceRef ident) =
201+ Just $ N.runIdent ident
202+ showRef (P.ModuleRef name) =
203+ Just $ "module " ++ N.runModuleName name
204+ showRef (P.ReExportRef _ _) =
205+ Nothing
206+ showRef (P.PositionedDeclarationRef _ _ ref) =
207+ showRef ref
202208
203209 commaList :: [String] -> String
204210 commaList = intercalate ", "
src/Language/PureScript/Interactive/Module.hs+16−3
@@ -26,7 +26,7 @@ supportModuleIsDefined = any ((== supportModuleName) . P.getModuleName)
2626loadModule :: FilePath -> IO (Either String [P.Module])
2727loadModule filename = do
2828 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)]
3030
3131-- |
3232-- Load all modules.
@@ -45,14 +45,27 @@ createTemporaryModule :: Bool -> PSCiState -> P.Expr -> P.Module
4545createTemporaryModule exec PSCiState{psciImportedModules = imports, psciLetBindings = lets} val =
4646 let
4747 moduleName = P.ModuleName [P.ProperName "$PSCI"]
48+ effModuleName = P.moduleNameFromString "Control.Monad.Eff"
49+ effImport = (effModuleName, P.Implicit, Just (P.ModuleName [P.ProperName "$Eff"]))
4850 supportImport = (supportModuleName, P.Implicit, Just (P.ModuleName [P.ProperName "$Support"]))
4951 eval = P.Var (P.Qualified (Just (P.ModuleName [P.ProperName "$Support"])) (P.Ident "eval"))
5052 mainValue = P.App eval (P.Var (P.Qualified Nothing (P.Ident "it")))
5153 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))
5261 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>"
5464 in
55− P.Module (P.internalModuleSourceSpan "<internal>") [] moduleName ((importDecl `map` (supportImport : imports)) ++ lets ++ decls) Nothing
65+ P.Module internalSpan
66+ [] moduleName
67+ ((importDecl `map` (effImport : supportImport : imports)) ++ lets ++ decls)
68+ Nothing
5669
5770
5871-- |
src/Language/PureScript/Interactive/Types.hs−1
@@ -13,7 +13,6 @@ import qualified Language.PureScript as P
1313--
1414data PSCiConfig = PSCiConfig
1515 { psciLoadedFiles :: [FilePath]
16− , psciNodeFlags :: [String]
1716 , psciEnvironment :: P.Environment
1817 } deriving Show
1918
src/Language/PureScript/Kinds.hs+8−18
@@ -6,30 +6,20 @@ import Prelude.Compat
66
77import qualified Data.Aeson.TH as A
88
9−-- |
10−-- The data type of kinds
11−--
9+-- | The data type of kinds
1210data Kind
13− -- |
14− -- Unification variable of type Kind
15− --
11+ -- | Unification variable of type Kind
1612 = KUnknown Int
17− -- |
18− -- The kind of types
19− --
13+ -- | The kind of types
2014 | Star
21− -- |
22− -- The kind of effects
23− --
15+ -- | The kind of effects
2416 | Bang
25− -- |
26− -- Kinds for labelled, unordered rows without duplicates
27− --
17+ -- | Kinds for labelled, unordered rows without duplicates
2818 | Row Kind
29− -- |
30− -- Function kinds
31− --
19+ -- | Function kinds
3220 | FunKind Kind Kind
21+ -- | Type-level strings
22+ | Symbol
3323 deriving (Show, Read, Eq, Ord)
3424
3525$(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
140140 where
141141 fm = fromMaybe e
142142
143− compBS :: Eq a => b -> a -> Maybe b -> Maybe b -> (a, (b, b))
143+ compBS :: b -> a -> Maybe b -> Maybe b -> (a, (b, b))
144144 compBS e s b b' = (s, compB e b b')
145145
146146 (sortedNames, binders) = unzip $ genericMerge (compBS NullBinder) sbs sbs'
@@ -274,7 +274,7 @@ checkExhaustive env mn numArgs cas expr = makeResult . first nub $ foldl' step (
274274 --
275275 -- The binder information is provided so that it can be embedded in the constraint,
276276 -- and then included in the error message.
277− addPartialConstraint :: MonadSupply m => ([[Binder]], Bool) -> Expr -> m Expr
277+ addPartialConstraint :: ([[Binder]], Bool) -> Expr -> m Expr
278278 addPartialConstraint (bss, complete) e = do
279279 tyVar <- ("p" ++) . show <$> fresh
280280 var <- freshName
src/Language/PureScript/Linter/Imports.hs+1−2
@@ -169,8 +169,7 @@ lintImports (Module ss _ mn mdecls (Just mexports)) env usedImps = do
169169 go (q, name) = M.alter (Just . maybe [name] (name :)) q
170170
171171 extractByQual
172− :: Eq a
173− => ModuleName
172+ :: ModuleName
174173 -> M.Map (Qualified a) [ImportRecord a]
175174 -> (a -> Name)
176175 -> [(ModuleName, Qualified Name)]
src/Language/PureScript/Make.hs+2−2
@@ -132,7 +132,7 @@ data RebuildPolicy
132132 | RebuildAlways deriving (Show, Read, Eq, Ord)
133133
134134-- | 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)
136136 => MakeActions m
137137 -> [ExternsFile]
138138 -> Module
@@ -159,7 +159,7 @@ rebuildModule MakeActions{..} externs m@(Module _ _ moduleName _ _) = do
159159-- If timestamps have not changed, the externs file can be used to provide the module's types without
160160-- having to typecheck the module again.
161161--
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)
163163 => MakeActions m
164164 -> [Module]
165165 -> m [ExternsFile]
src/Language/PureScript/Parser/Common.hs+10−1
@@ -16,9 +16,18 @@ import Language.PureScript.Parser.State
1616
1717import qualified Text.Parsec as P
1818
19+-- |
20+-- Parse a general proper name.
21+--
1922properName :: TokenParser (ProperName a)
2023properName = ProperName <$> uname
2124
25+-- |
26+-- Parse a proper name for a type.
27+--
28+typeName :: TokenParser (ProperName 'TypeName)
29+typeName = ProperName <$> tyname
30+
2231-- |
2332-- Parse a module name
2433--
@@ -63,7 +72,7 @@ augment p q f = flip (maybe id $ flip f) <$> p <*> P.optionMaybe q
6372-- |
6473-- Run the first parser, then match the second zero or more times, applying the specified function for each match
6574--
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
6776fold first more combine = do
6877 a <- first
6978 bs <- P.many more
src/Language/PureScript/Parser/Declarations.hs+8−8
@@ -66,7 +66,7 @@ kindedIdent = (, Nothing) <$> identifier
6666parseDataDeclaration :: TokenParser Declaration
6767parseDataDeclaration = do
6868 dtype <- (reserved "data" *> return Data) <|> (reserved "newtype" *> return Newtype)
69− name <- indented *> properName
69+ name <- indented *> typeName
7070 tyArgs <- many (indented *> kindedIdent)
7171 ctors <- P.option [] $ do
7272 indented *> equals
@@ -80,7 +80,7 @@ parseTypeDeclaration =
8080
8181parseTypeSynonymDeclaration :: TokenParser Declaration
8282parseTypeSynonymDeclaration =
83− TypeSynonymDeclaration <$> (reserved "type" *> indented *> properName)
83+ TypeSynonymDeclaration <$> (reserved "type" *> indented *> typeName)
8484 <*> many (indented *> kindedIdent)
8585 <*> (indented *> equals *> noWildcards parsePolyType)
8686
@@ -108,7 +108,7 @@ parseValueDeclaration = do
108108
109109parseExternDeclaration :: TokenParser Declaration
110110parseExternDeclaration = reserved "foreign" *> indented *> reserved "import" *> indented *>
111− (ExternDataDeclaration <$> (reserved "data" *> indented *> properName)
111+ (ExternDataDeclaration <$> (reserved "data" *> indented *> typeName)
112112 <*> (indented *> doubleColon *> parseKind)
113113 <|> (do ident <- parseIdent
114114 ty <- indented *> doubleColon *> noWildcards parsePolyType
@@ -132,7 +132,7 @@ parseFixityDeclaration = do
132132 where
133133 typeFixity fixity =
134134 TypeFixity fixity
135− <$> (reserved "type" *> parseQualified properName)
135+ <$> (reserved "type" *> parseQualified typeName)
136136 <*> (reserved "as" *> parseOperator)
137137 valueFixity fixity =
138138 ValueFixity fixity
@@ -140,7 +140,7 @@ parseFixityDeclaration = do
140140 <*> (reserved "as" *> parseOperator)
141141
142142parseImportDeclaration :: TokenParser Declaration
143−parseImportDeclaration = do
143+parseImportDeclaration = withSourceSpan PositionedDeclaration $ do
144144 (mn, declType, asQ) <- parseImportDeclaration'
145145 return $ ImportDeclaration mn declType asQ
146146
@@ -169,7 +169,7 @@ parseDeclarationRef =
169169 <|> (TypeOpRef <$> (indented *> reserved "type" *> parens parseOperator))
170170 where
171171 parseTypeRef = do
172− name <- properName
172+ name <- typeName
173173 dctors <- P.optionMaybe $ parens (symbol' ".." *> pure Nothing <|> Just <$> commaSep properName)
174174 return $ TypeRef name (fromMaybe (Just []) dctors)
175175
@@ -183,7 +183,7 @@ parseTypeClassDeclaration = do
183183 return implies
184184 className <- indented *> properName
185185 idents <- P.many (indented *> kindedIdent)
186− members <- P.option [] . P.try $ do
186+ members <- P.option [] $ do
187187 indented *> reserved "where"
188188 indented *> mark (P.many (same *> positioned parseTypeDeclaration))
189189 return $ TypeClassDeclaration className idents implies members
@@ -209,7 +209,7 @@ parseInstanceDeclaration = do
209209parseTypeInstanceDeclaration :: TokenParser Declaration
210210parseTypeInstanceDeclaration = do
211211 instanceDecl <- parseInstanceDeclaration
212− members <- P.option [] . P.try $ do
212+ members <- P.option [] $ do
213213 indented *> reserved "where"
214214 mark (P.many (same *> positioned parseValueDeclaration))
215215 return $ instanceDecl (ExplicitInstance members)
src/Language/PureScript/Parser/Kinds.hs+4
@@ -18,10 +18,14 @@ parseStar = const Star <$> symbol' "*"
1818parseBang :: TokenParser Kind
1919parseBang = const Bang <$> symbol' "!"
2020
21+parseSymbol :: TokenParser Kind
22+parseSymbol = const Symbol <$> uname' "Symbol"
23+
2124parseTypeAtom :: TokenParser Kind
2225parseTypeAtom = indented *> P.choice
2326 [ parseStar
2427 , parseBang
28+ , parseSymbol
2529 , parens parseKind
2630 ]
2731-- |
src/Language/PureScript/Parser/Lexer.hs+20−12
@@ -41,6 +41,7 @@ module Language.PureScript.Parser.Lexer
4141 , commaSep1
4242 , lname
4343 , qualifier
44+ , tyname
4445 , uname
4546 , uname'
4647 , mname
@@ -213,8 +214,9 @@ parseToken = P.choice
213214 , P.try $ P.char '_' *> P.notFollowedBy identLetter *> pure Underscore
214215 , HoleLit <$> P.try (P.char '?' *> P.many1 identLetter)
215216 , LName <$> parseLName
216− , do uName <- parseUName
217− (guard (validModuleName uName) >> Qualifier uName <$ P.char '.') <|> pure (UName uName)
217+ , parseUName >>= \uName ->
218+ (guard (validModuleName uName) >> Qualifier uName <$ P.char '.')
219+ <|> pure (UName uName)
218220 , Symbol <$> parseSymbol
219221 , CharLiteral <$> parseCharLiteral
220222 , StringLiteral <$> parseStringLiteral
@@ -226,7 +228,7 @@ parseToken = P.choice
226228 parseLName = (:) <$> identStart <*> P.many identLetter
227229
228230 parseUName :: P.Parsec String u String
229− parseUName = (:) <$> P.upper <*> P.many uidentLetter
231+ parseUName = (:) <$> P.upper <*> P.many identLetter
230232
231233 parseSymbol :: P.Parsec String u String
232234 parseSymbol = P.many1 symbolChar
@@ -237,9 +239,6 @@ parseToken = P.choice
237239 identLetter :: P.Parsec String u Char
238240 identLetter = P.alphaNum <|> P.oneOf "_'"
239241
240− uidentLetter :: P.Parsec String u Char
241− uidentLetter = P.alphaNum <|> P.char '_'
242−
243242 symbolChar :: P.Parsec String u Char
244243 symbolChar = P.satisfy isSymbolChar
245244
@@ -430,6 +429,18 @@ reserved s = token go P.<?> show s
430429
431430uname :: TokenParser String
432431uname = 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"
433444 where
434445 go (UName s) = Just s
435446 go _ = Nothing
@@ -440,12 +451,6 @@ mname = token go P.<?> "module name"
440451 go (UName s) | validModuleName s = Just s
441452 go _ = Nothing
442453
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−
449454symbol :: TokenParser String
450455symbol = token go P.<?> "symbol"
451456 where
@@ -496,6 +501,9 @@ identifier = token go P.<?> "identifier"
496501validModuleName :: String -> Bool
497502validModuleName s = '_' `notElem` s
498503
504+validUName :: String -> Bool
505+validUName s = '\'' `notElem` s
506+
499507-- |
500508-- A list of purescript reserved identifiers
501509--
src/Language/PureScript/Parser/Types.hs+5−1
@@ -26,6 +26,9 @@ parseFunction = parens rarrow >> return tyFunction
2626parseObject :: TokenParser Type
2727parseObject = braces $ TypeApp tyRecord <$> parseRow
2828
29+parseTypeLevelString :: TokenParser Type
30+parseTypeLevelString = TypeLevelString <$> stringLiteral
31+
2932parseTypeWildcard :: TokenParser Type
3033parseTypeWildcard = do
3134 start <- P.getPosition
@@ -40,7 +43,7 @@ parseTypeVariable = do
4043 return $ TypeVar ident
4144
4245parseTypeConstructor :: TokenParser Type
43−parseTypeConstructor = TypeConstructor <$> parseQualified properName
46+parseTypeConstructor = TypeConstructor <$> parseQualified typeName
4447
4548parseForAll :: TokenParser Type
4649parseForAll = mkForAll <$> ((reserved "forall" <|> reserved "∀") *> P.many1 (indented *> identifier) <* indented <* dot)
@@ -53,6 +56,7 @@ parseTypeAtom :: TokenParser Type
5356parseTypeAtom = indented *> P.choice
5457 [ P.try parseConstrainedType
5558 , P.try parseFunction
59+ , parseTypeLevelString
5660 , parseObject
5761 , parseTypeWildcard
5862 , parseForAll
src/Language/PureScript/Pretty/Common.hs+5−1
@@ -114,7 +114,7 @@ blockIndent = 4
114114-- |
115115-- Pretty print with a new indentation level
116116--
117−withIndent :: (Emit gen) => StateT PrinterState Maybe gen -> StateT PrinterState Maybe gen
117+withIndent :: StateT PrinterState Maybe gen -> StateT PrinterState Maybe gen
118118withIndent action = do
119119 modify $ \st -> st { indent = indent st + blockIndent }
120120 result <- action
@@ -153,3 +153,7 @@ before b1 b2 | rows b1 > 1 = b1 // b2
153153
154154beforeWithSpace :: Box -> Box -> Box
155155beforeWithSpace 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
2121 where
2222 match Star = Just "*"
2323 match Bang = Just "!"
24+ match Symbol = Just "Symbol"
2425 match (KUnknown u) = Just $ 'u' : show u
2526 match _ = Nothing
2627
src/Language/PureScript/Pretty/Types.hs+1
@@ -32,6 +32,7 @@ typeLiterals = mkPattern match
3232 where
3333 match TypeWildcard{} = Just $ text "_"
3434 match (TypeVar var) = Just $ text var
35+ match (TypeLevelString s) = Just . text $ show s
3536 match (PrettyPrintObject row) = Just $ prettyPrintRowWith '{' '}' row
3637 match (TypeConstructor ctor) = Just $ text $ runProperName $ disqualify ctor
3738 match (TUnknown u) = Just $ text $ 't' : show u
src/Language/PureScript/Publish.hs+1
@@ -21,6 +21,7 @@ module Language.PureScript.Publish
2121 , getResolvedDependencies
2222 ) where
2323
24+import Prelude ()
2425import Prelude.Compat hiding (userError)
2526
2627import Control.Arrow ((***))
src/Language/PureScript/Publish/ErrorsWarnings.hs+1−1
@@ -225,7 +225,7 @@ displayUserError e = case e of
225225 CompileError err ->
226226 vcat
227227 [ para "Compile error:"
228− , indented (vcat (P.prettyPrintMultipleErrorsBox False err))
228+ , indented (vcat (P.prettyPrintMultipleErrorsBox P.defaultPPEOptions err))
229229 ]
230230 DirtyWorkingTree ->
231231 para (
src/Language/PureScript/Sugar/CaseDeclarations.hs+1−1
@@ -144,7 +144,7 @@ toTuple (ValueDeclaration _ _ bs result) = (bs, result)
144144toTuple (PositionedDeclaration _ _ d) = toTuple d
145145toTuple _ = internalError "Not a value declaration"
146146
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
148148makeCaseDeclaration ident alternatives = do
149149 let namedArgs = map findName . fst <$> alternatives
150150 argNames = foldl1 resolveNames namedArgs
src/Language/PureScript/Sugar/Names.hs+30−25
@@ -10,7 +10,7 @@ module Language.PureScript.Sugar.Names
1010
1111import Prelude.Compat
1212
13−import Control.Arrow (first, second)
13+import Control.Arrow (first)
1414import Control.Monad
1515import Control.Monad.Error.Class (MonadError(..))
1616import Control.Monad.State.Lazy
@@ -84,16 +84,19 @@ desugarImportsWithEnv externs modules = do
8484 toExportedType _ = Nothing
8585
8686 exportedTypeOps :: M.Map (OpName 'TypeOpName) ModuleName
87− exportedTypeOps = M.fromList $ (, efModuleName) <$> mapMaybe getTypeOpRef efExports
87+ exportedTypeOps = exportedRefs getTypeOpRef
8888
8989 exportedTypeClasses :: M.Map (ProperName 'ClassName) ModuleName
90− exportedTypeClasses = M.fromList $ (, efModuleName) <$> mapMaybe getTypeClassRef efExports
90+ exportedTypeClasses = exportedRefs getTypeClassRef
9191
9292 exportedValues :: M.Map Ident ModuleName
93− exportedValues = M.fromList $ (, efModuleName) <$> mapMaybe getValueRef efExports
93+ exportedValues = exportedRefs getValueRef
9494
9595 exportedValueOps :: M.Map (OpName 'ValueOpName) ModuleName
96− exportedValueOps = M.fromList $ (, efModuleName) <$> mapMaybe getValueOpRef efExports
96+ exportedValueOps = exportedRefs getValueOpRef
97+
98+ exportedRefs :: Ord a => (DeclarationRef -> Maybe a) -> M.Map a ModuleName
99+ exportedRefs f = M.fromList $ (, efModuleName) <$> mapMaybe f efExports
97100
98101 updateEnv :: ([Module], Env) -> Module -> m ([Module], Env)
99102 updateEnv (ms, env) m@(Module ss _ mn _ refs) =
@@ -110,9 +113,10 @@ desugarImportsWithEnv externs modules = do
110113 renameInModule' env m@(Module _ _ mn _ _) =
111114 warnAndRethrow (addHint (ErrorInModule mn)) $ do
112115 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)
114− lintImports m' env used
115− return m'
116+ (m', used) <- flip runStateT M.empty $ renameInModule imps m
117+ let m'' = elaborateExports exps m'
118+ lintImports m'' env used
119+ return m''
116120
117121-- |
118122-- Make all exports for a module explicit. This may still effect modules that
@@ -121,24 +125,25 @@ desugarImportsWithEnv externs modules = do
121125--
122126elaborateExports :: Exports -> Module -> Module
123127elaborateExports exps (Module ss coms mn decls refs) =
124− Module ss coms mn decls $
125− Just $ map (\(ctor, dctors) -> TypeRef ctor (Just dctors)) myTypes ++
126− map TypeOpRef (my exportedTypeOps) ++
127− map TypeClassRef (my exportedTypeClasses) ++
128− map ValueRef (my exportedValues) ++
129− map ValueOpRef (my exportedValueOps) ++
130− maybe [] (filter isModuleRef) refs
128+ Module ss coms mn decls $ Just
129+ $ elaboratedTypeRefs
130+ ++ go TypeOpRef exportedTypeOps
131+ ++ go TypeClassRef exportedTypeClasses
132+ ++ go ValueRef exportedValues
133+ ++ go ValueOpRef exportedValueOps
134+ ++ maybe [] (filter isModuleRef) refs
131135 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)
136136
137− myTypes :: [(ProperName 'TypeName, [ProperName 'ConstructorName])]
138− myTypes = second fst <$> filt ((== mn) . snd) exportedTypes
137+ elaboratedTypeRefs :: [DeclarationRef]
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
139142
140− filt :: (b -> Bool) -> (Exports -> M.Map a b) -> [(a, b)]
141− filt predicate f = M.toList $ predicate `M.filter` f exps
143+ go :: (a -> DeclarationRef) -> (Exports -> M.Map a ModuleName) -> [DeclarationRef]
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)
142147
143148-- |
144149-- 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) =
292297 -- qualified references are replaced with their canoncial qualified names
293298 -- (e.g. M.Map -> Data.Map.Map).
294299 update
295− :: (Ord a, Show a)
300+ :: (Ord a)
296301 => M.Map (Qualified a) [ImportRecord a]
297302 -> (a -> Name)
298303 -> Qualified a
@@ -329,5 +334,5 @@ renameInModule imports (Module ss coms mn decls exps) =
329334 _ -> throwUnknown
330335
331336 where
332− positioned err = maybe err (`rethrowWithPosition` err) pos
337+ positioned err = maybe err (`warnAndRethrowWithPosition` err) pos
333338 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
1010 , envModuleSourceSpan
1111 , envModuleImports
1212 , envModuleExports
13+ , ExportMode(..)
1314 , exportType
1415 , exportTypeOp
1516 , exportTypeClass
@@ -26,6 +27,7 @@ import Control.Monad.Error.Class (MonadError(..))
2627import Control.Monad.Writer.Class (MonadWriter(..))
2728
2829import Data.Function (on)
30+import Data.Foldable (find)
2931import Data.List (groupBy, sortBy, delete)
3032import Data.Maybe (fromJust, mapMaybe)
3133import qualified Data.Map as M
@@ -205,32 +207,51 @@ primEnv = M.singleton
205207 primModuleName
206208 (internalModuleSourceSpan "<Prim>", nullImports, primExports)
207209
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+
208219-- |
209220-- Safely adds a type and its data constructors to some exports, returning an
210221-- error if a conflict occurs.
211222--
212223exportType
213224 :: MonadError MultipleErrors m
214− => Exports
225+ => ExportMode
226+ -> Exports
215227 -> ProperName 'TypeName
216228 -> [ProperName 'ConstructorName]
217229 -> ModuleName
218230 -> m Exports
219−exportType exps name dctors mn = do
231+exportType exportMode exps name dctors mn = do
220232 let exTypes = exportedTypes exps
221233 let exClasses = exportedTypeClasses exps
222− forM_ (name `M.lookup` exTypes) $ \(_, mn') ->
223− when (mn /= mn') $ throwConflictError ConflictingTypeDecls name
224− when (coerceProperName name `M.member` exClasses) $
225− throwConflictError TypeConflictsWithClass name
226− forM_ dctors $ \dctor -> do
227− when (dctorExists (coerceProperName dctor) `any` exTypes) $
228− throwConflictError ConflictingCtorDecls dctor
229− when (coerceProperName dctor `M.member` exClasses) $
230− throwConflictError CtorConflictsWithClass dctor
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
246+ forM_ (name `M.lookup` exTypes) $ \(_, mn') ->
247+ when (mn /= mn') $
248+ throwExportConflict mn mn' (TyName name)
249+ forM_ dctors $ \dctor ->
250+ forM_ ((elem dctor . fst) `find` exTypes) $ \(_, mn') ->
251+ when (mn /= mn') $
252+ throwExportConflict mn mn' (DctorName dctor)
231253 return $ exps { exportedTypes = M.alter updateOrInsert name exTypes }
232254 where
233− dctorExists dctor (dctors', mn') = mn /= mn' && elem dctor dctors'
234255 updateOrInsert Nothing = Just (dctors, mn)
235256 updateOrInsert (Just (dctors', _)) = Just (dctors ++ dctors', mn)
236257
@@ -245,7 +266,7 @@ exportTypeOp
245266 -> ModuleName
246267 -> m Exports
247268exportTypeOp exps op mn = do
248− typeOps <- addExport DuplicateTypeOpExport op mn (exportedTypeOps exps)
269+ typeOps <- addExport TyOpName op mn (exportedTypeOps exps)
249270 return $ exps { exportedTypeOps = typeOps }
250271
251272-- |
@@ -253,17 +274,19 @@ exportTypeOp exps op mn = do
253274--
254275exportTypeClass
255276 :: MonadError MultipleErrors m
256− => Exports
277+ => ExportMode
278+ -> Exports
257279 -> ProperName 'ClassName
258280 -> ModuleName
259281 -> m Exports
260−exportTypeClass exps name mn = do
282+exportTypeClass exportMode exps name mn = do
261283 let exTypes = exportedTypes exps
262− when (coerceProperName name `M.member` exTypes) $
263− throwConflictError ClassConflictsWithType name
264− when ((elem (coerceProperName name) . fst) `any` exTypes) $
265− throwConflictError ClassConflictsWithCtor name
266− classes <- addExport DuplicateClassExport name mn (exportedTypeClasses exps)
284+ when (exportMode == Internal) $ do
285+ when (coerceProperName name `M.member` exTypes) $
286+ throwDeclConflict (TyClassName name) (TyName (coerceProperName name))
287+ when ((elem (coerceProperName name) . fst) `any` exTypes) $
288+ throwDeclConflict (TyClassName name) (DctorName (coerceProperName name))
289+ classes <- addExport TyClassName name mn (exportedTypeClasses exps)
267290 return $ exps { exportedTypeClasses = classes }
268291
269292-- |
@@ -276,7 +299,7 @@ exportValue
276299 -> ModuleName
277300 -> m Exports
278301exportValue exps name mn = do
279− values <- addExport DuplicateValueExport name mn (exportedValues exps)
302+ values <- addExport IdentName name mn (exportedValues exps)
280303 return $ exps { exportedValues = values }
281304
282305-- |
@@ -290,7 +313,7 @@ exportValueOp
290313 -> ModuleName
291314 -> m Exports
292315exportValueOp exps op mn = do
293− valueOps <- addExport DuplicateValueOpExport op mn (exportedValueOps exps)
316+ valueOps <- addExport ValOpName op mn (exportedValueOps exps)
294317 return $ exps { exportedValueOps = valueOps }
295318
296319-- |
@@ -299,28 +322,42 @@ exportValueOp exps op mn = do
299322--
300323addExport
301324 :: (MonadError MultipleErrors m, Ord a)
302− => (a -> SimpleErrorMessage)
325+ => (a -> Name)
303326 -> a
304327 -> ModuleName
305328 -> M.Map a ModuleName
306329 -> m (M.Map a ModuleName)
307−addExport what name mn exports =
330+addExport toName name mn exports =
308331 case M.lookup name exports of
309332 Just mn'
310333 | mn == mn' -> return exports
311− | otherwise -> throwConflictError what name
334+ | otherwise -> throwExportConflict mn mn' (toName name)
312335 Nothing ->
313336 return $ M.insert name mn exports
314337
315338-- |
316339-- Raises an error for when there is more than one definition for something.
317340--
318−throwConflictError
341+throwDeclConflict
319342 :: MonadError MultipleErrors m
320− => (a -> SimpleErrorMessage)
321− -> a
322− -> m b
323−throwConflictError conflict = throwError . errorMessage . conflict
343+ => Name
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
357+ -> m a
358+throwExportConflict new existing name =
359+ throwError . errorMessage $
360+ ExportConflict (Qualified (Just new) name) (Qualified (Just existing) name)
324361
325362-- |
326363-- Gets the exports for a module, or raise an error if the module doesn't exist.
@@ -338,7 +375,7 @@ getExports env mn =
338375--
339376checkImportConflicts
340377 :: forall m a
341− . (Show a, MonadError MultipleErrors m, MonadWriter MultipleErrors m, Ord a)
378+ . (MonadError MultipleErrors m, MonadWriter MultipleErrors m)
342379 => ModuleName
343380 -> (a -> Name)
344381 -> [ImportRecord a]
src/Language/PureScript/Sugar/Names/Exports.hs+20−13
@@ -31,20 +31,28 @@ findExportable (Module _ _ mn ds _) =
3131 where
3232 updateExports :: Exports -> Declaration -> m Exports
3333 updateExports exps (TypeClassDeclaration tcn _ _ ds') = do
34− exps' <- exportTypeClass exps tcn mn
34+ exps' <- exportTypeClass Internal exps tcn mn
3535 foldM go exps' ds'
3636 where
3737 go exps'' (TypeDeclaration name _) = exportValue exps'' name mn
3838 go exps'' (PositionedDeclaration pos _ d) = rethrowWithPosition pos $ go exps'' d
3939 go _ _ = internalError "Invalid declaration in TypeClassDeclaration"
40− updateExports exps (DataDeclaration _ tn _ dcs) = exportType exps tn (map fst dcs) mn
41− updateExports exps (TypeSynonymDeclaration tn _ _) = exportType exps tn [] mn
42− updateExports exps (ExternDataDeclaration tn _) = exportType exps tn [] mn
43− updateExports exps (ValueDeclaration name _ _ _) = exportValue exps name mn
44− updateExports exps (ValueFixityDeclaration _ _ op) = exportValueOp exps op mn
45− updateExports exps (TypeFixityDeclaration _ _ op) = exportTypeOp exps op mn
46− updateExports exps (ExternDeclaration name _) = exportValue exps name mn
47− updateExports exps (PositionedDeclaration pos _ d) = rethrowWithPosition pos $ updateExports exps d
40+ updateExports exps (DataDeclaration _ tn _ dcs) =
41+ exportType Internal exps tn (map fst dcs) mn
42+ updateExports exps (TypeSynonymDeclaration tn _ _) =
43+ exportType Internal exps tn [] mn
44+ updateExports exps (ExternDataDeclaration tn _) =
45+ exportType Internal exps tn [] mn
46+ updateExports exps (ValueDeclaration name _ _ _) =
47+ exportValue exps name mn
48+ updateExports exps (ValueFixityDeclaration _ _ op) =
49+ exportValueOp exps op mn
50+ updateExports exps (TypeFixityDeclaration _ _ op) =
51+ exportTypeOp exps op mn
52+ updateExports exps (ExternDeclaration name _) =
53+ exportValue exps name mn
54+ updateExports exps (PositionedDeclaration pos _ d) =
55+ rethrowWithPosition pos $ updateExports exps d
4856 updateExports exps _ = return exps
4957
5058-- |
@@ -99,9 +107,9 @@ resolveExports env ss mn imps exps refs =
99107 reClasses <- extract isPseudo name TyClassName (importedTypeClasses imps)
100108 reValues <- extract isPseudo name IdentName (importedValues imps)
101109 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)
103111 >>= flip (foldM (uncurry . exportTypeOp)) (map resolveTypeOp reTypeOps)
104− >>= flip (foldM (uncurry . exportTypeClass)) (map resolveClass reClasses)
112+ >>= flip (foldM (uncurry . exportTypeClass ReExport)) (map resolveClass reClasses)
105113 >>= flip (foldM (uncurry . exportValue)) (map resolveValue reValues)
106114 >>= flip (foldM (uncurry . exportValueOp)) (map resolveValueOp reValueOps)
107115 elaborateModuleExports result _ = return result
@@ -109,8 +117,7 @@ resolveExports env ss mn imps exps refs =
109117 -- Extracts a list of values for a module based on a lookup table. If the
110118 -- boolean is true the values are filtered by the qualification
111119 extract
112− :: (Show a, Ord a)
113− => Bool
120+ :: Bool
114121 -> ModuleName
115122 -> (a -> Name)
116123 -> 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
207207 return $ imp { importedTypeClasses = typeClasses' }
208208 importRef _ _ TypeInstanceRef{} = internalError "TypeInstanceRef in importRef"
209209 importRef _ _ ModuleRef{} = internalError "ModuleRef in importRef"
210+ importRef _ _ ReExportRef{} = internalError "ReExportRef in importRef"
210211
211212 -- Find all exported data constructors for a given type
212213 allExportedDataConstructors
@@ -218,7 +219,7 @@ resolveImport importModule exps imps impQual = resolveByType
218219
219220 -- Add something to an import resolution list
220221 updateImports
221− :: (Ord a)
222+ :: Ord a
222223 => M.Map (Qualified a) [ImportRecord a]
223224 -> M.Map a b
224225 -> (b -> ModuleName)
src/Language/PureScript/TypeChecker.hs+9−8
@@ -53,7 +53,7 @@ addDataType moduleName dtype name args dctors ctorKind = do
5353 addDataConstructor moduleName dtype name (map fst args) dctor tys
5454
5555addDataConstructor
56− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
56+ :: (MonadState CheckState m, MonadError MultipleErrors m)
5757 => ModuleName
5858 -> DataDeclType
5959 -> ProperName 'TypeName
@@ -71,7 +71,7 @@ addDataConstructor moduleName dtype name args dctor tys = do
7171 putEnv $ env { dataConstructors = M.insert (Qualified (Just moduleName) dctor) (dtype, name, polyType, fields) (dataConstructors env) }
7272
7373addTypeSynonym
74− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
74+ :: (MonadState CheckState m, MonadError MultipleErrors m)
7575 => ModuleName
7676 -> ProperName 'TypeName
7777 -> [(String, Maybe Kind)]
@@ -85,7 +85,7 @@ addTypeSynonym moduleName name args ty kind = do
8585 , typeSynonyms = M.insert (Qualified (Just moduleName) name) (args, ty) (typeSynonyms env) }
8686
8787valueIsNotDefined
88− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
88+ :: (MonadState CheckState m, MonadError MultipleErrors m)
8989 => ModuleName
9090 -> Ident
9191 -> m ()
@@ -96,7 +96,7 @@ valueIsNotDefined moduleName name = do
9696 Nothing -> return ()
9797
9898addValue
99− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
99+ :: (MonadState CheckState m)
100100 => ModuleName
101101 -> Ident
102102 -> Type
@@ -107,7 +107,7 @@ addValue moduleName name ty nameKind = do
107107 putEnv (env { names = M.insert (moduleName, name) (ty, nameKind, Defined) (names env) })
108108
109109addTypeClass
110− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
110+ :: (MonadState CheckState m)
111111 => ModuleName
112112 -> ProperName 'ClassName
113113 -> [(String, Maybe Kind)]
@@ -123,7 +123,7 @@ addTypeClass moduleName pn args implies ds =
123123 toPair _ = internalError "Invalid declaration in TypeClassDeclaration"
124124
125125addTypeClassDictionaries
126− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
126+ :: (MonadState CheckState m)
127127 => Maybe ModuleName
128128 -> M.Map (Qualified (ProperName 'ClassName)) (M.Map (Qualified Ident) TypeClassDictionaryInScope)
129129 -> m ()
@@ -132,7 +132,7 @@ addTypeClassDictionaries mn entries =
132132 where insertState st = M.insertWith (M.unionWith M.union) mn entries (typeClassDictionaries . checkEnv $ st)
133133
134134checkDuplicateTypeArguments
135− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
135+ :: (MonadState CheckState m, MonadError MultipleErrors m)
136136 => [String]
137137 -> m ()
138138checkDuplicateTypeArguments args = for_ firstDup $ \dup ->
@@ -147,6 +147,7 @@ checkTypeClassInstance
147147 -> Type
148148 -> m ()
149149checkTypeClassInstance _ (TypeVar _) = return ()
150+checkTypeClassInstance _ (TypeLevelString _) = return ()
150151checkTypeClassInstance _ (TypeConstructor ctor) = do
151152 env <- getEnv
152153 when (ctor `M.member` typeSynonyms env) . throwError . errorMessage $ TypeSynonymInstance
@@ -158,7 +159,7 @@ checkTypeClassInstance _ ty = throwError . errorMessage $ InvalidInstanceHead ty
158159-- Check that type synonyms are fully-applied in a type
159160--
160161checkTypeSynonyms
161− :: (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
162+ :: (MonadState CheckState m, MonadError MultipleErrors m)
162163 => Type
163164 -> m ()
164165checkTypeSynonyms = void . replaceAllTypeSynonyms
src/Language/PureScript/TypeChecker/Entailment.hs+1
@@ -184,6 +184,7 @@ typeHeadsAreEqual _ (TUnknown u1) (TUnknown u2) | u1 == u2 = Just
184184typeHeadsAreEqual _ (Skolem _ s1 _ _) (Skolem _ s2 _ _) | s1 == s2 = Just []
185185typeHeadsAreEqual _ t (TypeVar v) = Just [(v, t)]
186186typeHeadsAreEqual _ (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = Just []
187+typeHeadsAreEqual _ (TypeLevelString s1) (TypeLevelString s2) | s1 == s2 = Just []
187188typeHeadsAreEqual m (TypeApp h1 t1) (TypeApp h2 t2) = (++) <$> typeHeadsAreEqual m h1 h2
188189 <*> typeHeadsAreEqual m t1 t2
189190typeHeadsAreEqual _ REmpty REmpty = Just []
src/Language/PureScript/TypeChecker/Kinds.hs+2
@@ -87,6 +87,7 @@ unifyKinds k1 k2 = do
8787 go k (KUnknown u) = solveKind u k
8888 go Star Star = return ()
8989 go Bang Bang = return ()
90+ go Symbol Symbol = return ()
9091 go (Row k1') (Row k2') = go k1' k2'
9192 go (FunKind k1' k2') (FunKind k3 k4) = do
9293 go k1' k3
@@ -230,6 +231,7 @@ infer' other = (, []) <$> go other
230231 unifyKinds k k'
231232 return k'
232233 go TypeWildcard{} = freshKind
234+ go (TypeLevelString _) = return Symbol
233235 go (TypeVar v) = do
234236 Just moduleName <- checkCurrentModule <$> get
235237 lookupTypeVariable moduleName (Qualified Nothing (ProperName v))
src/Language/PureScript/TypeChecker/Rows.hs+1−3
@@ -9,17 +9,15 @@ import Prelude.Compat
99
1010import Control.Monad
1111import Control.Monad.Error.Class (MonadError(..))
12−import Control.Monad.State.Class (MonadState(..))
1312
1413import Data.List
1514
1615import Language.PureScript.AST
1716import Language.PureScript.Errors
18−import Language.PureScript.TypeChecker.Monad
1917import Language.PureScript.Types
2018
2119-- | 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 ()
2321checkDuplicateLabels =
2422 let (_, f, _) = everywhereOnValuesM def go def
2523 in void . f
src/Language/PureScript/TypeChecker/Skolems.hs+1−1
@@ -89,7 +89,7 @@ skolemizeTypesInValue ident sko scope ss =
8989-- |
9090-- Ensure skolem variables do not escape their scope
9191--
92−skolemEscapeCheck :: (MonadError MultipleErrors m, MonadState CheckState m) => Expr -> m ()
92+skolemEscapeCheck :: (MonadError MultipleErrors m) => Expr -> m ()
9393skolemEscapeCheck (TypedValue False _ _) = return ()
9494skolemEscapeCheck root@TypedValue{} =
9595 -- 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)
133133type UntypedData = [(Ident, Type)]
134134
135135typeDictionaryForBindingGroup ::
136− (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
136+ (MonadState CheckState m) =>
137137 ModuleName ->
138138 [(Ident, Expr)] ->
139139 m ([(Ident, Expr)], [(Ident, (Expr, Type, Bool))], TypeData, UntypedData)
@@ -206,7 +206,7 @@ overTypes f = let (_, f', _) = everywhereOnValues id g id in f'
206206
207207-- | Check the kind of a type, failing if it is not of kind *.
208208checkTypeKind ::
209− (MonadState CheckState m, MonadError MultipleErrors m) =>
209+ (MonadError MultipleErrors m) =>
210210 Type ->
211211 Kind ->
212212 m ()
src/Language/PureScript/TypeChecker/Unify.hs+8−7
@@ -153,13 +153,14 @@ unifyRows r1 r2 =
153153-- Check that two types unify
154154--
155155unifiesWith :: Type -> Type -> Bool
156−unifiesWith (TUnknown u1) (TUnknown u2) | u1 == u2 = True
157−unifiesWith (Skolem _ s1 _ _) (Skolem _ s2 _ _) | s1 == s2 = True
158−unifiesWith (TypeVar v1) (TypeVar v2) | v1 == v2 = True
159−unifiesWith (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = True
160−unifiesWith (TypeApp h1 t1) (TypeApp h2 t2) = h1 `unifiesWith` h2 && t1 `unifiesWith` t2
161−unifiesWith REmpty REmpty = True
162−unifiesWith r1@RCons{} r2@RCons{} =
156+unifiesWith (TUnknown u1) (TUnknown u2) = u1 == u2
157+unifiesWith (Skolem _ s1 _ _) (Skolem _ s2 _ _) = s1 == s2
158+unifiesWith (TypeVar v1) (TypeVar v2) = v1 == v2
159+unifiesWith (TypeLevelString s1) (TypeLevelString s2) = s1 == s2
160+unifiesWith (TypeConstructor c1) (TypeConstructor c2) = c1 == c2
161+unifiesWith (TypeApp h1 t1) (TypeApp h2 t2) = h1 `unifiesWith` h2 && t1 `unifiesWith` t2
162+unifiesWith REmpty REmpty = True
163+unifiesWith r1@RCons{} r2@RCons{} =
163164 let (s1, r1') = rowToList r1
164165 (s2, r2') = rowToList r2
165166
src/Language/PureScript/Types.hs+19−51
@@ -29,79 +29,47 @@ newtype SkolemScope = SkolemScope { runSkolemScope :: Int }
2929-- The type of types
3030--
3131data Type
32− -- |
33− -- A unification variable of type Type
34− --
32+ -- | A unification variable of type Type
3533 = TUnknown Int
36− -- |
37− -- A named type variable
38− --
34+ -- | A named type variable
3935 | TypeVar String
40− -- |
41− -- A type wildcard, as would appear in a partial type synonym
42− --
36+ -- | A type-level string
37+ | TypeLevelString String
38+ -- | A type wildcard, as would appear in a partial type synonym
4339 | TypeWildcard SourceSpan
44− -- |
45− -- A type constructor
46− --
40+ -- | A type constructor
4741 | 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
5043 -- "operators" phase of desugaring.
51− --
5244 | TypeOp (Qualified (OpName 'TypeOpName))
53− -- |
54− -- A type application
55− --
45+ -- | A type application
5646 | TypeApp Type Type
57− -- |
58− -- Forall quantifier
59− --
47+ -- | Forall quantifier
6048 | ForAll String Type (Maybe SkolemScope)
61− -- |
62− -- A type with a set of type class constraints
63− --
49+ -- | A type with a set of type class constraints
6450 | ConstrainedType [Constraint] Type
65− -- |
66− -- A skolem constant
67− --
51+ -- | A skolem constant
6852 | Skolem String Int SkolemScope (Maybe SourceSpan)
69− -- |
70− -- An empty row
71− --
53+ -- | An empty row
7254 | REmpty
73− -- |
74− -- A non-empty row
75− --
55+ -- | A non-empty row
7656 | RCons String Type Type
77− -- |
78− -- A type with a kind annotation
79− --
57+ -- | A type with a kind annotation
8058 | KindedType Type Kind
81− -- |
82− -- A placeholder used in pretty printing
83− --
59+ -- | A placeholder used in pretty printing
8460 | PrettyPrintFunction Type Type
85− -- |
86− -- A placeholder used in pretty printing
87− --
61+ -- | A placeholder used in pretty printing
8862 | PrettyPrintObject Type
89− -- |
90− -- A placeholder used in pretty printing
91− --
63+ -- | A placeholder used in pretty printing
9264 | PrettyPrintForAll [String] Type
93− -- |
94− -- Binary operator application. During the rebracketing phase of desugaring,
65+ -- | Binary operator application. During the rebracketing phase of desugaring,
9566 -- this data constructor will be removed.
96− --
9767 | 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
10069 -- data constructor will be removed.
10170 --
10271 -- Note: although it seems this constructor is not used, it _is_ useful,
10372 -- since it prevents certain traversals from matching.
104− --
10573 | ParensInType Type
10674 deriving (Show, Read, Eq, Ord)
10775
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
22packages:
33- '.'
4−extra-deps:
5−- bower-json-0.8.0
6−- language-javascript-0.6.0.4
7−- parsec-3.1.11
4+extra-deps: []
85flags: {}
tests/Language/PureScript/Ide/FilterSpec.hs+21−32
@@ -1,32 +1,31 @@
11{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
23module Language.PureScript.Ide.FilterSpec where
34
4−import Data.Text (Text)
5+import Protolude
56import Language.PureScript.Ide.Filter
67import Language.PureScript.Ide.Types
78import qualified Language.PureScript as P
89import Test.Hspec
910
10−value :: Text -> ExternDecl
11−value s = ValueDeclaration s $ P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
11+value :: Text -> IdeDeclarationAnn
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"])
1217
1318modules :: [Module]
14−modules =
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− ]
19+modules = [moduleA, moduleB]
2120
2221runEq :: Text -> [Module]
23−runEq s = runFilter (equalityFilter s) modules
22+runEq s = applyFilters [equalityFilter s] modules
23+
2424runPrefix :: Text -> [Module]
25−runPrefix s = runFilter (prefixFilter s) modules
26−runModule :: [ModuleIdent] -> [Module]
27−runModule ms = runFilter (moduleFilter ms) modules
28−runDependency :: [ModuleIdent] -> [Module]
29−runDependency ms = runFilter (dependencyFilter ms) modules
25+runPrefix s = applyFilters [prefixFilter s] modules
26+
27+runModule :: [P.ModuleName] -> [Module]
28+runModule ms = applyFilters [moduleFilter ms] modules
3029
3130spec :: Spec
3231spec = do
@@ -34,30 +33,20 @@ spec = do
3433 it "removes empty modules" $
3534 runEq "test" `shouldBe` []
3635 it "keeps function declarations that are equal" $
37− runEq "function1" `shouldBe` [head modules]
38− -- TODO: It would be more sensible to match Constructors
36+ runEq "function1" `shouldBe` [moduleA]
3937 it "keeps data declarations that are equal" $
40− runEq "data1" `shouldBe` [modules !! 1]
38+ runEq "data1" `shouldBe` [moduleB]
4139 describe "prefixFilter" $ do
4240 it "keeps everything on empty string" $
4341 runPrefix "" `shouldBe` modules
4442 it "keeps functionname prefix matches" $
45− runPrefix "fun" `shouldBe` [head modules]
43+ runPrefix "fun" `shouldBe` [moduleA]
4644 it "keeps data decls prefix matches" $
47− runPrefix "dat" `shouldBe` [modules !! 1]
48− it "keeps module decl prefix matches" $
49− runPrefix "Mod" `shouldBe` [modules !! 2]
45+ runPrefix "dat" `shouldBe` [moduleB]
5046 describe "moduleFilter" $ do
5147 it "removes everything on empty input" $
5248 runModule [] `shouldBe` []
5349 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]
5551 it "ignores modules that are not in scope" $
56− runModule ["Module.A", "Module.C", "Unknown"] `shouldBe` [head modules, modules !! 2]
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]
52+ runModule (P.moduleNameFromString <$> ["Module.A", "Unknown"]) `shouldBe` [moduleA]
tests/Language/PureScript/Ide/Imports/IntegrationSpec.hs+14−25
@@ -1,8 +1,10 @@
11{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
23module Language.PureScript.Ide.Imports.IntegrationSpec where
34
4−import Control.Monad (void)
5−import Data.Text (Text)
5+
6+import Protolude
7+
68import qualified Data.Text as T
79import qualified Data.Text.IO as TIO
810import qualified Language.PureScript.Ide.Integration as Integration
@@ -12,9 +14,7 @@ import System.Directory
1214import System.FilePath
1315
1416setup :: IO ()
15−setup = do
16− Integration.reset
17− mapM_ Integration.loadModuleWithDeps ["ImportsSpec", "ImportsSpec1"]
17+setup = void (Integration.reset *> Integration.loadAll)
1818
1919withSupportFiles :: (FilePath -> FilePath -> IO a) -> IO ()
2020withSupportFiles test = do
@@ -35,52 +35,41 @@ spec = beforeAll_ setup . describe "Adding imports" $ do
3535 let
3636 sourceFileSkeleton :: [Text] -> [Text]
3737 sourceFileSkeleton importSection =
38− [ "module ImportsSpec where" , ""] ++ importSection ++ [ "" , "myId = id"]
38+ [ "module ImportsSpec where" , ""] ++ importSection ++ [ "" , "myId x = x"]
3939 it "adds an implicit import" $ do
4040 withSupportFiles (Integration.addImplicitImport "ImportsSpec1")
4141 outputFileShouldBe (sourceFileSkeleton
4242 [ "import ImportsSpec1"
43− , "import Main (id)"
4443 ])
4544 it "adds an explicit unqualified import" $ do
4645 withSupportFiles (Integration.addImport "exportedFunction")
4746 outputFileShouldBe (sourceFileSkeleton
4847 [ "import ImportsSpec1 (exportedFunction)"
49− , "import Main (id)"
5048 ])
5149 it "adds an explicit unqualified import (type)" $ do
5250 withSupportFiles (Integration.addImport "MyType")
53− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (MyType)"
54− , "import Main (id)"
55− ])
51+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyType)"])
5652 it "adds an explicit unqualified import (parameterized type)" $ do
5753 withSupportFiles (Integration.addImport "MyParamType")
58− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (MyParamType)"
59− , "import Main (id)"
60− ])
54+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyParamType)"])
6155 it "adds an explicit unqualified import (typeclass)" $ do
6256 withSupportFiles (Integration.addImport "ATypeClass")
63− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (class ATypeClass)"
64− , "import Main (id)"])
57+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (class ATypeClass)"])
6558 it "adds an explicit unqualified import (dataconstructor)" $ do
6659 withSupportFiles (Integration.addImport "MyJust")
67− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (MyMaybe(MyJust))"
68− , "import Main (id)"])
60+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyMaybe(MyJust))"])
6961 it "adds an explicit unqualified import (newtype)" $ do
7062 withSupportFiles (Integration.addImport "MyNewtype")
71− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (MyNewtype(MyNewtype))"
72− , "import Main (id)"])
63+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (MyNewtype(MyNewtype))"])
7364 it "adds an explicit unqualified import (typeclass member function)" $ do
7465 withSupportFiles (Integration.addImport "typeClassFun")
75− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (typeClassFun)"
76− , "import Main (id)"])
66+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (typeClassFun)"])
7767 it "doesn't add a newtypes constructor if only the type is exported" $ do
7868 withSupportFiles (Integration.addImport "OnlyTypeExported")
79− outputFileShouldBe (sourceFileSkeleton [ "import ImportsSpec1 (OnlyTypeExported)"
80− , "import Main (id)"])
69+ outputFileShouldBe (sourceFileSkeleton ["import ImportsSpec1 (OnlyTypeExported)"])
8170 it "doesn't add an import if the identifier is defined in the module itself" $ do
8271 withSupportFiles (Integration.addImport "myId")
83− outputFileShouldBe (sourceFileSkeleton [ "import Main (id)"])
72+ outputFileShouldBe (sourceFileSkeleton [])
8473 it "responds with an error if it's undecidable whether we want a type or constructor" $
8574 withSupportFiles (\sourceFp outFp -> do
8675 r <- Integration.addImport "SpecialCase" sourceFp outFp
tests/Language/PureScript/Ide/ImportsSpec.hs+9−9
@@ -1,8 +1,10 @@
11{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
23module Language.PureScript.Ide.ImportsSpec where
34
4−import Data.Maybe (fromJust)
5−import Data.Text (Text)
5+import Protolude
6+import Unsafe (fromJust)
7+
68import qualified Language.PureScript as P
79import Language.PureScript.Ide.Imports
810import Language.PureScript.Ide.Types
@@ -17,11 +19,9 @@ simpleFile =
1719 ]
1820
1921splitSimpleFile :: (P.ModuleName, [Text], [Import], [Text])
20−splitSimpleFile = fromRight $ sliceImportSection simpleFile
22+splitSimpleFile = fromRight (sliceImportSection simpleFile)
2123 where
22− fromRight (Right r) = r
23− fromRight (Left _) = error "fromRight"
24−
24+ fromRight = fromJust . rightToMaybe
2525withImports :: [Text] -> [Text]
2626withImports is =
2727 take 2 simpleFile ++ is ++ drop 2 simpleFile
@@ -68,11 +68,11 @@ spec = do
6868 describe "import commands" $ do
6969 let simpleFileImports = let (_, _, i, _) = splitSimpleFile in i
7070 addValueImport i mn is =
71− prettyPrintImportSection (addExplicitImport' (ValueDeclaration i wildcard) mn is)
71+ prettyPrintImportSection (addExplicitImport' (IdeValue (P.Ident i) wildcard) mn is)
7272 addOpImport op mn is =
73− prettyPrintImportSection (addExplicitImport' (ValueOperator op "" 2 P.Infix) mn is)
73+ prettyPrintImportSection (addExplicitImport' (IdeValueOperator op "" 2 P.Infix) mn is)
7474 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)
7676 it "adds an implicit unqualified import" $
7777 shouldBe
7878 (addImplicitImport' simpleFileImports (P.moduleNameFromString "Data.Map"))
tests/Language/PureScript/Ide/Integration.hs+73−77
@@ -14,6 +14,7 @@
1414
1515{-# LANGUAGE OverloadedStrings #-}
1616{-# LANGUAGE ScopedTypeVariables #-}
17+{-# LANGUAGE NoImplicitPrelude #-}
1718module Language.PureScript.Ide.Integration
1819 (
1920 -- managing the server process
@@ -29,33 +30,33 @@ module Language.PureScript.Ide.Integration
2930 -- sending commands
3031 , addImport
3132 , addImplicitImport
33+ , loadAll
3234 , loadModule
33− , loadModuleWithDeps
35+ , loadModules
3436 , getCwd
3537 , getFlexCompletions
3638 , getFlexCompletionsInModule
3739 , getType
40+ , getInfo
3841 , rebuildModule
3942 , reset
4043 -- checking results
4144 , resultIsSuccess
4245 , parseCompletions
46+ , parseInfo
4347 , parseTextResult
4448 ) where
4549
46−import Control.Concurrent (threadDelay)
47−import Control.Exception
48−import Control.Monad (join, when)
50+import Protolude
51+import Unsafe (fromJust)
52+
4953import Data.Aeson
5054import Data.Aeson.Types
51−import qualified Data.ByteString.Lazy.UTF8 as BSL
52−import Data.Either (isRight)
53−import Data.Maybe (fromJust, isNothing, fromMaybe)
5455import qualified Data.Text as T
5556import qualified Data.Vector as V
5657import Language.PureScript.Ide.Util
58+import qualified Language.PureScript as P
5759import System.Directory
58−import System.Exit
5960import System.FilePath
6061import System.IO.Error (mkIOError, userErrorType)
6162import System.Process
@@ -70,8 +71,8 @@ startServer = do
7071 pdir <- projectDirectory
7172 -- Turn off filewatching since it creates race condition in a testing environment
7273 (_, _, _, procHandle) <- createProcess $
73− (shell "psc-ide-server --no-watch") {cwd = Just pdir}
74− threadDelay 500000 -- give the server 500ms to start up
74+ (shell "psc-ide-server --no-watch src/*.purs") {cwd = Just pdir}
75+ threadDelay 2000000 -- give the server 2s to start up
7576 return procHandle
7677
7778stopServer :: ProcessHandle -> IO ()
@@ -80,26 +81,20 @@ stopServer = terminateProcess
8081withServer :: IO a -> IO a
8182withServer s = do
8283 _ <- startServer
83− started <- tryNTimes 5 (shush <$> (try getCwd :: IO (Either SomeException String)))
84+ started <- tryNTimes 5 (rightToMaybe <$> (try getCwd :: IO (Either SomeException Text)))
8485 when (isNothing started) $
8586 throwIO (mkIOError userErrorType "psc-ide-server didn't start in time" Nothing Nothing)
8687 r <- s
8788 quitServer
8889 pure r
8990
90−shush :: Either a b -> Maybe b
91−shush = either (const Nothing) Just
92−
9391-- project management utils
9492
9593compileTestProject :: IO Bool
9694compileTestProject = do
9795 pdir <- projectDirectory
9896 (_, _, _, procHandle) <- createProcess $
99− (shell $ "psc " ++ fileGlob) { cwd = Just pdir
100− , std_out = CreatePipe
101− , std_err = CreatePipe
102− }
97+ (shell . toS $ "psc " <> fileGlob) { cwd = Just pdir }
10398 r <- tryNTimes 5 (getProcessExitCode procHandle)
10499 pure (fromMaybe False (isSuccess <$> r))
105100
@@ -121,24 +116,17 @@ deleteOutputFolder = do
121116deleteFileIfExists :: FilePath -> IO ()
122117deleteFileIfExists fp = whenM (doesFileExist fp) (removeFile fp)
123118
124−whenM :: Monad m => m Bool -> m () -> m ()
125−whenM p f = do
126− x <- p
127− when x f
128−
129119isSuccess :: ExitCode -> Bool
130120isSuccess ExitSuccess = True
131121isSuccess (ExitFailure _) = False
132122
133−fileGlob :: String
134−fileGlob = unwords
135− [ "\"src/**/*.purs\""
136− ]
123+fileGlob :: Text
124+fileGlob = "\"src/**/*.purs\""
137125
138126-- Integration Testing API
139127
140−sendCommand :: Value -> IO String
141−sendCommand v = readCreateProcess
128+sendCommand :: Value -> IO Text
129+sendCommand v = toS <$> readCreateProcess
142130 ((shell "psc-ide-client") { std_out=CreatePipe
143131 , std_err=CreatePipe
144132 })
@@ -146,65 +134,71 @@ sendCommand v = readCreateProcess
146134
147135quitServer :: IO ()
148136quitServer = do
149− let quitCommand = object ["command" .= ("quit" :: String)]
150− _ <- try $ sendCommand quitCommand :: IO (Either SomeException String)
137+ let quitCommand = object ["command" .= ("quit" :: Text)]
138+ _ <- try $ sendCommand quitCommand :: IO (Either SomeException Text)
151139 return ()
152140
153141reset :: IO ()
154142reset = do
155− let resetCommand = object ["command" .= ("reset" :: String)]
156− _ <- try $ sendCommand resetCommand :: IO (Either SomeException String)
143+ let resetCommand = object ["command" .= ("reset" :: Text)]
144+ _ <- try $ sendCommand resetCommand :: IO (Either SomeException Text)
157145 return ()
158146
159−getCwd :: IO String
147+getCwd :: IO Text
160148getCwd = do
161− let cwdCommand = object ["command" .= ("cwd" :: String)]
149+ let cwdCommand = object ["command" .= ("cwd" :: Text)]
162150 sendCommand cwdCommand
163151
164−loadModuleWithDeps :: String -> IO String
165−loadModuleWithDeps m = sendCommand $ load [] [m]
152+loadModule :: Text -> IO Text
153+loadModule m = loadModules [m]
154+
155+loadModules :: [Text] -> IO Text
156+loadModules = sendCommand . load
166157
167−loadModule :: String -> IO String
168−loadModule m = sendCommand $ load [m] []
158+loadAll :: IO Text
159+loadAll = sendCommand (load [])
169160
170−getFlexCompletions :: String -> IO [(String, String, String)]
161+getFlexCompletions :: Text -> IO [(Text, Text, Text)]
171162getFlexCompletions q = parseCompletions <$> sendCommand (completion [] (Just (flexMatcher q)) Nothing)
172163
173−getFlexCompletionsInModule :: String -> String -> IO [(String, String, String)]
164+getFlexCompletionsInModule :: Text -> Text -> IO [(Text, Text, Text)]
174165getFlexCompletionsInModule q m = parseCompletions <$> sendCommand (completion [] (Just (flexMatcher q)) (Just m))
175166
176−getType :: String -> IO [(String, String, String)]
167+getType :: Text -> IO [(Text, Text, Text)]
177168getType q = parseCompletions <$> sendCommand (typeC q [])
178169
179−addImport :: String -> FilePath -> FilePath -> IO String
170+getInfo :: Text -> IO [P.SourceSpan]
171+getInfo q = parseInfo <$> sendCommand (typeC q [])
172+
173+addImport :: Text -> FilePath -> FilePath -> IO Text
180174addImport identifier fp outfp = sendCommand (addImportC identifier fp outfp)
181175
182−addImplicitImport :: String -> FilePath -> FilePath -> IO String
176+addImplicitImport :: Text -> FilePath -> FilePath -> IO Text
183177addImplicitImport mn fp outfp = sendCommand (addImplicitImportC mn fp outfp)
184178
185−rebuildModule :: FilePath -> IO String
179+rebuildModule :: FilePath -> IO Text
186180rebuildModule m = sendCommand (rebuildC m Nothing)
187181
188182-- Command Encoding
189183
190−commandWrapper :: String -> Value -> Value
184+commandWrapper :: Text -> Value -> Value
191185commandWrapper c p = object ["command" .= c, "params" .= p]
192186
193−load :: [String] -> [String] -> Value
194−load ms ds = commandWrapper "load" (object ["modules" .= ms, "dependencies" .= ds])
187+load :: [Text] -> Value
188+load ms = commandWrapper "load" (object ["modules" .= ms])
195189
196−typeC :: String -> [Value] -> Value
190+typeC :: Text -> [Value] -> Value
197191typeC q filters = commandWrapper "type" (object ["search" .= q, "filters" .= filters])
198192
199−addImportC :: String -> FilePath -> FilePath -> Value
193+addImportC :: Text -> FilePath -> FilePath -> Value
200194addImportC identifier = addImportW $
201− object [ "importCommand" .= ("addImport" :: String)
195+ object [ "importCommand" .= ("addImport" :: Text)
202196 , "identifier" .= identifier
203197 ]
204198
205−addImplicitImportC :: String -> FilePath -> FilePath -> Value
199+addImplicitImportC :: Text -> FilePath -> FilePath -> Value
206200addImplicitImportC mn = addImportW $
207− object [ "importCommand" .= ("addImplicitImport" :: String)
201+ object [ "importCommand" .= ("addImplicitImport" :: Text)
208202 , "module" .= mn
209203 ]
210204
@@ -222,7 +216,7 @@ addImportW importCommand fp outfp =
222216 ])
223217
224218
225−completion :: [Value] -> Maybe Value -> Maybe String -> Value
219+completion :: [Value] -> Maybe Value -> Maybe Text -> Value
226220completion filters matcher currentModule =
227221 let
228222 matcher' = case matcher of
@@ -234,16 +228,16 @@ completion filters matcher currentModule =
234228 in
235229 commandWrapper "complete" (object $ "filters" .= filters : matcher' ++ currentModule' )
236230
237−flexMatcher :: String -> Value
238−flexMatcher q = object [ "matcher" .= ("flex" :: String)
231+flexMatcher :: Text -> Value
232+flexMatcher q = object [ "matcher" .= ("flex" :: Text)
239233 , "params" .= object ["search" .= q]
240234 ]
241235
242236-- Result parsing
243237
244−unwrapResult :: Value -> Parser (Either String Value)
238+unwrapResult :: Value -> Parser (Either Text Value)
245239unwrapResult = withObject "result" $ \o -> do
246− (rt :: String) <- o .: "resultType"
240+ (rt :: Text) <- o .: "resultType"
247241 case rt of
248242 "error" -> do
249243 res <- o .: "result"
@@ -251,16 +245,16 @@ unwrapResult = withObject "result" $ \o -> do
251245 "success" -> do
252246 res <- o .: "result"
253247 pure (Right res)
254− _ -> fail "lol"
248+ _ -> mzero
255249
256−withResult :: (Value -> Parser a) -> Value -> Parser (Either String a)
250+withResult :: (Value -> Parser a) -> Value -> Parser (Either Text a)
257251withResult p v = do
258252 r <- unwrapResult v
259253 case r of
260254 Left err -> pure (Left err)
261255 Right res -> Right <$> p res
262256
263−completionParser :: Value -> Parser [(String, String, String)]
257+completionParser :: Value -> Parser [(Text, Text, Text)]
264258completionParser = withArray "res" $ \cs ->
265259 mapM (withObject "completion" $ \o -> do
266260 ident <- o .: "identifier"
@@ -268,22 +262,24 @@ completionParser = withArray "res" $ \cs ->
268262 ty <- o .: "type"
269263 pure (module', ident, ty)) (V.toList cs)
270264
271−valueFromString :: String -> Value
272−valueFromString = fromJust . decode . BSL.fromString
265+infoParser :: Value -> Parser [P.SourceSpan]
266+infoParser = withArray "res" $ \cs ->
267+ mapM (withObject "info" $ \o -> o .: "definedAt") (V.toList cs)
273268
274−resultIsSuccess :: String -> Bool
275−resultIsSuccess = isRight . join . parseEither unwrapResult . valueFromString
269+valueFromText :: Text -> Value
270+valueFromText = fromJust . decode . toS
276271
277−parseCompletions :: String -> [(String, String, String)]
278−parseCompletions s = fromJust $ do
279− cs <- parseMaybe (withResult completionParser) (valueFromString s)
280− case cs of
281− Left _ -> error "Failed to parse completions"
282− Right cs' -> pure cs'
272+resultIsSuccess :: Text -> Bool
273+resultIsSuccess = isRight . join . first toS . parseEither unwrapResult . valueFromText
283274
284−parseTextResult :: String -> String
285−parseTextResult s = fromJust $ do
286− r <- parseMaybe (withResult (withText "tr" pure)) (valueFromString s)
287− case r of
288− Left _ -> error "Failed to parse textResult"
289− Right r' -> pure (T.unpack r')
275+parseCompletions :: Text -> [(Text, Text, Text)]
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 =
285+ fromJust $ join (rightToMaybe <$> parseMaybe (withResult (withText "tr" pure)) (valueFromText s))
tests/Language/PureScript/Ide/MatcherSpec.hs+16−17
@@ -1,33 +1,32 @@
11{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
23
34module Language.PureScript.Ide.MatcherSpec where
45
5−import Control.Monad (void)
6−import Data.Text (Text)
6+import Protolude
7+
78import qualified Language.PureScript as P
89import Language.PureScript.Ide.Integration
910import Language.PureScript.Ide.Matcher
1011import Language.PureScript.Ide.Types
1112import Test.Hspec
1213
13−value :: Text -> ExternDecl
14−value s = ValueDeclaration s $ P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
14+value :: Text -> IdeDeclaration
15+value s = IdeValue (P.Ident (toS s)) P.REmpty
1516
16−completions :: [Match]
17−completions =
18− [ Match "" (value "firstResult")
19− , Match "" (value "secondResult")
20− , Match "" (value "fiult")
21− ]
17+firstResult, secondResult, fiult :: Match IdeDeclaration
18+firstResult = Match (P.moduleNameFromString "Match", value "firstResult")
19+secondResult = Match (P.moduleNameFromString "Match", value "secondResult")
20+fiult = Match (P.moduleNameFromString "Match", value "fiult")
2221
23−mkResult :: [Int] -> [Match]
24−mkResult = map (completions !!)
22+completions :: [Match IdeDeclaration]
23+completions = [firstResult, secondResult, fiult]
2524
26−runFlex :: Text -> [Match]
25+runFlex :: Text -> [Match IdeDeclaration]
2726runFlex s = runMatcher (flexMatcher s) completions
2827
2928setup :: IO ()
30−setup = reset *> void (loadModuleWithDeps "Main")
29+setup = reset *> void loadAll
3130
3231spec :: Spec
3332spec = do
@@ -35,9 +34,9 @@ spec = do
3534 it "doesn't match on an empty string" $
3635 runFlex "" `shouldBe` []
3736 it "matches on equality" $
38− runFlex "firstResult" `shouldBe` mkResult [0]
37+ runFlex "firstResult" `shouldBe` [firstResult]
3938 it "scores short matches higher and sorts accordingly" $
40− runFlex "filt" `shouldBe` mkResult [2, 0]
39+ runFlex "filt" `shouldBe` [fiult, firstResult]
4140
4241 beforeAll_ setup . describe "Integration Tests: Flex Matcher" $ do
4342 it "doesn't match on an empty string" $ do
@@ -45,4 +44,4 @@ spec = do
4544 cs `shouldBe` []
4645 it "matches on equality" $ do
4746 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 #-}
13module Language.PureScript.Ide.RebuildSpec where
24
5+import Protolude
6+
37import qualified Language.PureScript.Ide.Integration as Integration
48import System.FilePath
59import Test.Hspec
610
7−shouldBeSuccess :: String -> IO ()
11+shouldBeSuccess :: Text -> IO ()
812shouldBeSuccess = shouldBe True . Integration.resultIsSuccess
913
10−shouldBeFailure :: String -> IO ()
14+shouldBeFailure :: Text -> IO ()
1115shouldBeFailure = shouldBe False . Integration.resultIsSuccess
1216
1317spec :: Spec
1418spec = before_ Integration.reset . describe "Rebuilding single modules" $ do
1519 it "rebuilds a correct module without dependencies successfully" $ do
16− _ <- Integration.loadModuleWithDeps "RebuildSpecSingleModule"
20+ _ <- Integration.loadModule "RebuildSpecSingleModule"
1721 pdir <- Integration.projectDirectory
1822 let file = pdir </> "src" </> "RebuildSpecSingleModule.purs"
1923 Integration.rebuildModule file >>= shouldBeSuccess
@@ -22,12 +26,12 @@ spec = before_ Integration.reset . describe "Rebuilding single modules" $ do
2226 let file = pdir </> "src" </> "RebuildSpecSingleModule.fail"
2327 Integration.rebuildModule file >>= shouldBeFailure
2428 it "rebuilds a correct module with its dependencies successfully" $ do
25− _ <- Integration.loadModuleWithDeps "RebuildSpecWithDeps"
29+ _ <- Integration.loadModules ["RebuildSpecWithDeps", "RebuildSpecDep"]
2630 pdir <- Integration.projectDirectory
2731 let file = pdir </> "src" </> "RebuildSpecWithDeps.purs"
2832 Integration.rebuildModule file >>= shouldBeSuccess
2933 it "rebuilds a correct module that has reverse dependencies" $ do
30− _ <- Integration.loadModuleWithDeps "RebuildSpecWithDeps"
34+ _ <- Integration.loadModule "RebuildSpecWithDeps"
3135 pdir <- Integration.projectDirectory
3236 let file = pdir </> "src" </> "RebuildSpecDep.purs"
3337 Integration.rebuildModule file >>= shouldBeSuccess
@@ -37,7 +41,7 @@ spec = before_ Integration.reset . describe "Rebuilding single modules" $ do
3741 let file = pdir </> "src" </> "RebuildSpecWithDeps.purs"
3842 Integration.rebuildModule file >>= shouldBeFailure
3943 it "rebuilds a correct module with a foreign file" $ do
40− _ <- Integration.loadModuleWithDeps "RebuildSpecWithForeign"
44+ _ <- Integration.loadModule "RebuildSpecWithForeign"
4145 pdir <- Integration.projectDirectory
4246 let file = pdir </> "src" </> "RebuildSpecWithForeign.purs"
4347 Integration.rebuildModule file >>= shouldBeSuccess
tests/Language/PureScript/Ide/ReexportsSpec.hs+54−71
@@ -1,81 +1,64 @@
11{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
23module Language.PureScript.Ide.ReexportsSpec where
34
4−import Control.Exception (evaluate)
5−import Data.List (sort)
6−import qualified Data.Map as Map
5+import qualified Prelude as Prelude
6+import Protolude
7+
8+import qualified Data.Map as Map
79import Language.PureScript.Ide.Reexports
810import Language.PureScript.Ide.Types
911import qualified Language.PureScript as P
1012import Test.Hspec
1113
12−wildcard :: P.Type
13−wildcard = P.TypeWildcard $ P.SourceSpan "" (P.SourcePos 0 0) (P.SourcePos 0 0)
14−
15−decl1 :: ExternDecl
16−decl1 = ValueDeclaration "filter" wildcard
17−decl2 :: ExternDecl
18−decl2 = ValueDeclaration "map" wildcard
19−decl3 :: ExternDecl
20−decl3 = ValueDeclaration "catMaybe" wildcard
21−dep1 :: ExternDecl
22−dep1 = Dependency "Test.Foo" [] (Just "T")
23−dep2 :: ExternDecl
24−dep2 = Dependency "Test.Bar" [] (Just "T")
25−
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]
46−
47−shouldBeEqualSorted :: Module -> Module -> Expectation
48−shouldBeEqualSorted (n1, d1) (n2, d2) = (n1, sort d1) `shouldBe` (n2, sort d2)
14+m :: Prelude.String -> P.ModuleName
15+m = P.moduleNameFromString
16+
17+d :: IdeDeclaration -> IdeDeclarationAnn
18+d = IdeDeclarationAnn emptyAnn
19+
20+valueA, typeA, classA, dtorA1, dtorA2 :: IdeDeclarationAnn
21+valueA = d (IdeValue (P.Ident "valueA") P.REmpty)
22+typeA = d (IdeType (P.ProperName "TypeA") P.Star)
23+classA = d (IdeTypeClass (P.ProperName "ClassA"))
24+dtorA1 = d (IdeDataConstructor (P.ProperName "DtorA1") (P.ProperName "TypeA") P.REmpty)
25+dtorA2 = d (IdeDataConstructor (P.ProperName "DtorA2") (P.ProperName "TypeA") P.REmpty)
26+
27+env :: Map P.ModuleName [IdeDeclarationAnn]
28+env = Map.fromList
29+ [ (m "A", [valueA, typeA, classA, dtorA1, dtorA2])
30+ ]
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+ ]
4950
5051spec :: Spec
51−spec =
52− describe "Reexports" $ do
53− it "finds all reexports" $
54− getReexports module1 `shouldBe` [Export "Module2", Export "Module3"]
55−
56− it "replaces a reexport with another module" $
57− replaceReexport (Export "Module2") module1 module2 `shouldBeEqualSorted` result
58−
59− it "adds another module even if there is no export statement" $
60− replaceReexport (Export "Module2") ("Module1", [decl1, Export "Module3"]) module2
61− `shouldBeEqualSorted` result
62−
63− it "only adds a declaration once" $
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"]
52+spec = do
53+ describe "Successful Reexports" $
54+ for_ succTestCases $ \(desc, initial, refs, result) ->
55+ it (toS desc) $ do
56+ let reResult = resolveReexports env (initial, refs)
57+ reResolved reResult `shouldBe` result
58+ reResult `shouldSatisfy` not . reexportHasFailures
59+ describe "Failed Reexports" $
60+ for_ failTestCases $ \(desc, initial, refs) ->
61+ it (toS desc) $ do
62+ let reResult = resolveReexports env (initial, refs)
63+ reFailed reResult `shouldBe` refs
64+ reResult `shouldSatisfy` reexportHasFailures
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
7676 externs <- ExceptT . fmap fst . runTest $ P.make (makeActions foreigns) (map snd modules)
7777 return (zip (map snd modules) externs)
7878 case supportExterns of
79− Left errs -> fail (P.prettyPrintMultipleErrors False errs)
79+ Left errs -> fail (P.prettyPrintMultipleErrors P.defaultPPEOptions errs)
8080 Right externs -> return (externs, passingFiles, warningFiles, failingFiles)
8181
8282 context "Passing examples" $
@@ -232,7 +232,7 @@ assertCompiles
232232assertCompiles supportExterns inputFiles =
233233 assert supportExterns inputFiles checkMain $ \e ->
234234 case e of
235− Left errs -> return . Just . P.prettyPrintMultipleErrors False $ errs
235+ Left errs -> return . Just . P.prettyPrintMultipleErrors P.defaultPPEOptions $ errs
236236 Right _ -> do
237237 process <- findNodeProcess
238238 let entryPoint = modulesDir </> "index.js"
@@ -255,7 +255,7 @@ assertCompilesWithWarnings supportExterns inputFiles shouldWarnWith =
255255 assert supportExterns inputFiles checkMain $ \e ->
256256 case e of
257257 Left errs ->
258− return . Just . P.prettyPrintMultipleErrors False $ errs
258+ return . Just . P.prettyPrintMultipleErrors P.defaultPPEOptions $ errs
259259 Right warnings ->
260260 return
261261 . fmap (printAllWarnings warnings)
@@ -263,7 +263,7 @@ assertCompilesWithWarnings supportExterns inputFiles shouldWarnWith =
263263
264264 where
265265 printAllWarnings warnings =
266− (<> "\n\n" <> P.prettyPrintMultipleErrors False warnings)
266+ (<> "\n\n" <> P.prettyPrintMultipleErrors P.defaultPPEOptions warnings)
267267
268268assertDoesNotCompile
269269 :: [(P.Module, P.ExternsFile)]
tests/TestUtils.hs+10−1
@@ -12,6 +12,8 @@ import Control.Exception
1212import System.Process
1313import System.Directory
1414import System.Info
15+import System.Exit (exitFailure)
16+import System.IO (stderr, hPutStrLn)
1517
1618findNodeProcess :: IO (Maybe String)
1719findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names
@@ -33,10 +35,17 @@ updateSupportCode = do
3335 then callProcess "setup-win.cmd" []
3436 else do
3537 callProcess "npm" ["install"]
38+ -- bower uses shebang "/usr/bin/env node", but we might have nodejs
39+ node <- maybe cannotFindNode pure =<< findNodeProcess
3640 -- Sometimes we run as a root (e.g. in simple docker containers)
3741 -- 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"]
3943 setCurrentDirectory "../.."
44+ where
45+ cannotFindNode :: IO a
46+ cannotFindNode = do
47+ hPutStrLn stderr "Cannot find node (or nodejs) executable"
48+ exitFailure
4049
4150-- |
4251-- The support modules that should be cached between test cases, to avoid
tests/support/pscide/src/ImportsSpec.purs+1−3
@@ -1,5 +1,3 @@
11module ImportsSpec where
22
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
22
33id :: forall a. a -> a
44id x = x
tests/support/pscide/src/RebuildSpecSingleModule.purs+1−1
@@ -1,4 +1,4 @@
11module RebuildSpecSingleModule where
22
33id 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−
31exports.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
4545elif [ "$BUILD_TYPE" = "haddock" ]
4646then
4747 echo ">>> Checking haddock documentation..."
48− $STACK haddock
48+ $STACK haddock --fast
4949else
5050 echo "Unrecognised BUILD_TYPE: $BUILD_TYPE"
5151 exit 1