git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge branch 'master' of github.com:purescript/purescript into deriving-generic-patch
fd82591U-CIQDEV\gbazerman
.gitignore+3
@@ -9,5 +9,8 @@ cabal.sandbox.config
9*.lksh*
9*.lksh*
10.virthualenv
10.virthualenv
11.psci_modules/
11.psci_modules/
12+.test_modules/
12bower_components/
13bower_components/
13tmp/
14tmp/
15+.stack-work/
16+tests/support/flattened/
.travis.yml+47−9
@@ -1,20 +1,43 @@
1+sudo: false
1env:
2env:
2− - CABALVER=1.22 GHCVER=7.8.3 SUITE=tests
3+ - GHCVER=7.8.4 COVERAGE_SUITE=tests
3− - CABALVER=1.22 GHCVER=7.8.3 SUITE=psci-tests
4+ - GHCVER=7.8.4 COVERAGE_SUITE=psci-tests
5+ - GHCVER=7.6.3
6+ - GHCVER=7.10.1
7+ - GHCVER=7.8.4 STACKAGE=lts-2.22
8+ # 7.10.2 Pending https://github.com/travis-ci/apt-package-whitelist/pull/686
9+ - GHCVER=7.10.1 STACKAGE-nightly-2015-08-09
4before_install:
10before_install:
5− - travis_retry sudo add-apt-repository -y ppa:hvr/ghc
11+ - export PATH="/opt/ghc/$GHCVER/bin:$PATH"
6− - travis_retry sudo apt-get update
7− - travis_retry sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER
8− - export PATH="/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$HOME/.cabal/bin:$PATH"
12+ - export PATH="/opt/cabal/1.22/bin:$PATH"
13+ - export PATH="$HOME/.cabal/bin:$PATH"
14+ - export PATH="/opt/happy/1.19.5/bin:/$PATH"
15+ - export PATH="/opt/alex/3.1.4/bin:/$PATH"
9install:
16install:
10 - cabal --version
17 - cabal --version
11 - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
18 - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
12 - travis_retry cabal update
19 - travis_retry cabal update
20+ - cabal sandbox init
21+ # Download stackage cabal.config
22+ # Not sure whether filtering out purescript is necessary
23+ - if [ -n "$STACKAGE" ]; then curl http://www.stackage.org/$STACKAGE/cabal.config | grep -v purescript > cabal.config; fi
24+ # Run with limited concurrency
25+ # Travis container infrastructure seems to expose all host CPUs (16?), thus
26+ # cabal and ghc tries to use them all. Which is bad idea on a shared box.
27+ # See also: https://ghc.haskell.org/trac/ghc/ticket/9221
28+ #
29+ # We probably want to be running with larger heap sizes when there are lots
30+ # of cores, to counteract the synchronization overhead of stop-the-world GC
31+ # across many cores. e.g. +RTS -A32m at least.
13− - cabal install --only-dependencies --enable-tests --enable-benchmarks
32+ - cabal install --only-dependencies --enable-tests -j2 --ghc-options='+RTS -A32m -RTS'
33+ - cabal install hpc-coveralls -j2
14script:
34script:
15− - ./travis-script.sh
35+ - ./travis/configure.sh
36+ - cabal build -j2 --ghc-options='+RTS -A32m -RTS'
37+ - cabal test
38+ - ./travis/test-install.sh
16after_script:
39after_script:
17− - ./travis-after-script.sh
40+ - ./travis/after.sh
18notifications:
41notifications:
19 email: true
42 email: true
20before_deploy: "./bundle/build.sh linux64"
43before_deploy: "./bundle/build.sh linux64"
@@ -28,3 +51,18 @@ deploy:
28 on:
51 on:
29 all_branches: true
52 all_branches: true
30 tags: true
53 tags: true
54+addons:
55+ apt:
56+ sources:
57+ - hvr-ghc
58+ packages:
59+ - cabal-install-1.22
60+ - ghc-7.6.3
61+ - ghc-7.8.4
62+ - ghc-7.10.1
63+ - happy-1.19.5
64+ - alex-3.1.4
65+cache:
66+ directories:
67+ - .cabal-sandbox
68+ - ../install-test/.cabal-sandbox
CONTRIBUTING.md+15−7
@@ -2,22 +2,25 @@ An introductory overview of the compiler is available [here](https://www.youtube
2
2
3Pull requests are encouraged.
3Pull requests are encouraged.
4
4
5+## Finding Issues to Work On
6+
7+If you would like to contribute, please consider the issues in the current milestone first. If you are a new contributor, you may want to have a go at the ["easy" issues](https://github.com/purescript/purescript/labels/easy) to get started.
8+
9+## Pull Requests
10+
5Please follow the following guidelines:
11Please follow the following guidelines:
6
12
7- Add at least a test to `examples/passing/` and possibly to `examples/failing`.
13- Add at least a test to `examples/passing/` and possibly to `examples/failing`.
8- Build the binaries and libs with `cabal build`
14- Build the binaries and libs with `cabal build`
9- Install the binaries and libs with `cabal install`.
15- Install the binaries and libs with `cabal install`.
10−- Run `cabal configure --enable-tests && cabal build && cabal test` to build the test suite.
16+- Run `cabal configure --enable-tests && cabal build && cabal test` to build the test suite. You will need `npm` and `node` on your PATH to run the tests.
11−- Run `purescript-test-everything` to make sure you haven't broken any core library builds.
17+- Build the core libraries by running the script in `core-tests`.
12−- Run `starter-kit` to make sure the starter kit has not been broken.
13
18
14−If you would like to contribute, please consider the issues in the current milestone first. If you are a new contributor, you may want to have a go at the ["easy" issues](https://github.com/purescript/purescript/labels/easy) to get started.
19+## Code Review
15−
16−Finally, if you have made code changes and would like to be included in the copyright notice in the cabal file, please include that change in your pull request.
17
20
18To prevent core libraries from getting broken, every change must be reviewed. A pull request will be merged as long as one other team member has verified the changes.
21To prevent core libraries from getting broken, every change must be reviewed. A pull request will be merged as long as one other team member has verified the changes.
19
22
20−## Adding dependencies
23+## Adding Dependencies
21
24
22Because the PureScript compiler is distributed in binary form, we include
25Because the PureScript compiler is distributed in binary form, we include
23the licenses of all dependencies, including transitive ones, in the LICENSE
26the licenses of all dependencies, including transitive ones, in the LICENSE
@@ -30,3 +33,8 @@ You can automate this (if you have bash):
30- run at the command line: `./license/generate > LICENSE`
33- run at the command line: `./license/generate > LICENSE`
31
34
32[cabal-dependency-licenses]: https://github.com/jaspervdj/cabal-dependency-licenses
35[cabal-dependency-licenses]: https://github.com/jaspervdj/cabal-dependency-licenses
36+
37+## Writing Issues
38+
39+- If the issue is actually a question, please consider asking on Reddit, Stack Overflow or IRC first.
40+- Please include a minimal, repeatable test case with any bug report.
INSTALL.mdnew file+47
@@ -0,0 +1,47 @@
1+# Installation information
2+
3+If you are having difficulty installing the PureScript compiler, feel free to
4+ask for help! A good place is the #purescript IRC channel on Freenode, or
5+alternatively Stack Overflow.
6+
7+## Using prebuilt binaries
8+
9+The prebuilt binaries are compiled with GHC 7.8.3, and therefore they should
10+run on any operating system supported by GHC 7.8.3, such as:
11+
12+* Windows 2000 or later,
13+* OS X 10.7 or later,
14+* Linux ??? (we're not sure what the minimum version is).
15+
16+This list is not exhaustive. If your OS is too old or not listed, or if the
17+binaries fail to run, you may be able to install the compiler by building it
18+from source; see below.
19+
20+It's probably safe to assume that other prebuilt distributions (eg, Homebrew,
21+Chocolatey, AUR, npm) use the same binaries, and therefore have the same
22+requirements.
23+
24+## Compiling from source
25+
26+GHC 7.6.1 or newer is required to compile from source. The easiest way is to
27+use `cabal-install`:
28+
29+```
30+$ cabal update && cabal install purescript
31+```
32+
33+The PureScript compiler has been known to run on OS X 10.6 when built with GHC
34+7.6.
35+
36+## The "curses" library
37+
38+`psci` depends on the `curses` library (via the Haskell package `terminfo`). If
39+you are having difficulty running the compiler, it may be because the `curses`
40+library is missing.
41+
42+On Linux, you will probably need to install `ncurses` manually. On Ubuntu, for
43+example, this can be done by running:
44+
45+```
46+$ sudo apt-get install libncurses5-dev
47+```
LICENSE+218−89
@@ -22,6 +22,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
23PureScript uses the following Haskell library packages. Their license files follow.
23PureScript uses the following Haskell library packages. Their license files follow.
24
24
25+ Glob
26+ HUnit
25 aeson
27 aeson
26 aeson-better-errors
28 aeson-better-errors
27 ansi-terminal
29 ansi-terminal
@@ -29,6 +31,7 @@ PureScript uses the following Haskell library packages. Their license files foll
29 array
31 array
30 attoparsec
32 attoparsec
31 base
33 base
34+ blaze-builder
32 bower-json
35 bower-json
33 boxes
36 boxes
34 bytestring
37 bytestring
@@ -38,10 +41,10 @@ PureScript uses the following Haskell library packages. Their license files foll
38 dlist
41 dlist
39 filepath
42 filepath
40 ghc-prim
43 ghc-prim
41− Glob
42 hashable
44 hashable
43 haskeline
45 haskeline
44 integer-gmp
46 integer-gmp
47+ language-javascript
45 mtl
48 mtl
46 nats
49 nats
47 old-locale
50 old-locale
@@ -69,6 +72,69 @@ PureScript uses the following Haskell library packages. Their license files foll
69 vector
72 vector
70 void
73 void
71
74
75+Glob LICENSE file:
76+
77+ The code in Glob is released under the license below. Copyrights to parts of
78+ the code are held by whoever wrote the code in question: see CREDITS.txt for a
79+ list of authors.
80+
81+ Copyright (c) 2008-2012 <authors>
82+ All rights reserved.
83+
84+ Redistribution and use in source and binary forms, with or without
85+ modification, are permitted provided that the following conditions are met:
86+ * Redistributions of source code must retain the above copyright
87+ notice, this list of conditions and the following disclaimer.
88+ * Redistributions in binary form must reproduce the above copyright
89+ notice, this list of conditions and the following disclaimer in the
90+ documentation and/or other materials provided with the distribution.
91+ * Neither the name of the project nor the names of its contributors may be
92+ used to endorse or promote products derived from this software without
93+ specific prior written permission.
94+
95+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
96+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
97+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
98+ EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
99+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
100+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
101+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
102+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
103+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
104+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
105+
106+HUnit LICENSE file:
107+
108+ HUnit is Copyright (c) Dean Herington, 2002, all rights reserved,
109+ and is distributed as free software under the following license.
110+
111+ Redistribution and use in source and binary forms, with or without
112+ modification, are permitted provided that the following conditions
113+ are met:
114+
115+ - Redistributions of source code must retain the above copyright
116+ notice, this list of conditions, and the following disclaimer.
117+
118+ - Redistributions in binary form must reproduce the above copyright
119+ notice, this list of conditions, and the following disclaimer in the
120+ documentation and/or other materials provided with the distribution.
121+
122+ - The names of the copyright holders may not be used to endorse or
123+ promote products derived from this software without specific prior
124+ written permission.
125+
126+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY
127+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
128+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
129+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE
130+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
131+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
132+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
133+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
134+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
135+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
136+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
137+
72aeson LICENSE file:
138aeson LICENSE file:
73
139
74 Copyright (c) 2011, MailRank, Inc.
140 Copyright (c) 2011, MailRank, Inc.
@@ -149,6 +215,7 @@ ansi-terminal LICENSE file:
149 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
215 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
150 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
216 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
151 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
217 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
218+
152ansi-wl-pprint LICENSE file:
219ansi-wl-pprint LICENSE file:
153
220
154 Copyright 2008, Daan Leijen and Max Bolingbroke. All rights reserved.
221 Copyright 2008, Daan Leijen and Max Bolingbroke. All rights reserved.
@@ -382,6 +449,39 @@ base LICENSE file:
382
449
383 -----------------------------------------------------------------------------
450 -----------------------------------------------------------------------------
384
451
452+blaze-builder LICENSE file:
453+
454+ Copyright Jasper Van der Jeugt 2010, Simon Meier 2010 & 2011
455+
456+ All rights reserved.
457+
458+ Redistribution and use in source and binary forms, with or without
459+ modification, are permitted provided that the following conditions are met:
460+
461+ * Redistributions of source code must retain the above copyright
462+ notice, this list of conditions and the following disclaimer.
463+
464+ * Redistributions in binary form must reproduce the above
465+ copyright notice, this list of conditions and the following
466+ disclaimer in the documentation and/or other materials provided
467+ with the distribution.
468+
469+ * Neither the name of Jasper Van der Jeugt nor the names of other
470+ contributors may be used to endorse or promote products derived
471+ from this software without specific prior written permission.
472+
473+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
474+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
475+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
476+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
477+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
478+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
479+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
480+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
481+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
482+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
483+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
484+
385bower-json LICENSE file:
485bower-json LICENSE file:
386
486
387 Copyright (c) 2015 Harry Garrood
487 Copyright (c) 2015 Harry Garrood
@@ -742,10 +842,6 @@ ghc-prim LICENSE file:
742 be a definition of the Haskell 98 Language.
842 be a definition of the Haskell 98 Language.
743
843
744
844
745−Glob LICENSE file:
746−
747− Page not found: Sorry, it's just not here.
748−
749hashable LICENSE file:
845hashable LICENSE file:
750
846
751 Copyright Milan Straka 2010
847 Copyright Milan Straka 2010
@@ -838,6 +934,39 @@ integer-gmp LICENSE file:
838 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
934 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
839 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
935 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
840
936
937+language-javascript LICENSE file:
938+
939+ Copyright (c)2010, Alan Zimmerman
940+
941+ All rights reserved.
942+
943+ Redistribution and use in source and binary forms, with or without
944+ modification, are permitted provided that the following conditions are met:
945+
946+ * Redistributions of source code must retain the above copyright
947+ notice, this list of conditions and the following disclaimer.
948+
949+ * Redistributions in binary form must reproduce the above
950+ copyright notice, this list of conditions and the following
951+ disclaimer in the documentation and/or other materials provided
952+ with the distribution.
953+
954+ * Neither the name of Alan Zimmerman nor the names of other
955+ contributors may be used to endorse or promote products derived
956+ from this software without specific prior written permission.
957+
958+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
959+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
960+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
961+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
962+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
963+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
964+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
965+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
966+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
967+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
968+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
969+
841mtl LICENSE file:
970mtl LICENSE file:
842
971
843 The Glasgow Haskell Compiler License
972 The Glasgow Haskell Compiler License
@@ -1198,7 +1327,7 @@ rts LICENSE file:
1198
1327
1199safe LICENSE file:
1328safe LICENSE file:
1200
1329
1201− Copyright Neil Mitchell 2007-2014.
1330+ Copyright Neil Mitchell 2007-2015.
1202 All rights reserved.
1331 All rights reserved.
1203
1332
1204 Redistribution and use in source and binary forms, with or without
1333 Redistribution and use in source and binary forms, with or without
@@ -1323,89 +1452,89 @@ split LICENSE file:
1323
1452
1324syb LICENSE file:
1453syb LICENSE file:
1325
1454
1326− This library (libraries/syb) is derived from code from several
1455+ This library (libraries/syb) is derived from code from several
1327− sources:
1456+ sources:
1328−
1457+
1329− * Code from the GHC project which is largely (c) The University of
1458+ * Code from the GHC project which is largely (c) The University of
1330− Glasgow, and distributable under a BSD-style license (see below),
1459+ Glasgow, and distributable under a BSD-style license (see below),
1331−
1460+
1332− * Code from the Haskell 98 Report which is (c) Simon Peyton Jones
1461+ * Code from the Haskell 98 Report which is (c) Simon Peyton Jones
1333− and freely redistributable (but see the full license for
1462+ and freely redistributable (but see the full license for
1334− restrictions).
1463+ restrictions).
1335−
1464+
1336− * Code from the Haskell Foreign Function Interface specification,
1465+ * Code from the Haskell Foreign Function Interface specification,
1337− which is (c) Manuel M. T. Chakravarty and freely redistributable
1466+ which is (c) Manuel M. T. Chakravarty and freely redistributable
1338− (but see the full license for restrictions).
1467+ (but see the full license for restrictions).
1339−
1468+
1340− The full text of these licenses is reproduced below. All of the
1469+ The full text of these licenses is reproduced below. All of the
1341− licenses are BSD-style or compatible.
1470+ licenses are BSD-style or compatible.
1342−
1471+
1343− -----------------------------------------------------------------------------
1472+ -----------------------------------------------------------------------------
1344−
1473+
1345− The Glasgow Haskell Compiler License
1474+ The Glasgow Haskell Compiler License
1346−
1475+
1347− Copyright 2004, The University Court of the University of Glasgow.
1476+ Copyright 2004, The University Court of the University of Glasgow.
1348− All rights reserved.
1477+ All rights reserved.
1349−
1478+
1350− Redistribution and use in source and binary forms, with or without
1479+ Redistribution and use in source and binary forms, with or without
1351− modification, are permitted provided that the following conditions are met:
1480+ modification, are permitted provided that the following conditions are met:
1352−
1481+
1353− - Redistributions of source code must retain the above copyright notice,
1482+ - Redistributions of source code must retain the above copyright notice,
1354− this list of conditions and the following disclaimer.
1483+ this list of conditions and the following disclaimer.
1355−
1484+
1356− - Redistributions in binary form must reproduce the above copyright notice,
1485+ - Redistributions in binary form must reproduce the above copyright notice,
1357− this list of conditions and the following disclaimer in the documentation
1486+ this list of conditions and the following disclaimer in the documentation
1358− and/or other materials provided with the distribution.
1487+ and/or other materials provided with the distribution.
1359−
1488+
1360− - Neither name of the University nor the names of its contributors may be
1489+ - Neither name of the University nor the names of its contributors may be
1361− used to endorse or promote products derived from this software without
1490+ used to endorse or promote products derived from this software without
1362− specific prior written permission.
1491+ specific prior written permission.
1363−
1492+
1364− THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF
1493+ THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF
1365− GLASGOW AND THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
1494+ GLASGOW AND THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
1366− INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
1495+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
1367− FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
1496+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
1368− UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS BE LIABLE
1497+ UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS BE LIABLE
1369− FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1498+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1370− DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1499+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1371− SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1500+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1372− CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1501+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1373− LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1502+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1374− OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1503+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1375− DAMAGE.
1504+ DAMAGE.
1376−
1505+
1377− -----------------------------------------------------------------------------
1506+ -----------------------------------------------------------------------------
1378−
1507+
1379− Code derived from the document "Report on the Programming Language
1508+ Code derived from the document "Report on the Programming Language
1380− Haskell 98", is distributed under the following license:
1509+ Haskell 98", is distributed under the following license:
1381−
1510+
1382− Copyright (c) 2002 Simon Peyton Jones
1511+ Copyright (c) 2002 Simon Peyton Jones
1383−
1512+
1384− The authors intend this Report to belong to the entire Haskell
1513+ The authors intend this Report to belong to the entire Haskell
1385− community, and so we grant permission to copy and distribute it for
1514+ community, and so we grant permission to copy and distribute it for
1386− any purpose, provided that it is reproduced in its entirety,
1515+ any purpose, provided that it is reproduced in its entirety,
1387− including this Notice. Modified versions of this Report may also be
1516+ including this Notice. Modified versions of this Report may also be
1388− copied and distributed for any purpose, provided that the modified
1517+ copied and distributed for any purpose, provided that the modified
1389− version is clearly presented as such, and that it does not claim to
1518+ version is clearly presented as such, and that it does not claim to
1390− be a definition of the Haskell 98 Language.
1519+ be a definition of the Haskell 98 Language.
1391−
1520+
1392− -----------------------------------------------------------------------------
1521+ -----------------------------------------------------------------------------
1393−
1522+
1394− Code derived from the document "The Haskell 98 Foreign Function
1523+ Code derived from the document "The Haskell 98 Foreign Function
1395− Interface, An Addendum to the Haskell 98 Report" is distributed under
1524+ Interface, An Addendum to the Haskell 98 Report" is distributed under
1396− the following license:
1525+ the following license:
1397−
1526+
1398− Copyright (c) 2002 Manuel M. T. Chakravarty
1527+ Copyright (c) 2002 Manuel M. T. Chakravarty
1399−
1528+
1400− The authors intend this Report to belong to the entire Haskell
1529+ The authors intend this Report to belong to the entire Haskell
1401− community, and so we grant permission to copy and distribute it for
1530+ community, and so we grant permission to copy and distribute it for
1402− any purpose, provided that it is reproduced in its entirety,
1531+ any purpose, provided that it is reproduced in its entirety,
1403− including this Notice. Modified versions of this Report may also be
1532+ including this Notice. Modified versions of this Report may also be
1404− copied and distributed for any purpose, provided that the modified
1533+ copied and distributed for any purpose, provided that the modified
1405− version is clearly presented as such, and that it does not claim to
1534+ version is clearly presented as such, and that it does not claim to
1406− be a definition of the Haskell 98 Foreign Function Interface.
1535+ be a definition of the Haskell 98 Foreign Function Interface.
1407−
1536+
1408− -----------------------------------------------------------------------------
1537+ -----------------------------------------------------------------------------
1409
1538
1410template-haskell LICENSE file:
1539template-haskell LICENSE file:
1411
1540
README.md+1−1
@@ -2,7 +2,7 @@
2
2
3A small strongly typed programming language with expressive types that compiles to Javascript, written in and inspired by Haskell.
3A small strongly typed programming language with expressive types that compiles to Javascript, written in and inspired by Haskell.
4
4
5−[![Hackage](https://budueba.com/hackage/purescript)](http://hackage.haskell.org/package/purescript) [![Build Status](https://secure.travis-ci.org/purescript/purescript.png?branch=master)](http://travis-ci.org/purescript/purescript) [![Coverage Status](https://coveralls.io/repos/purescript/purescript/badge.png?branch=master)](https://coveralls.io/r/purescript/purescript?branch=master)
5+[![Hackage](https://budueba.com/hackage/purescript)](http://hackage.haskell.org/package/purescript) [![Build Status](https://api.travis-ci.org/purescript/purescript.svg?branch=master)](http://travis-ci.org/purescript/purescript) [![Coverage Status](https://coveralls.io/repos/purescript/purescript/badge.svg?branch=master)](https://coveralls.io/r/purescript/purescript?branch=master)
6
6
7## Language info
7## Language info
8
8
bundle/README+6−5
@@ -10,11 +10,12 @@ Installation Instructions
10
10
11This bundle contains the following executables:
11This bundle contains the following executables:
12
12
13−- psc The PureScript compiler (generates JavaScript for use
13+- psc The PureScript compiler
14− in the browser)
15−- psc-make The PureScript compiler (generates CommonJS modules)
16−- psci The PureScript interactive module (requires NodeJS)
14+- psci The PureScript interactive REPL (requires NodeJS)
17−- psc-docs A documentation generator
15+- psc-docs A Markdown documentation generator for PureScript code
16+- psc-bundle Bundles together CommonJS modules produced by `psc` into a
17+ single JavaScript file; useful for running in the browser.
18+- psc-publish Generates documentation packages for uploading to Pursuit
18
19
19Copy these files anywhere on your PATH.
20Copy these files anywhere on your PATH.
20
21
bundle/build.sh+3−2
@@ -18,18 +18,19 @@ mkdir -p build/purescript/
18# Strip the binaries
18# Strip the binaries
19strip ../dist/build/psc/psc
19strip ../dist/build/psc/psc
20strip ../dist/build/psci/psci
20strip ../dist/build/psci/psci
21−strip ../dist/build/psc-make/psc-make
22strip ../dist/build/psc-docs/psc-docs
21strip ../dist/build/psc-docs/psc-docs
23strip ../dist/build/psc-publish/psc-publish
22strip ../dist/build/psc-publish/psc-publish
23+strip ../dist/build/psc-bundle/psc-bundle
24
24
25# Copy files to staging directory
25# Copy files to staging directory
26cp ../dist/build/psc/psc build/purescript/
26cp ../dist/build/psc/psc build/purescript/
27cp ../dist/build/psci/psci build/purescript/
27cp ../dist/build/psci/psci build/purescript/
28−cp ../dist/build/psc-make/psc-make build/purescript/
29cp ../dist/build/psc-docs/psc-docs build/purescript/
28cp ../dist/build/psc-docs/psc-docs build/purescript/
30cp ../dist/build/psc-publish/psc-publish build/purescript/
29cp ../dist/build/psc-publish/psc-publish build/purescript/
30+cp ../dist/build/psc-bundle/psc-bundle build/purescript/
31cp README build/purescript/
31cp README build/purescript/
32cp ../LICENSE build/purescript/
32cp ../LICENSE build/purescript/
33+cp ../INSTALL.md build/purescript/
33
34
34# Make the binary bundle
35# Make the binary bundle
35pushd build > /dev/null
36pushd build > /dev/null
bundle/winbuild.sh+3−2
@@ -14,18 +14,19 @@ mkdir -p build/purescript/
14# Strip the binaries
14# Strip the binaries
15strip ../dist/build/psc/psc.exe
15strip ../dist/build/psc/psc.exe
16strip ../dist/build/psci/psci.exe
16strip ../dist/build/psci/psci.exe
17−strip ../dist/build/psc-make/psc-make.exe
18strip ../dist/build/psc-docs/psc-docs.exe
17strip ../dist/build/psc-docs/psc-docs.exe
19strip ../dist/build/psc-publish/psc-publish.exe
18strip ../dist/build/psc-publish/psc-publish.exe
19+strip ../dist/build/psc-bundle/psc-bundle.exe
20
20
21# Copy files to staging directory
21# Copy files to staging directory
22cp ../dist/build/psc/psc.exe build/purescript/
22cp ../dist/build/psc/psc.exe build/purescript/
23cp ../dist/build/psci/psci.exe build/purescript/
23cp ../dist/build/psci/psci.exe build/purescript/
24−cp ../dist/build/psc-make/psc-make.exe build/purescript/
25cp ../dist/build/psc-docs/psc-docs.exe build/purescript/
24cp ../dist/build/psc-docs/psc-docs.exe build/purescript/
26cp ../dist/build/psc-publish/psc-publish.exe build/purescript/
25cp ../dist/build/psc-publish/psc-publish.exe build/purescript/
26+cp ../dist/build/psc-bundle/psc-bundle.exe build/purescript/
27cp README build/purescript/
27cp README build/purescript/
28cp ../LICENSE build/purescript/
28cp ../LICENSE build/purescript/
29+cp ../INSTALL.md build/purescript/
29
30
30# Make the binary bundle
31# Make the binary bundle
31pushd build
32pushd build
core-tests/test-everything.sh+6−3
@@ -18,7 +18,6 @@ bower i purescript-prelude \
18 purescript-maps \
18 purescript-maps \
19 purescript-free \
19 purescript-free \
20 purescript-transformers \
20 purescript-transformers \
21− purescript-monad-eff \
22 purescript-exists \
21 purescript-exists \
23 purescript-monoid \
22 purescript-monoid \
24 purescript-either \
23 purescript-either \
@@ -45,6 +44,10 @@ bower i purescript-prelude \
45 purescript-globals \
44 purescript-globals \
46 purescript-exceptions \
45 purescript-exceptions \
47 purescript-validation \
46 purescript-validation \
47+ purescript-parallel \
48+ purescript-proxy \
49+ purescript-semirings \
48 purescript-math
50 purescript-math
49−
51+
50−find bower_components/**/src -name '*.purs' | xargs ../dist/build/psc-make/psc-make
52+../dist/build/psc/psc 'bower_components/purescript-*/src/**/*.purs' \
53+ --ffi 'bower_components/purescript-*/src/**/*.js'
examples/failing/365.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInDeclaration
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/438.purs+6−2
@@ -1,3 +1,8 @@
1+-- @shouldFailWith NoInstanceFound
2+
3+-- See issue 438 for details: this test is mainly here to test that code like
4+-- this doesn't cause the compiler to loop.
5+
1module Main where
6module Main where
2
7
3import Prelude
8import Prelude
@@ -5,7 +10,6 @@ import Prelude
5data Fix f = In (f (Fix f))
10data Fix f = In (f (Fix f))
6
11
7instance eqFix :: (Eq (f (Fix f))) => Eq (Fix f) where
12instance eqFix :: (Eq (f (Fix f))) => Eq (Fix f) where
8− (==) (In f) (In g) = f == g
13+ eq (In f) (In g) = f == g
9− (/=) a b = not (a == b)
10
14
11example = In [] == In []
15example = In [] == In []
examples/failing/ArrayType.purs+3−1
@@ -1,7 +1,9 @@
1+-- @shouldFailWith TypesDoNotUnify
2+
1module Main where
3module Main where
2
4
3import Prelude
5import Prelude
4−import Debug.Trace
6+import Control.Monad.Eff.Console
5
7
6bar :: Number -> Number -> Number
8bar :: Number -> Number -> Number
7bar n m = n + m
9bar n m = n + m
examples/failing/Arrays.purs+3
@@ -1,5 +1,8 @@
1+-- @shouldFailWith ExprDoesNotHaveType
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
4
5
6+foreign import (!!) :: forall a. Array a -> Int -> a
7+
5test = \arr -> arr !! (0 !! 0)
8test = \arr -> arr !! (0 !! 0)
examples/failing/CaseDoesNotMatchAllConstructorArgs.pursnew file+15
@@ -0,0 +1,15 @@
1+-- @shouldFailWith IncorrectConstructorArity
2+module Main where
3+
4+import Prelude
5+
6+data Person = Person String Int
7+
8+data TwoPeople = Two Person Person
9+
10+getName p = case p of
11+ (Two (Person n) (Person n2 a2)) -> n
12+ _ -> "Unknown"
13+
14+
15+name = getName (Two (Person "Jimmy" 20) (Person "" 1))
examples/failing/Do.purs+2
@@ -1,3 +1,5 @@
1+-- @shouldFailWith InvalidDoBind
2+-- @shouldFailWith InvalidDoLet
1module Main where
3module Main where
2
4
3import Prelude
5import Prelude
examples/failing/DoNotSuggestComposition.pursnew file+13
@@ -0,0 +1,13 @@
1+-- @shouldFailWith TypesDoNotUnify
2+-- TODO: Check that this does not produce a "function composition is (<<<)"
3+-- suggestion.
4+module DoNotSuggestComposition where
5+
6+import Prelude
7+
8+x = { y: 3 }
9+
10+foo :: String -> String
11+foo y = y
12+
13+bar = foo x
examples/failing/DoNotSuggestComposition2.pursnew file+7
@@ -0,0 +1,7 @@
1+-- @shouldFailWith CannotApplyFunction
2+-- TODO: Check that this does not produce a "function composition is (<<<)"
3+-- suggestion.
4+
5+module DoNotSuggestComposition2 where
6+
7+foo = let x = { y: 3 } in x 2
examples/failing/DuplicateDeclarationsInLet.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith OverlappingNamesInLet
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/DuplicateProperties1.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith TypesDoNotUnify
1module DuplicateProperties where
2module DuplicateProperties where
2
3
3import Prelude
4import Prelude
examples/failing/DuplicateProperties2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith DuplicateLabel
1module DuplicateProperties where
2module DuplicateProperties where
2
3
3import Prelude
4import Prelude
examples/failing/DuplicateTypeVars.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith DuplicateTypeArgument
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/Eff.purs+3−2
@@ -1,12 +1,13 @@
1+-- @shouldFailWith TypesDoNotUnify
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
4import Control.Monad.Eff
5import Control.Monad.Eff
5import Control.Monad.ST
6import Control.Monad.ST
6−import Debug.Trace
7+import Control.Monad.Eff.Console
7
8
8test = pureST (do
9test = pureST (do
9 ref <- newSTRef 0
10 ref <- newSTRef 0
10− trace "ST"
11+ log "ST"
11 modifySTRef ref $ \n -> n + 1
12 modifySTRef ref $ \n -> n + 1
12 readSTRef ref)
13 readSTRef ref)
examples/failing/ExtraRecordField.pursnew file+10
@@ -0,0 +1,10 @@
1+-- @shouldFailWith PropertyIsMissing
2+-- TODO: Make this fail with a new error ExtraProperty instead.
3+module ExtraRecordField where
4+
5+import Prelude ((<>))
6+
7+full :: { first :: String, last :: String } -> String
8+full p = p.first <> " " <> p.last
9+
10+oops = full { first: "Jane", last: "Smith", age: 29 }
examples/failing/Foldable.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInDeclaration
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/InfiniteKind.pursnew file+5
@@ -0,0 +1,5 @@
1+-- @shouldFailWith InfiniteKind
2+
3+module Main where
4+
5+data F a = F (a a)
examples/failing/InfiniteType.pursnew file+5
@@ -0,0 +1,5 @@
1+-- @shouldFailWith InfiniteType
2+
3+module Main where
4+
5+f a = a a
examples/failing/InstanceExport.purs+2
@@ -1,3 +1,4 @@
1+-- @shouldFailWith TransitiveExportError
1module InstanceExport (S(..), f) where
2module InstanceExport (S(..), f) where
2
3
3import Prelude
4import Prelude
@@ -13,5 +14,6 @@ instance fs :: F S where
13module Test where
14module Test where
14
15
15import InstanceExport
16import InstanceExport
17+import Prelude
16
18
17test = f $ S "Test"
19test = f $ S "Test"
examples/failing/KindError.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith KindsDoNotUnify
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/LeadingZeros1.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/LeadingZeros2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/Let.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInDeclaration
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/MPTCs.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith KindsDoNotUnify
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/MissingClassExport.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith TransitiveExportError
1module Test (bar) where
2module Test (bar) where
2
3
3import Prelude
4import Prelude
examples/failing/MissingClassMemberExport.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith TransitiveExportError
1module Test (Foo) where
2module Test (Foo) where
2
3
3import Prelude
4import Prelude
examples/failing/MissingRecordField.pursnew file+11
@@ -0,0 +1,11 @@
1+-- @shouldFailWith TypesDoNotUnify
2+-- TODO: Update type checker to make this fail with PropertyIsMissing instead.
3+module MissingRecordField where
4+
5+import Prelude ((>))
6+
7+john = { first: "John", last: "Smith" }
8+
9+isOver50 p = p.age > 50.0
10+
11+result = isOver50 john
examples/failing/MultipleErrors.purs+4−2
@@ -1,11 +1,13 @@
1+-- @shouldFailWith ExprDoesNotHaveType
2+-- @shouldFailWith ExprDoesNotHaveType
1module MultipleErrors where
3module MultipleErrors where
2
4
3import Prelude
5import Prelude
4
6
5−foo :: Number -> Number
7+foo :: Int -> Int
6foo 0 = "Test"
8foo 0 = "Test"
7foo n = bar (n - 1)
9foo n = bar (n - 1)
8
10
9−bar :: Number -> Number
11+bar :: Int -> Int
10bar 0 = "Test"
12bar 0 = "Test"
11bar n = foo (n - 1)
13bar n = foo (n - 1)
examples/failing/MultipleErrors2.purs+2
@@ -1,3 +1,5 @@
1+-- @shouldFailWith UnknownValue
2+-- @shouldFailWith UnknownValue
1module MultipleErrors2 where
3module MultipleErrors2 where
2
4
3import Prelude
5import Prelude
examples/failing/MutRec.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInDeclaration
1module MutRec where
2module MutRec where
2
3
3import Prelude
4import Prelude
examples/failing/MutRec2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInDeclaration
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/NewtypeMultiArgs.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith InvalidNewtype
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/NewtypeMultiCtor.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith InvalidNewtype
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/NoOverlap.pursdeleted−13
@@ -1,13 +0,0 @@
1−module Main where
2−
3−import Prelude
4−
5−data Foo = Foo
6−
7−instance showFoo1 :: Show Foo where
8− show _ = "Foo"
9−
10−instance showFoo2 :: Show Foo where
11− show _ = "Bar"
12−
13−test = show Foo
examples/failing/NullaryAbs.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/Object.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith PropertyIsMissing
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/OverlappingArguments.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith OverlappingArgNames
1module OverlappingArguments where
2module OverlappingArguments where
2
3
3import Prelude
4import Prelude
examples/failing/OverlappingBinders.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith OverlappingArgNames
1module OverlappingBinders where
2module OverlappingBinders where
2
3
3import Prelude
4import Prelude
examples/failing/OverlappingInstances.purs+2−1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith OverlappingInstances
1module OverlappingInstances where
2module OverlappingInstances where
2
3
3import Prelude
4import Prelude
@@ -10,4 +11,4 @@ instance showA1 :: Show A where
10instance showA2 :: Show A where
11instance showA2 :: Show A where
11 show A = "Instance 2"
12 show A = "Instance 2"
12
13
13−main = Debug.Trace.trace $ show A
14+main = Control.Monad.Eff.Console.log $ show A
examples/failing/OverlappingInstances2.purs+6−7
@@ -1,3 +1,4 @@
1+-- @shouldFailWith OverlappingInstances
1module OverlappingInstances where
2module OverlappingInstances where
2
3
3import Prelude
4import Prelude
@@ -5,14 +6,12 @@ import Prelude
5data A = A | B
6data A = A | B
6
7
7instance eqA1 :: Eq A where
8instance eqA1 :: Eq A where
8− (==) A A = true
9+ eq A A = true
9− (==) B B = true
10+ eq B B = true
10− (==) _ _ = false
11+ eq _ _ = false
11− (/=) x y = not (x == y)
12
12
13instance eqA2 :: Eq A where
13instance eqA2 :: Eq A where
14− (==) _ _ = true
14+ eq _ _ = true
15− (/=) _ _ = false
16
15
17instance ordA :: Ord A where
16instance ordA :: Ord A where
18 compare A B = LT
17 compare A B = LT
@@ -22,4 +21,4 @@ instance ordA :: Ord A where
22test :: forall a. (Ord a) => a -> a -> String
21test :: forall a. (Ord a) => a -> a -> String
23test x y = show $ x == y
22test x y = show $ x == y
24
23
25−main = Debug.Trace.trace $ test A B
24+main = Control.Monad.Eff.Console.log $ test A B
examples/failing/OverlappingVars.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith NoInstanceFound
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/Rank2Types.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ExprDoesNotHaveType
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/Reserved.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/RowConstructors1.purs+2−1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith KindsDoNotUnify
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
@@ -5,4 +6,4 @@ import Prelude
5data Foo = Bar
6data Foo = Bar
6type Baz = { | Foo }
7type Baz = { | Foo }
7
8
8−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/failing/RowConstructors2.purs+2−1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith KindsDoNotUnify
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
@@ -5,4 +6,4 @@ import Prelude
5type Foo r = (x :: Number | r)
6type Foo r = (x :: Number | r)
6type Bar = { | Foo }
7type Bar = { | Foo }
7
8
8−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/failing/RowConstructors3.purs+2−1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith KindsDoNotUnify
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
@@ -5,4 +6,4 @@ import Prelude
5type Foo = { x :: Number }
6type Foo = { x :: Number }
6type Bar = { | Foo }
7type Bar = { | Foo }
7
8
8−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/failing/SkolemEscape.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith EscapedSkolem
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/SkolemEscape2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith EscapedSkolem
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/SuggestComposition.pursnew file+7
@@ -0,0 +1,7 @@
1+-- @shouldFailWith TypesDoNotUnify
2+-- TODO: Ensure the correct suggestion is produced.
3+module SuggestComposition where
4+
5+import Prelude
6+
7+f = g . g where g = (+1)
examples/failing/Superclasses1.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith NoInstanceFound
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/Superclasses2.purs+2
@@ -1,3 +1,5 @@
1+-- @shouldFailWith CycleInTypeSynonym
2+-- TODO: Should this have its own error, perhaps CycleInTypeClassDeclaration?
1module CycleInSuperclasses where
3module CycleInSuperclasses where
2
4
3import Prelude
5import Prelude
examples/failing/Superclasses3.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith UndefinedTypeVariable
1module UnknownSuperclassTypeVar where
2module UnknownSuperclassTypeVar where
2
3
3import Prelude
4import Prelude
examples/failing/Superclasses4.purs+2−1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith OverlappingInstances
1module OverlappingInstances where
2module OverlappingInstances where
2
3
3import Prelude
4import Prelude
@@ -11,4 +12,4 @@ instance foo2 :: Foo Number
11test :: forall a. (Foo a) => a -> a
12test :: forall a. (Foo a) => a -> a
12test a = a
13test a = a
13
14
14−test1 = test 0
15+test1 = test 0.0
examples/failing/TopLevelCaseNoArgs.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith DuplicateValueDeclaration
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/TypeClassInstances.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith MissingClassMember
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/TypeClasses2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith NoInstanceFound
1module Main where
2module Main where
2
3
3import Prelude ()
4import Prelude ()
examples/failing/TypeError.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ExprDoesNotHaveType
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/TypeSynonyms.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInTypeSynonym
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/TypeSynonyms2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith TypeSynonymInstance
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/TypeSynonyms3.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith TypeSynonymInstance
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/TypeSynonyms4.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith PartiallyAppliedSynonym
1module TypeSynonyms4 where
2module TypeSynonyms4 where
2
3
3import Prelude
4import Prelude
examples/failing/TypeSynonyms5.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInTypeSynonym
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/failing/TypeWildcards1.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
1module TypeWildcards where
2module TypeWildcards where
2
3
3import Prelude
4import Prelude
examples/failing/TypeWildcards2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
1module TypeWildcards where
2module TypeWildcards where
2
3
3import Prelude
4import Prelude
examples/failing/TypeWildcards3.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
1module TypeWildcards where
2module TypeWildcards where
2
3
3import Prelude
4import Prelude
examples/failing/UnderscoreModuleName.purs+2−1
@@ -1,5 +1,6 @@
1+-- @shouldFailWith ErrorParsingModule
1module Bad_Module where
2module Bad_Module where
2
3
3import Prelude
4import Prelude
4
5
5−main = Debug.Trace.trace "Done"
6+main = Control.Monad.Eff.Console.log "Done"
examples/failing/UnifyInTypeInstanceLookup.purs+3
@@ -1,3 +1,6 @@
1+-- @shouldFailWith NoInstanceFound
2+-- See issue #390.
3+-- TODO: Improve this error.
1module Main where
4module Main where
2
5
3import Prelude
6import Prelude
examples/failing/UnknownType.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith UnknownType
1module Main where
2module Main where
2
3
3import Prelude
4import Prelude
examples/manual/QualifiedNames.purs+1−1
@@ -10,4 +10,4 @@ either :: forall a b c. (a -> c) -> (b -> c) -> Data.Either.Either a b -> c
10either f _ (Data.Either.Left x) = f x
10either f _ (Data.Either.Left x) = f x
11either _ g (Data.Either.Right y) = g y
11either _ g (Data.Either.Right y) = g y
12
12
13−main = Debug.Trace.trace (either id id (Data.Either.Left "Done"))
13+main = Control.Monad.Eff.Console.log (either id id (Data.Either.Left "Done"))
examples/manual/failing/ExportExplicit1.purs+1−1
@@ -11,4 +11,4 @@ module Main where
11 -- should fail as Y constructor is not exported from M1
11 -- should fail as Y constructor is not exported from M1
12 testY = Y
12 testY = Y
13
13
14− main = Debug.Trace.trace "Done"
14+ main = Control.Monad.Eff.Console.log "Done"
examples/manual/failing/ExportExplicit3.purs+1−1
@@ -10,4 +10,4 @@ module Main where
10 -- should fail as Z is not exported from M1
10 -- should fail as Z is not exported from M1
11 testZ = M1.Z
11 testZ = M1.Z
12
12
13− main = Debug.Trace.trace "Done"
13+ main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/ExportExplicit.purs+1−1
@@ -17,4 +17,4 @@ module Main where
17 testZ = Z
17 testZ = Z
18 testFoo = foo
18 testFoo = foo
19
19
20− main = Debug.Trace.trace "Done"
20+ main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/ExportExplicit2.purs+1−1
@@ -12,4 +12,4 @@ module Main where
12
12
13 testBar = bar
13 testBar = bar
14
14
15− main = Debug.Trace.trace "Done"
15+ main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/Import.purs+1−1
@@ -16,4 +16,4 @@ module M2 where
16
16
17module Main where
17module Main where
18
18
19−main = Debug.Trace.trace "Done"
19+main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/ImportExplicit.purs+1−1
@@ -11,4 +11,4 @@ module Main where
11 testX = X
11 testX = X
12 testY = Y
12 testY = Y
13
13
14− main = Debug.Trace.trace "Done"
14+ main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/ImportQualified.purs+3−3
@@ -1,12 +1,12 @@
1module M1 where
1module M1 where
2
2
3− trace x = x
3+ log x = x
4
4
5module Main where
5module Main where
6
6
7 import Prelude
7 import Prelude
8 import Control.Monad.Eff
8 import Control.Monad.Eff
9 import M1
9 import M1
10− import qualified Debug.Trace as T
10+ import qualified Control.Monad.Eff.Console as C
11
11
12− main = T.trace (trace "Done")
12+ main = C.log (log "Done")
examples/manual/passing/Module.purs+1−1
@@ -25,4 +25,4 @@ module M2 where
25
25
26module Main where
26module Main where
27
27
28−main = Debug.Trace.trace "Done"
28+main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/ModuleDeps.purs+1−1
@@ -14,4 +14,4 @@ baz = 1
14
14
15module Main where
15module Main where
16
16
17−main = Debug.Trace.trace "Done"
17+main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/RedefinedFixity.purs+1−1
@@ -21,4 +21,4 @@ import M2
21
21
22module Main where
22module Main where
23
23
24−main = Debug.Trace.trace "Done"
24+main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/ShadowedName.purs+2−2
@@ -1,10 +1,10 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
5
5
6done :: String
6done :: String
7done = let str = "Not yet done" in
7done = let str = "Not yet done" in
8 let str = "Done" in str
8 let str = "Done" in str
9
9
10−main = Debug.Trace.trace done
10+main = Control.Monad.Eff.Console.log done
examples/manual/passing/TransitiveImport.purs+1−1
@@ -16,7 +16,7 @@ module Main where
16
16
17 import Prelude
17 import Prelude
18 import Middle
18 import Middle
19− import Debug.Trace
19+ import Control.Monad.Eff.Console
20
20
21 main = do
21 main = do
22 print (middle unit)
22 print (middle unit)
examples/manual/passing/WildcardType.purs+2−2
@@ -1,7 +1,7 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
5
5
6f1 :: (_ -> _) -> _
6f1 :: (_ -> _) -> _
7f1 g = g 1
7f1 g = g 1
@@ -9,5 +9,5 @@ f1 g = g 1
9f2 :: _ -> _
9f2 :: _ -> _
10f2 _ = "Done"
10f2 _ = "Done"
11
11
12−main = Debug.Trace.trace $ f1 f2
12+main = Control.Monad.Eff.Console.log $ f1 f2
13
13
examples/passing/652.purs+1−1
@@ -14,4 +14,4 @@ instance bar :: Bar (a -> b) b
14
14
15instance baz :: (Eq a) => Baz (a -> b) a b
15instance baz :: (Eq a) => Baz (a -> b) a b
16
16
17−main = Debug.Trace.trace "Done"
17+main = Control.Monad.Eff.Console.log "Done"
examples/passing/810.purs+1−1
@@ -10,4 +10,4 @@ test m = o.x
10 o = case m of Nothing -> { x : Nothing }
10 o = case m of Nothing -> { x : Nothing }
11 Just a -> { x : Just a }
11 Just a -> { x : Just a }
12
12
13−main = Debug.Trace.trace "Done"
13+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Applicative.purs+4−4
@@ -4,13 +4,13 @@ import Prelude ()
4
4
5class Applicative f where
5class Applicative f where
6 pure :: forall a. a -> f a
6 pure :: forall a. a -> f a
7− (<*>) :: forall a b. f (a -> b) -> f a -> f b
7+ apply :: forall a b. f (a -> b) -> f a -> f b
8
8
9data Maybe a = Nothing | Just a
9data Maybe a = Nothing | Just a
10
10
11instance applicativeMaybe :: Applicative Maybe where
11instance applicativeMaybe :: Applicative Maybe where
12 pure = Just
12 pure = Just
13− (<*>) (Just f) (Just a) = Just (f a)
13+ apply (Just f) (Just a) = Just (f a)
14− (<*>) _ _ = Nothing
14+ apply _ _ = Nothing
15
15
16−main = Debug.Trace.trace "Done"
16+main = Control.Monad.Eff.Console.log "Done"
examples/passing/ArrayType.purs+1−1
@@ -8,4 +8,4 @@ class Pointed p where
8instance pointedArray :: Pointed Array where
8instance pointedArray :: Pointed Array where
9 point a = [a]
9 point a = [a]
10
10
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Auto.purs+1−1
@@ -12,4 +12,4 @@ exists = \state step f -> f (Auto { state: state, step: step })
12run :: forall i o. SomeAuto i o -> i -> o
12run :: forall i o. SomeAuto i o -> i -> o
13run = \s i -> s (\a -> case a of Auto a -> a.step a.state i)
13run = \s i -> s (\a -> case a of Auto a -> a.step a.state i)
14
14
15−main = Debug.Trace.trace "Done"
15+main = Control.Monad.Eff.Console.log "Done"
examples/passing/AutoPrelude.purs+2−2
@@ -1,9 +1,9 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
5
5
6f x = x * 10.0
6f x = x * 10.0
7g y = y - 10.0
7g y = y - 10.0
8
8
9−main = trace $ show $ (f <<< g) 100.0
9+main = log $ show $ (f <<< g) 100.0
examples/passing/AutoPrelude2.purs+2−2
@@ -2,9 +2,9 @@ module Main where
2
2
3import Prelude
3import Prelude
4import qualified Prelude as P
4import qualified Prelude as P
5−import Debug.Trace
5+import Control.Monad.Eff.Console
6
6
7f :: forall a. a -> a
7f :: forall a. a -> a
8f = P.id
8f = P.id
9
9
10−main = P.($) trace ((f P.<<< f) "Done")
10+main = P.($) log ((f P.<<< f) "Done")
examples/passing/BindersInFunctions.purs+5−6
@@ -1,12 +1,11 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Assert
4+import Test.Assert
5
5
6snd = \[_, y] -> y
6snd = \[_, y] -> y
7
7
8−main =
8+main = do
9− let ts = snd [1.0, 2.0] in
9+ let ts = snd [1.0, 2.0]
10− if ts == 2.0
11− then Debug.Trace.trace "Done"
12− else error "Incorrect result from 'snd'."
10+ assert' "Incorrect result from 'snd'." (ts == 2.0)
11+ Control.Monad.Eff.Console.log "Done"
examples/passing/BindingGroups.purs+1−1
@@ -7,4 +7,4 @@ foo = bar
7
7
8r = foo 2.0
8r = foo 2.0
9
9
10−main = Debug.Trace.trace "Done"
10+main = Control.Monad.Eff.Console.log "Done"
examples/passing/BlockString.purs+1−1
@@ -5,4 +5,4 @@ import Prelude
5foo :: String
5foo :: String
6foo = """foo"""
6foo = """foo"""
7
7
8−main = Debug.Trace.trace "Done"
8+main = Control.Monad.Eff.Console.log "Done"
examples/passing/CaseInDo.purs+3−3
@@ -1,14 +1,14 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
5import Control.Monad.Eff
5import Control.Monad.Eff
6
6
7doIt :: forall eff. Eff eff Boolean
7doIt :: forall eff. Eff eff Boolean
8doIt = return true
8doIt = return true
9
9
10set = do
10set = do
11− trace "Testing..."
11+ log "Testing..."
12 case 0 of
12 case 0 of
13 0 -> doIt
13 0 -> doIt
14 _ -> return false
14 _ -> return false
@@ -16,4 +16,4 @@ set = do
16main = do
16main = do
17 b <- set
17 b <- set
18 case b of
18 case b of
19− true -> trace "Done"
19+ true -> log "Done"
examples/passing/CaseStatement.purs+1−1
@@ -18,4 +18,4 @@ h f N a = a
18h f a N = a
18h f a N = a
19h f (J a) (J b) = J (f a b)
19h f (J a) (J b) = J (f a b)
20
20
21−main = Debug.Trace.trace $ f "Done" "Failed" A
21+main = Control.Monad.Eff.Console.log $ f "Done" "Failed" A
examples/passing/CheckFunction.purs+1−1
@@ -4,4 +4,4 @@ import Prelude
4
4
5test = ((\x -> x+1.0) >>> (\x -> x*2.0)) 4.0
5test = ((\x -> x+1.0) >>> (\x -> x*2.0)) 4.0
6
6
7−main = Debug.Trace.trace "Done"
7+main = Control.Monad.Eff.Console.log "Done"
examples/passing/CheckSynonymBug.purs+4−1
@@ -2,8 +2,11 @@ module Main where
2
2
3import Prelude
3import Prelude
4
4
5+length :: forall a. Array a -> Int
6+length _ = 0
7+
5type Foo a = Array a
8type Foo a = Array a
6
9
7foo _ = length ([] :: Foo Number)
10foo _ = length ([] :: Foo Number)
8
11
9−main = Debug.Trace.trace "Done"
12+main = Control.Monad.Eff.Console.log "Done"
examples/passing/CheckTypeClass.purs+1−1
@@ -14,5 +14,5 @@ foo_ x = foo ((mkBar :: forall a. (Foo a) => a -> Bar a) x)
14mkBar :: forall a. a -> Bar a
14mkBar :: forall a. a -> Bar a
15mkBar _ = Bar
15mkBar _ = Bar
16
16
17−main = Debug.Trace.trace "Done"
17+main = Control.Monad.Eff.Console.log "Done"
18
18
examples/passing/Church.purs+1−1
@@ -15,4 +15,4 @@ append = \l1 l2 r f -> l2 (l1 r f) f
15
15
16test = append (cons 1 empty) (cons 2 empty)
16test = append (cons 1 empty) (cons 2 empty)
17
17
18−main = Debug.Trace.trace "Done"
18+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Collatz.purs+6−6
@@ -4,15 +4,15 @@ import Prelude
4import Control.Monad.Eff
4import Control.Monad.Eff
5import Control.Monad.ST
5import Control.Monad.ST
6
6
7−collatz :: Number -> Number
7+collatz :: Int -> Int
8collatz n = runPure (runST (do
8collatz n = runPure (runST (do
9 r <- newSTRef n
9 r <- newSTRef n
10− count <- newSTRef 0.0
10+ count <- newSTRef 0
11 untilE $ do
11 untilE $ do
12− modifySTRef count $ (+) 1.0
12+ modifySTRef count $ (+) 1
13 m <- readSTRef r
13 m <- readSTRef r
14− writeSTRef r $ if m % 2.0 == 0.0 then m / 2.0 else 3.0 * m + 1.0
14+ writeSTRef r $ if m `mod` 2 == 0 then m / 2 else 3 * m + 1
15− return $ m == 1.0
15+ return $ m == 1
16 readSTRef count))
16 readSTRef count))
17
17
18−main = Debug.Trace.print $ collatz 1000.0
18+main = Control.Monad.Eff.Console.print $ collatz 1000
examples/passing/Comparisons.purs+3−3
@@ -2,8 +2,8 @@ module Main where
2
2
3import Prelude
3import Prelude
4import Control.Monad.Eff
4import Control.Monad.Eff
5−import Debug.Trace
5+import Control.Monad.Eff.Console
6−import Assert
6+import Test.Assert
7
7
8main = do
8main = do
9 assert (1.0 < 2.0)
9 assert (1.0 < 2.0)
@@ -12,4 +12,4 @@ main = do
12 assert ("a" < "b")
12 assert ("a" < "b")
13 assert ("a" == "a")
13 assert ("a" == "a")
14 assert ("z" > "a")
14 assert ("z" > "a")
15− trace "Done!"
15+ log "Done!"
examples/passing/Conditional.purs+1−1
@@ -6,4 +6,4 @@ fns = \f -> if f true then f else \x -> x
6
6
7not = \x -> if x then false else true
7not = \x -> if x then false else true
8
8
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Console.purs+2−2
@@ -2,7 +2,7 @@ module Main where
2
2
3import Prelude
3import Prelude
4import Control.Monad.Eff
4import Control.Monad.Eff
5−import Debug.Trace
5+import Control.Monad.Eff.Console
6
6
7replicateM_ :: forall m a. (Monad m) => Number -> m a -> m {}
7replicateM_ :: forall m a. (Monad m) => Number -> m a -> m {}
8replicateM_ 0.0 _ = return {}
8replicateM_ 0.0 _ = return {}
@@ -10,4 +10,4 @@ replicateM_ n act = do
10 act
10 act
11 replicateM_ (n - 1.0) act
11 replicateM_ (n - 1.0) act
12
12
13−main = replicateM_ 10.0 (trace "Hello World!")
13+main = replicateM_ 10.0 (log "Hello World!")
examples/passing/DataAndType.purs+1−1
@@ -6,4 +6,4 @@ data A = A B
6
6
7type B = A
7type B = A
8
8
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/DeepArrayBinder.purs+5−4
@@ -2,7 +2,7 @@ module Main where
2
2
3import Prelude
3import Prelude
4import Control.Monad.Eff
4import Control.Monad.Eff
5−import Assert
5+import Test.Assert
6
6
7data List a = Cons a (List a) | Nil
7data List a = Cons a (List a) | Nil
8
8
@@ -10,6 +10,7 @@ match2 :: List Number -> Number
10match2 (Cons x (Cons y xs)) = x * y + match2 xs
10match2 (Cons x (Cons y xs)) = x * y + match2 xs
11match2 _ = 0.0
11match2 _ = 0.0
12
12
13+main = do
13−main = case match2 (Cons 1.0 (Cons 2.0 (Cons 3.0 (Cons 4.0 (Cons 5.0 (Cons 6.0 (Cons 7.0 (Cons 8.0 (Cons 9.0 Nil))))))))) of
14+ let result = match2 (Cons 1.0 (Cons 2.0 (Cons 3.0 (Cons 4.0 (Cons 5.0 (Cons 6.0 (Cons 7.0 (Cons 8.0 (Cons 9.0 Nil)))))))))
14− 100.0 -> Debug.Trace.trace "Done"
15− _ -> error "Incorrect result!"
15+ assert' "Incorrect result!" (result == 100.0)
16+ Control.Monad.Eff.Console.log "Done"
examples/passing/DeepCase.purs+1−1
@@ -1,7 +1,7 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
5import Control.Monad.Eff
5import Control.Monad.Eff
6import Control.Monad.ST
6import Control.Monad.ST
7
7
examples/passing/Do.purs+7−7
@@ -5,19 +5,19 @@ import Prelude
5data Maybe a = Nothing | Just a
5data Maybe a = Nothing | Just a
6
6
7instance functorMaybe :: Functor Maybe where
7instance functorMaybe :: Functor Maybe where
8− (<$>) f Nothing = Nothing
8+ map f Nothing = Nothing
9− (<$>) f (Just x) = Just (f x)
9+ map f (Just x) = Just (f x)
10
10
11instance applyMaybe :: Apply Maybe where
11instance applyMaybe :: Apply Maybe where
12− (<*>) (Just f) (Just x) = Just (f x)
12+ apply (Just f) (Just x) = Just (f x)
13− (<*>) _ _ = Nothing
13+ apply _ _ = Nothing
14
14
15instance applicativeMaybe :: Applicative Maybe where
15instance applicativeMaybe :: Applicative Maybe where
16 pure = Just
16 pure = Just
17
17
18instance bindMaybe :: Bind Maybe where
18instance bindMaybe :: Bind Maybe where
19− (>>=) Nothing _ = Nothing
19+ bind Nothing _ = Nothing
20− (>>=) (Just a) f = f a
20+ bind (Just a) f = f a
21
21
22instance monadMaybe :: Prelude.Monad Maybe
22instance monadMaybe :: Prelude.Monad Maybe
23
23
@@ -64,4 +64,4 @@ test10 _ = do
64 g x = f x / 2.0
64 g x = f x / 2.0
65 Just (f 10.0)
65 Just (f 10.0)
66
66
67−main = Debug.Trace.trace "Done"
67+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Dollar.purs+1−1
@@ -13,4 +13,4 @@ test1 x = id $ id $ id $ id $ x
13
13
14test2 x = id id $ id x
14test2 x = id id $ id x
15
15
16−main = Debug.Trace.trace "Done"
16+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Eff.purs+5−5
@@ -3,11 +3,11 @@ module Main where
3import Prelude
3import Prelude
4import Control.Monad.Eff
4import Control.Monad.Eff
5import Control.Monad.ST
5import Control.Monad.ST
6−import Debug.Trace
6+import Control.Monad.Eff.Console
7
7
8test1 = do
8test1 = do
9− trace "Line 1"
9+ log "Line 1"
10− trace "Line 2"
10+ log "Line 2"
11
11
12test2 = runPure (runST (do
12test2 = runPure (runST (do
13 ref <- newSTRef 0.0
13 ref <- newSTRef 0.0
@@ -21,5 +21,5 @@ test3 = pureST (do
21
21
22main = do
22main = do
23 test1
23 test1
24− Debug.Trace.print test2
24+ Control.Monad.Eff.Console.print test2
25− Debug.Trace.print test3
25+ Control.Monad.Eff.Console.print test3
examples/passing/EmptyDataDecls.purs+4−4
@@ -1,7 +1,7 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Assert
4+import Test.Assert
5
5
6data Z
6data Z
7data S n
7data S n
@@ -12,8 +12,8 @@ nil :: forall a. ArrayBox Z a
12nil = ArrayBox []
12nil = ArrayBox []
13
13
14cons' :: forall a n. a -> ArrayBox n a -> ArrayBox (S n) a
14cons' :: forall a n. a -> ArrayBox n a -> ArrayBox (S n) a
15−cons' x (ArrayBox xs) = ArrayBox $ concat [x] xs
15+cons' x (ArrayBox xs) = ArrayBox $ append [x] xs
16
16
17main = case cons' 1 $ cons' 2 $ cons' 3 nil of
17main = case cons' 1 $ cons' 2 $ cons' 3 nil of
18− ArrayBox [1, 2, 3] -> Debug.Trace.trace "Done"
18+ ArrayBox [1, 2, 3] -> Control.Monad.Eff.Console.log "Done"
19− _ -> error "Failed"
19+ _ -> assert' "Failed" false
examples/passing/EmptyRow.purs+1−1
@@ -7,4 +7,4 @@ data Foo r = Foo { | r }
7test :: Foo ()
7test :: Foo ()
8test = Foo {}
8test = Foo {}
9
9
10−main = Debug.Trace.trace "Done"
10+main = Control.Monad.Eff.Console.log "Done"
examples/passing/EmptyTypeClass.purs+1−1
@@ -9,4 +9,4 @@ head [x] = x
9
9
10instance allowPartials :: Partial
10instance allowPartials :: Partial
11
11
12−main = Debug.Trace.trace $ head ["Done"]
12+main = Control.Monad.Eff.Console.log $ head ["Done"]
examples/passing/EqOrd.purs+2−3
@@ -10,7 +10,6 @@ instance ordPair :: (Ord a, Ord b) => Ord (Pair a b) where
10 r -> r
10 r -> r
11
11
12instance eqPair :: (Eq a, Eq b) => Eq (Pair a b) where
12instance eqPair :: (Eq a, Eq b) => Eq (Pair a b) where
13− (==) (Pair a1 b1) (Pair a2 b2) = a1 == a2 && b1 == b2
13+ eq (Pair a1 b1) (Pair a2 b2) = a1 == a2 && b1 == b2
14− (/=) (Pair a1 b1) (Pair a2 b2) = a1 /= a2 || b1 /= b2
15
14
16−main = Debug.Trace.print $ Pair 1.0 2.0 == Pair 1.0 2.0
15+main = Control.Monad.Eff.Console.print $ Pair 1.0 2.0 == Pair 1.0 2.0
examples/passing/ExtendedInfixOperators.purs+1−1
@@ -11,4 +11,4 @@ null _ = false
11test = [1.0, 2.0, 3.0] `comparing null` [4.0, 5.0, 6.0]
11test = [1.0, 2.0, 3.0] `comparing null` [4.0, 5.0, 6.0]
12
12
13main = do
13main = do
14− Debug.Trace.print test
14+ Control.Monad.Eff.Console.print test
examples/passing/Fib.purs+1−1
@@ -12,4 +12,4 @@ main = runST (do
12 n2' <- readSTRef n2
12 n2' <- readSTRef n2
13 writeSTRef n2 $ n1' + n2'
13 writeSTRef n2 $ n1' + n2'
14 writeSTRef n1 n2'
14 writeSTRef n1 n2'
15− Debug.Trace.print n2')
15+ Control.Monad.Eff.Console.print n2')
examples/passing/FinalTagless.purs+2−2
@@ -1,6 +1,6 @@
1module Main where
1module Main where
2
2
3−import Prelude
3+import Prelude hiding (add)
4
4
5class E e where
5class E e where
6 num :: Number -> e Number
6 num :: Number -> e Number
@@ -19,4 +19,4 @@ runId (Id a) = a
19three :: Expr Number
19three :: Expr Number
20three = add (num 1.0) (num 2.0)
20three = add (num 1.0) (num 2.0)
21
21
22−main = Debug.Trace.print $ runId three
22+main = Control.Monad.Eff.Console.print $ runId three
examples/passing/FunctionScope.purs+3−4
@@ -1,13 +1,12 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Assert
4+import Test.Assert
5
5
6mkValue :: Number -> Number
6mkValue :: Number -> Number
7mkValue id = id
7mkValue id = id
8
8
9main = do
9main = do
10 let value = mkValue 1.0
10 let value = mkValue 1.0
11− if value == 1.0
11+ assert $ value == 1.0
12− then Debug.Trace.trace "Done"
12+ Control.Monad.Eff.Console.log "Done"
13− else error "Not done"
examples/passing/Functions.purs+1−1
@@ -12,4 +12,4 @@ test4 = \(%%) -> 1.0 %% 2.0
12
12
13test5 = \(+++) (***) -> 1.0 +++ 2.0 *** 3.0
13test5 = \(+++) (***) -> 1.0 +++ 2.0 *** 3.0
14
14
15−main = Debug.Trace.trace "Done"
15+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Functions2.purs+3−4
@@ -1,13 +1,12 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Assert
4+import Test.Assert
5
5
6test :: forall a b. a -> b -> a
6test :: forall a b. a -> b -> a
7test = \const _ -> const
7test = \const _ -> const
8
8
9main = do
9main = do
10 let value = test "Done" {}
10 let value = test "Done" {}
11− if value == "Done"
11+ assert' "Not done" $ value == "Done"
12− then Debug.Trace.trace "Done"
12+ Control.Monad.Eff.Console.log "Done"
13− else error "Not done"
examples/passing/Guards.purs+2−2
@@ -3,7 +3,7 @@ module Main where
3import Prelude
3import Prelude
4
4
5collatz = \x -> case x of
5collatz = \x -> case x of
6− y | y % 2.0 == 0.0 -> y / 2.0
6+ y | y `mod` 2.0 == 0.0 -> y / 2.0
7 y -> y * 3.0 + 1.0
7 y -> y * 3.0 + 1.0
8
8
9-- Guards have access to current scope
9-- Guards have access to current scope
@@ -26,4 +26,4 @@ testIndentation x y | x > 0.0
26 | otherwise
26 | otherwise
27 = y - x
27 = y - x
28
28
29−main = Debug.Trace.trace $ min "Done" "ZZZZ"
29+main = Control.Monad.Eff.Console.log $ min "Done" "ZZZZ"
examples/passing/HoistError.purs+3−3
@@ -2,11 +2,11 @@ module Main where
2
2
3import Prelude
3import Prelude
4import Control.Monad.Eff
4import Control.Monad.Eff
5−import Debug.Trace
5+import Control.Monad.Eff.Console
6−import Assert
6+import Test.Assert
7
7
8main = do
8main = do
9 let x = 0.0
9 let x = 0.0
10 assert $ x == 0.0
10 assert $ x == 0.0
11 let x = 1.0 + 1.0
11 let x = 1.0 + 1.0
12− trace "Done"
12+ log "Done"
examples/passing/IfThenElseMaybe.purs+1−1
@@ -8,4 +8,4 @@ test1 = if true then Just 10 else Nothing
8
8
9test2 = if true then Nothing else Just 10
9test2 = if true then Nothing else Just 10
10
10
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/ImplicitEmptyImport.purs+3−3
@@ -3,6 +3,6 @@ module Main where
3import Prelude
3import Prelude
4
4
5main = do
5main = do
6− Debug.Trace.trace "Hello"
6+ Control.Monad.Eff.Console.log "Hello"
7− Debug.Trace.trace "Goodbye"
7+ Control.Monad.Eff.Console.log "Goodbye"
8− Debug.Trace.trace "Done"
8+ Control.Monad.Eff.Console.log "Done"
examples/passing/ImportHiding.purs+1−1
@@ -1,6 +1,6 @@
1module Main where
1module Main where
2
2
3−import Debug.Trace
3+import Control.Monad.Eff.Console
4import Prelude hiding (
4import Prelude hiding (
5 show, -- a value
5 show, -- a value
6 Show, -- a type class
6 Show, -- a type class
examples/passing/InferRecFunWithConstrainedArgument.purs+1−1
@@ -5,4 +5,4 @@ import Prelude
5test 100.0 = 100.0
5test 100.0 = 100.0
6test n = test(1.0 + n)
6test n = test(1.0 + n)
7
7
8−main = Debug.Trace.print $ test 0.0
8+main = Control.Monad.Eff.Console.print $ test 0.0
examples/passing/InstanceBeforeClass.purs+1−1
@@ -8,4 +8,4 @@ instance fooNumber :: Foo Number where
8class Foo a where
8class Foo a where
9 foo :: a
9 foo :: a
10
10
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/IntAndChar.purs+2−2
@@ -2,7 +2,7 @@ module Main where
2
2
3import Prelude
3import Prelude
4import Control.Monad.Eff
4import Control.Monad.Eff
5−import Assert
5+import Test.Assert
6
6
7f 1 = 1
7f 1 = 1
8f _ = 0
8f _ = 0
@@ -15,4 +15,4 @@ main = do
15 assert $ f 0 == 0
15 assert $ f 0 == 0
16 assert $ g 'a' == 'a'
16 assert $ g 'a' == 'a'
17 assert $ g 'b' == 'b'
17 assert $ g 'b' == 'b'
18− Debug.Trace.trace "Done"
18+ Control.Monad.Eff.Console.log "Done"
examples/passing/JSReserved.purs+1−1
@@ -9,4 +9,4 @@ public = \return -> return
9
9
10this catch = catch
10this catch = catch
11
11
12−main = Debug.Trace.trace "Done"
12+main = Control.Monad.Eff.Console.log "Done"
examples/passing/KindedType.purs+1−1
@@ -30,4 +30,4 @@ class Clazz (a :: *) where
30instance clazzString :: Clazz String where
30instance clazzString :: Clazz String where
31 def = "test"
31 def = "test"
32
32
33−main = Debug.Trace.trace "Done"
33+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Let.purs+7−7
@@ -44,10 +44,10 @@ test10 _ =
44 in f 10.0
44 in f 10.0
45
45
46main = do
46main = do
47− Debug.Trace.print (test1 1.0)
47+ Control.Monad.Eff.Console.print (test1 1.0)
48− Debug.Trace.print (test2 1.0 2.0)
48+ Control.Monad.Eff.Console.print (test2 1.0 2.0)
49− Debug.Trace.print test3
49+ Control.Monad.Eff.Console.print test3
50− Debug.Trace.print test4
50+ Control.Monad.Eff.Console.print test4
51− Debug.Trace.print test5
51+ Control.Monad.Eff.Console.print test5
52− Debug.Trace.print test7
52+ Control.Monad.Eff.Console.print test7
53− Debug.Trace.print (test8 100.0)
53+ Control.Monad.Eff.Console.print (test8 100.0)
examples/passing/Let2.purs+1−1
@@ -14,4 +14,4 @@ test =
14 x = f 1.0
14 x = f 1.0
15 in not x
15 in not x
16
16
17−main = Debug.Trace.print test
17+main = Control.Monad.Eff.Console.print test
examples/passing/LetInInstance.purs+1−1
@@ -11,4 +11,4 @@ instance fooString :: Foo String where
11 go :: String -> String
11 go :: String -> String
12 go s = s
12 go s = s
13
13
14−main = Debug.Trace.trace "Done"
14+main = Control.Monad.Eff.Console.log "Done"
examples/passing/LiberalTypeSynonyms.purs+1−1
@@ -18,4 +18,4 @@ f :: (forall r. F r) -> String
18f g = case g { x: "Hello" } of
18f g = case g { x: "Hello" } of
19 { x = x } -> x
19 { x = x } -> x
20
20
21−main = Debug.Trace.trace "Done"
21+main = Control.Monad.Eff.Console.log "Done"
examples/passing/MPTCs.purs+1−1
@@ -17,4 +17,4 @@ instance coerceRefl :: Coerce a a where
17instance coerceShow :: (Prelude.Show a) => Coerce a String where
17instance coerceShow :: (Prelude.Show a) => Coerce a String where
18 coerce = show
18 coerce = show
19
19
20−main = Debug.Trace.trace "Done"
20+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Match.purs+1−1
@@ -6,4 +6,4 @@ data Foo a = Foo
6
6
7foo = \f -> case f of Foo -> "foo"
7foo = \f -> case f of Foo -> "foo"
8
8
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/ModuleExport.pursnew file+9
@@ -0,0 +1,9 @@
1+module A (module Prelude) where
2+ import Prelude
3+
4+module Main where
5+ import Control.Monad.Eff.Console
6+ import A
7+
8+ main = do
9+ print (show 1.0)
examples/passing/ModuleExportDupes.pursnew file+19
@@ -0,0 +1,19 @@
1+module A (module Prelude) where
2+ import Prelude
3+
4+module B (module Prelude) where
5+ import Prelude
6+
7+module C (module Prelude, module A) where
8+ import Prelude
9+ import A
10+
11+module Main where
12+ import Control.Monad.Eff.Console
13+ import A
14+ import B
15+ import C
16+ import Prelude
17+
18+ main = do
19+ print (show 1.0)
examples/passing/ModuleExportExcluded.pursnew file+14
@@ -0,0 +1,14 @@
1+module A (module Prelude, foo) where
2+ import Prelude
3+
4+ foo :: Number -> Number
5+ foo _ = 0.0
6+
7+module Main where
8+ import Control.Monad.Eff.Console
9+ import A (foo)
10+
11+ otherwise = false
12+
13+ main = do
14+ print "1.0"
examples/passing/ModuleExportHiding.pursnew file+11
@@ -0,0 +1,11 @@
1+module A (module Prelude) where
2+ import Prelude
3+
4+module Main where
5+ import Control.Monad.Eff.Console
6+ import A hiding (module Prelude)
7+
8+ otherwise = false
9+
10+ main = do
11+ print "1.0"
examples/passing/ModuleExportQualified.pursnew file+9
@@ -0,0 +1,9 @@
1+module A (module Prelude) where
2+ import Prelude
3+
4+module Main where
5+ import Control.Monad.Eff.Console
6+ import qualified A as B
7+
8+ main = do
9+ print (B.show 1.0)
examples/passing/ModuleExportSelf.pursnew file+14
@@ -0,0 +1,14 @@
1+module A (module A, module Prelude) where
2+ import Prelude
3+
4+ type Foo = Boolean
5+
6+module Main where
7+ import Control.Monad.Eff.Console
8+ import A
9+
10+ bar :: Foo
11+ bar = true
12+
13+ main = do
14+ print (show bar)
examples/passing/Monad.purs+1−1
@@ -29,4 +29,4 @@ test1 = test id
29
29
30test2 = test maybe
30test2 = test maybe
31
31
32−main = Debug.Trace.trace "Done"
32+main = Control.Monad.Eff.Console.log "Done"
examples/passing/MonadState.purs+4−4
@@ -13,16 +13,16 @@ data State s a = State (s -> Tuple s a)
13runState s (State f) = f s
13runState s (State f) = f s
14
14
15instance functorState :: Functor (State s) where
15instance functorState :: Functor (State s) where
16− (<$>) = liftM1
16+ map = liftM1
17
17
18instance applyState :: Apply (State s) where
18instance applyState :: Apply (State s) where
19− (<*>) = ap
19+ apply = ap
20
20
21instance applicativeState :: Applicative (State s) where
21instance applicativeState :: Applicative (State s) where
22 pure a = State $ \s -> Tuple s a
22 pure a = State $ \s -> Tuple s a
23
23
24instance bindState :: Bind (State s) where
24instance bindState :: Bind (State s) where
25− (>>=) f g = State $ \s -> case runState s f of
25+ bind f g = State $ \s -> case runState s f of
26 Tuple s1 a -> runState s1 (g a)
26 Tuple s1 a -> runState s1 (g a)
27
27
28instance monadState :: Monad (State s)
28instance monadState :: Monad (State s)
@@ -44,5 +44,5 @@ test = runState "" $ do
44
44
45main = do
45main = do
46 let t1 = test
46 let t1 = test
47− Debug.Trace.trace "Done"
47+ Control.Monad.Eff.Console.log "Done"
48
48
examples/passing/MultiArgFunctions.purs+13−13
@@ -3,7 +3,7 @@ module Main where
3import Prelude
3import Prelude
4import Data.Function
4import Data.Function
5import Control.Monad.Eff
5import Control.Monad.Eff
6−import Debug.Trace
6+import Control.Monad.Eff.Console
7
7
8f = mkFn2 $ \a b -> runFn2 g a b + runFn2 g b a
8f = mkFn2 $ \a b -> runFn2 g a b + runFn2 g b a
9
9
@@ -12,16 +12,16 @@ g = mkFn2 $ \a b -> case {} of
12 _ -> runFn2 f (a - 0.0) (b - 0.0)
12 _ -> runFn2 f (a - 0.0) (b - 0.0)
13
13
14main = do
14main = do
15− runFn0 (mkFn0 $ \_ -> trace $ show 0.0)
15+ runFn0 (mkFn0 $ \_ -> log $ show 0.0)
16− runFn1 (mkFn1 $ \a -> trace $ show a) 0.0
16+ runFn1 (mkFn1 $ \a -> log $ show a) 0.0
17− runFn2 (mkFn2 $ \a b -> trace $ show [a, b]) 0.0 0.0
17+ runFn2 (mkFn2 $ \a b -> log $ show [a, b]) 0.0 0.0
18− runFn3 (mkFn3 $ \a b c -> trace $ show [a, b, c]) 0.0 0.0 0.0
18+ runFn3 (mkFn3 $ \a b c -> log $ show [a, b, c]) 0.0 0.0 0.0
19− runFn4 (mkFn4 $ \a b c d -> trace $ show [a, b, c, d]) 0.0 0.0 0.0 0.0
19+ runFn4 (mkFn4 $ \a b c d -> log $ show [a, b, c, d]) 0.0 0.0 0.0 0.0
20− runFn5 (mkFn5 $ \a b c d e -> trace $ show [a, b, c, d, e]) 0.0 0.0 0.0 0.0 0.0
20+ runFn5 (mkFn5 $ \a b c d e -> log $ show [a, b, c, d, e]) 0.0 0.0 0.0 0.0 0.0
21− runFn6 (mkFn6 $ \a b c d e f -> trace $ show [a, b, c, d, e, f]) 0.0 0.0 0.0 0.0 0.0 0.0
21+ runFn6 (mkFn6 $ \a b c d e f -> log $ show [a, b, c, d, e, f]) 0.0 0.0 0.0 0.0 0.0 0.0
22− runFn7 (mkFn7 $ \a b c d e f g -> trace $ show [a, b, c, d, e, f, g]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0
22+ runFn7 (mkFn7 $ \a b c d e f g -> log $ show [a, b, c, d, e, f, g]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0
23− runFn8 (mkFn8 $ \a b c d e f g h -> trace $ show [a, b, c, d, e, f, g, h]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
23+ runFn8 (mkFn8 $ \a b c d e f g h -> log $ show [a, b, c, d, e, f, g, h]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
24− runFn9 (mkFn9 $ \a b c d e f g h i -> trace $ show [a, b, c, d, e, f, g, h, i]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
24+ runFn9 (mkFn9 $ \a b c d e f g h i -> log $ show [a, b, c, d, e, f, g, h, i]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
25− runFn10 (mkFn10 $ \a b c d e f g h i j-> trace $ show [a, b, c, d, e, f, g, h, i, j]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
25+ runFn10 (mkFn10 $ \a b c d e f g h i j-> log $ show [a, b, c, d, e, f, g, h, i, j]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
26 print $ runFn2 g 0.0 0.0
26 print $ runFn2 g 0.0 0.0
27− trace "Done!"
27+ log "Done!"
examples/passing/MutRec.purs+1−1
@@ -16,4 +16,4 @@ evenToNumber (Even n) = oddToNumber n + 0.0
16
16
17oddToNumber (Odd n) = evenToNumber n + 0.0
17oddToNumber (Odd n) = evenToNumber n + 0.0
18
18
19−main = Debug.Trace.trace "Done"
19+main = Control.Monad.Eff.Console.log "Done"
examples/passing/MutRec2.purs+1−1
@@ -16,4 +16,4 @@ g b = case b of B a -> f a
16showN :: A -> S
16showN :: A -> S
17showN a = f a
17showN a = f a
18
18
19−main = Debug.Trace.trace "Done"
19+main = Control.Monad.Eff.Console.log "Done"
examples/passing/MutRec3.purs+1−1
@@ -16,4 +16,4 @@ g b = case b of B a -> f a
16showN :: A -> S
16showN :: A -> S
17showN a = f a
17showN a = f a
18
18
19−main = Debug.Trace.trace "Done"
19+main = Control.Monad.Eff.Console.log "Done"
examples/passing/NamedPatterns.purs+1−1
@@ -6,4 +6,4 @@ foo = \x -> case x of
6 y@{ foo = "Foo" } -> y
6 y@{ foo = "Foo" } -> y
7 y -> y
7 y -> y
8
8
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/NegativeBinder.purs+1−1
@@ -6,4 +6,4 @@ test :: Number -> Boolean
6test -1.0 = false
6test -1.0 = false
7test _ = true
7test _ = true
8
8
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Nested.purs+1−1
@@ -6,4 +6,4 @@ data Extend r a = Extend { prev :: r a, next :: a }
6
6
7data Matrix r a = Square (r (r a)) | Bigger (Matrix (Extend r) a)
7data Matrix r a = Square (r (r a)) | Bigger (Matrix (Extend r) a)
8
8
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/NestedTypeSynonyms.purs+1−1
@@ -8,4 +8,4 @@ type Y = X -> X
8fn :: Y
8fn :: Y
9fn a = a
9fn a = a
10
10
11−main = Debug.Trace.print (fn "Done")
11+main = Control.Monad.Eff.Console.print (fn "Done")
examples/passing/NestedWhere.purs+1−1
@@ -9,4 +9,4 @@ f x = g x
9 go x = go1 (x - 1.0)
9 go x = go1 (x - 1.0)
10 go1 x = go x
10 go1 x = go x
11
11
12−main = Debug.Trace.trace "Done"
12+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Newtype.purs+3−3
@@ -1,8 +1,8 @@
1module Main where
1module Main where
2
2
3−import Prelude
3+import Prelude hiding (apply)
4import Control.Monad.Eff
4import Control.Monad.Eff
5−import Debug.Trace
5+import Control.Monad.Eff.Console
6
6
7newtype Thing = Thing String
7newtype Thing = Thing String
8
8
@@ -20,4 +20,4 @@ main = do
20 print $ Thing "hello"
20 print $ Thing "hello"
21 print $ Box 42.0
21 print $ Box 42.0
22 print $ apply Box 9000.0
22 print $ apply Box 9000.0
23− trace "Done"
23+ log "Done"
examples/passing/NewtypeEff.purs+9−9
@@ -1,29 +1,29 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
5import Control.Monad.Eff
5import Control.Monad.Eff
6
6
7−newtype T a = T (Eff (trace :: Trace) a)
7+newtype T a = T (Eff (console :: CONSOLE) a)
8
8
9−runT :: forall a. T a -> Eff (trace :: Trace) a
9+runT :: forall a. T a -> Eff (console :: CONSOLE) a
10runT (T t) = t
10runT (T t) = t
11
11
12instance functorT :: Functor T where
12instance functorT :: Functor T where
13− (<$>) f (T t) = T (f <$> t)
13+ map f (T t) = T (f <$> t)
14
14
15instance applyT :: Apply T where
15instance applyT :: Apply T where
16− (<*>) (T f) (T x) = T (f <*> x)
16+ apply (T f) (T x) = T (f <*> x)
17
17
18instance applicativeT :: Applicative T where
18instance applicativeT :: Applicative T where
19 pure t = T (pure t)
19 pure t = T (pure t)
20
20
21instance bindT :: Bind T where
21instance bindT :: Bind T where
22− (>>=) (T t) f = T (t >>= \x -> runT (f x))
22+ bind (T t) f = T (t >>= \x -> runT (f x))
23
23
24instance monadT :: Monad T
24instance monadT :: Monad T
25
25
26main = runT do
26main = runT do
27− T $ trace "Done"
27+ T $ log "Done"
28− T $ trace "Done"
28+ T $ log "Done"
29− T $ trace "Done"
29+ T $ log "Done"
examples/passing/NewtypeWithRecordUpdate.purs+2−2
@@ -3,7 +3,7 @@
3module Main where
3module Main where
4
4
5import Prelude
5import Prelude
6−import Debug.Trace
6+import Control.Monad.Eff.Console
7
7
8newtype NewType a = NewType (Object a)
8newtype NewType a = NewType (Object a)
9
9
@@ -13,4 +13,4 @@ rec1 = { a: 0.0, b: 0.0, c: 0.0 }
13rec2 :: NewType (a :: Number, b :: Number, c :: Number)
13rec2 :: NewType (a :: Number, b :: Number, c :: Number)
14rec2 = NewType (rec1 { a = 1.0 })
14rec2 = NewType (rec1 { a = 1.0 })
15
15
16−main = trace "Done"
16+main = log "Done"
examples/passing/ObjectGetter.purs+4−4
@@ -7,7 +7,7 @@ getX = _.x
7point = { x: 1.0, y: 0.0 }
7point = { x: 1.0, y: 0.0 }
8
8
9main = do
9main = do
10− Debug.Trace.print $ getX point
10+ Control.Monad.Eff.Console.print $ getX point
11− Debug.Trace.trace $ _." 123 string Prop Name " { " 123 string Prop Name ": "OK" }
11+ Control.Monad.Eff.Console.log $ _." 123 string Prop Name " { " 123 string Prop Name ": "OK" }
12− Debug.Trace.trace $ (_.x >>> _.y) { x: { y: "Nested" } }
12+ Control.Monad.Eff.Console.log $ (_.x >>> _.y) { x: { y: "Nested" } }
13− Debug.Trace.trace $ _.value { value: "Done!" }
13+ Control.Monad.Eff.Console.log $ _.value { value: "Done!" }
examples/passing/ObjectSynonym.purs+1−1
@@ -12,4 +12,4 @@ type Outer = { inner :: Inner }
12outer :: Outer
12outer :: Outer
13outer = { inner: inner }
13outer = { inner: inner }
14
14
15−main = Debug.Trace.trace "Done"
15+main = Control.Monad.Eff.Console.log "Done"
examples/passing/ObjectUpdate.purs+1−1
@@ -17,4 +17,4 @@ polyUpdate = \o -> o { foo = "Foo" }
17
17
18inferPolyUpdate = \o -> o { foo = "Foo" }
18inferPolyUpdate = \o -> o { foo = "Foo" }
19
19
20−main = Debug.Trace.trace ((update1 {foo: ""}).foo)
20+main = Control.Monad.Eff.Console.log ((update1 {foo: ""}).foo)
examples/passing/ObjectUpdate2.purs+1−1
@@ -14,4 +14,4 @@ test = blah x
14 { baz = "blah"
14 { baz = "blah"
15 }
15 }
16
16
17−main = Debug.Trace.trace "Done"
17+main = Control.Monad.Eff.Console.log "Done"
examples/passing/ObjectUpdater.purs+2−2
@@ -2,8 +2,8 @@ module Main where
2
2
3import Prelude
3import Prelude
4import Control.Monad.Eff
4import Control.Monad.Eff
5−import Debug.Trace
5+import Control.Monad.Eff.Console
6−import Assert
6+import Test.Assert
7
7
8getValue :: forall e. Eff (| e) Boolean
8getValue :: forall e. Eff (| e) Boolean
9getValue = return true
9getValue = return true
examples/passing/ObjectWildcards.purs+3−3
@@ -2,8 +2,8 @@ module Main where
2
2
3import Prelude
3import Prelude
4import Control.Monad.Eff
4import Control.Monad.Eff
5−import Debug.Trace
5+import Control.Monad.Eff.Console
6−import Assert
6+import Test.Assert
7
7
8mkRecord = { foo: _, bar: _, baz: "baz" }
8mkRecord = { foo: _, bar: _, baz: "baz" }
9
9
@@ -17,4 +17,4 @@ main = do
17 point <- { x: _, y: x } <$> return 2.0
17 point <- { x: _, y: x } <$> return 2.0
18 assert $ point.x == 2.0
18 assert $ point.x == 2.0
19 assert $ point.y == 1.0
19 assert $ point.y == 1.0
20− trace (mkRecord 1.0 "Done!").bar
20+ log (mkRecord 1.0 "Done!").bar
examples/passing/Objects.purs+2−2
@@ -1,6 +1,6 @@
1module Main where
1module Main where
2
2
3−import Prelude
3+import Prelude hiding (append)
4
4
5test = \x -> x.foo + x.bar + 1.0
5test = \x -> x.foo + x.bar + 1.0
6
6
@@ -32,4 +32,4 @@ test6 = case { "***": 1.0 } of
32
32
33test7 {a: snoog , b : blah } = blah
33test7 {a: snoog , b : blah } = blah
34
34
35−main = Debug.Trace.trace "Done"
35+main = Control.Monad.Eff.Console.log "Done"
examples/passing/OneConstructor.purs+1−1
@@ -6,4 +6,4 @@ data One a = One a
6
6
7one' (One a) = a
7one' (One a) = a
8
8
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/OperatorAssociativity.purs+3−3
@@ -2,8 +2,8 @@ module Main where
2
2
3import Prelude
3import Prelude
4import Control.Monad.Eff
4import Control.Monad.Eff
5−import Debug.Trace
5+import Control.Monad.Eff.Console
6−import Assert
6+import Test.Assert
7
7
8bug :: Number -> Number -> Number
8bug :: Number -> Number -> Number
9bug a b = 0.0 - (a - b)
9bug a b = 0.0 - (a - b)
@@ -22,4 +22,4 @@ main = do
22 assert (1.0 + 10.0 - 5.0 == 6.0)
22 assert (1.0 + 10.0 - 5.0 == 6.0)
23 assert (1.0 + 10.0 * 5.0 == 51.0)
23 assert (1.0 + 10.0 * 5.0 == 51.0)
24 assert (10.0 * 5.0 - 1.0 == 49.0)
24 assert (10.0 * 5.0 - 1.0 == 49.0)
25− trace "Success!"
25+ log "Success!"
examples/passing/OperatorInlining.purs+1−1
@@ -1,7 +1,7 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
5
5
6main = do
6main = do
7
7
examples/passing/OperatorSections.purs+2−2
@@ -1,11 +1,11 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Assert
4+import Test.Assert
5
5
6main = do
6main = do
7 assert $ (/ 2.0) 4.0 == 2.0
7 assert $ (/ 2.0) 4.0 == 2.0
8 assert $ (2.0 /) 4.0 == 0.5
8 assert $ (2.0 /) 4.0 == 0.5
9 assert $ (`const` 1.0) 2.0 == 2.0
9 assert $ (`const` 1.0) 2.0 == 2.0
10 assert $ (1.0 `const`) 2.0 == 1.0
10 assert $ (1.0 `const`) 2.0 == 1.0
11− Debug.Trace.trace "Done!"
11+ Control.Monad.Eff.Console.log "Done!"
examples/passing/Operators.purs+2−2
@@ -2,7 +2,7 @@ module Main where
2
2
3import Prelude
3import Prelude
4import Control.Monad.Eff
4import Control.Monad.Eff
5−import Debug.Trace
5+import Control.Monad.Eff.Console
6
6
7(?!) :: forall a. a -> a -> a
7(?!) :: forall a. a -> a -> a
8(?!) x _ = x
8(?!) x _ = x
@@ -96,4 +96,4 @@ main = do
96 let t18 = test18
96 let t18 = test18
97 let t19 = test19
97 let t19 = test19
98 let t20 = test20
98 let t20 = test20
99− trace "Done"
99+ log "Done"
examples/passing/OptimizerBug.purs+1−1
@@ -6,4 +6,4 @@ x a = 1.0 + y a
6
6
7y a = x a
7y a = x a
8
8
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/PartialFunction.purs+2−2
@@ -1,10 +1,10 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Assert
4+import Test.Assert
5
5
6fn :: Number -> Number
6fn :: Number -> Number
7fn 0.0 = 0.0
7fn 0.0 = 0.0
8fn 1.0 = 2.0
8fn 1.0 = 2.0
9
9
10−main = assertPartial $ \_ -> fn 2.0
10+main = assertThrows $ \_ -> fn 2.0
examples/passing/Patterns.purs+1−1
@@ -19,4 +19,4 @@ isDesc :: Array Number -> Boolean
19isDesc [x, y] | x > y = true
19isDesc [x, y] | x > y = true
20isDesc _ = false
20isDesc _ = false
21
21
22−main = Debug.Trace.trace "Done"
22+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Person.purs+1−1
@@ -8,4 +8,4 @@ showPerson :: Person -> String
8showPerson = \p -> case p of
8showPerson = \p -> case p of
9 Person o -> o.name ++ ", aged " ++ show o.age
9 Person o -> o.name ++ ", aged " ++ show o.age
10
10
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Rank2Data.purs+2−2
@@ -1,6 +1,6 @@
1module Main where
1module Main where
2
2
3−import Prelude
3+import Prelude hiding (add)
4
4
5data Id = Id forall a. a -> a
5data Id = Id forall a. a -> a
6
6
@@ -26,4 +26,4 @@ two = succ zero'
26four = add two two
26four = add two two
27fourNumber = runNat four
27fourNumber = runNat four
28
28
29−main = Debug.Trace.trace "Done'"
29+main = Control.Monad.Eff.Console.log "Done'"
examples/passing/Rank2Object.purs+2−2
@@ -1,11 +1,11 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
5
5
6data Foo = Foo { id :: forall a. a -> a }
6data Foo = Foo { id :: forall a. a -> a }
7
7
8foo :: Foo -> Number
8foo :: Foo -> Number
9foo (Foo { id = f }) = f 0.0
9foo (Foo { id = f }) = f 0.0
10
10
11−main = trace "Done"
11+main = log "Done"
examples/passing/Rank2TypeSynonym.purs+1−1
@@ -13,4 +13,4 @@ bar = foo 3.0
13
13
14main = do
14main = do
15 x <- bar
15 x <- bar
16− Debug.Trace.print x
16+ Control.Monad.Eff.Console.print x
examples/passing/Rank2Types.purs+1−1
@@ -8,4 +8,4 @@ test1 = \f -> f 0.0
8forever :: forall m a b. (forall a b. m a -> (a -> m b) -> m b) -> m a -> m b
8forever :: forall m a b. (forall a b. m a -> (a -> m b) -> m b) -> m a -> m b
9forever = \bind action -> bind action $ \_ -> forever bind action
9forever = \bind action -> bind action $ \_ -> forever bind action
10
10
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/RebindableSyntax.purs+6−6
@@ -9,7 +9,7 @@ example1 = do
9 " for"
9 " for"
10 " Semigroup"
10 " Semigroup"
11 where
11 where
12− (>>=) x f = x <> f unit
12+ bind x f = x <> f unit
13
13
14(*>) :: forall f a b. (Apply f) => f a -> f b -> f b
14(*>) :: forall f a b. (Apply f) => f a -> f b -> f b
15(*>) fa fb = const id <$> fa <*> fb
15(*>) fa fb = const id <$> fa <*> fb
@@ -20,10 +20,10 @@ runConst :: forall a b. Const a b -> a
20runConst (Const a) = a
20runConst (Const a) = a
21
21
22instance functorConst :: Functor (Const a) where
22instance functorConst :: Functor (Const a) where
23− (<$>) _ (Const a) = Const a
23+ map _ (Const a) = Const a
24
24
25instance applyConst :: (Semigroup a) => Apply (Const a) where
25instance applyConst :: (Semigroup a) => Apply (Const a) where
26− (<*>) (Const a1) (Const a2) = Const (a1 <> a2)
26+ apply (Const a1) (Const a2) = Const (a1 <> a2)
27
27
28example2 :: Const String Unit
28example2 :: Const String Unit
29example2 = do
29example2 = do
@@ -32,8 +32,8 @@ example2 = do
32 Const " for"
32 Const " for"
33 Const " Apply"
33 Const " Apply"
34 where
34 where
35− (>>=) x f = x *> f unit
35+ bind x f = x *> f unit
36
36
37main = do
37main = do
38− Debug.Trace.trace example1
38+ Control.Monad.Eff.Console.log example1
39− Debug.Trace.trace $ runConst example2
39+ Control.Monad.Eff.Console.log $ runConst example2
examples/passing/Recursion.purs+1−1
@@ -7,4 +7,4 @@ fib = \n -> case n of
7 1.0 -> 1.0
7 1.0 -> 1.0
8 n -> fib (n - 1.0) + fib (n - 2.0)
8 n -> fib (n - 1.0) + fib (n - 2.0)
9
9
10−main = Debug.Trace.trace "Done"
10+main = Control.Monad.Eff.Console.log "Done"
examples/passing/ReservedWords.purs+1−1
@@ -12,4 +12,4 @@ p = o { type = "p" }
12f :: forall r. { type :: String | r } -> String
12f :: forall r. { type :: String | r } -> String
13f { type = "p" } = "Done"
13f { type = "p" } = "Done"
14
14
15−main = Debug.Trace.trace $ f { type: p.type, foo: "bar" }
15+main = Control.Monad.Eff.Console.log $ f { type: p.type, foo: "bar" }
examples/passing/RowConstructors.purs+1−1
@@ -39,4 +39,4 @@ wildcard { w: w } = { x: w, y: w, z: w, w: w }
39wildcard' :: { | Quux _ } -> Number
39wildcard' :: { | Quux _ } -> Number
40wildcard' { q: q } = q
40wildcard' { q: q } = q
41
41
42−main = Debug.Trace.trace "Done"
42+main = Control.Monad.Eff.Console.log "Done"
examples/passing/RowPolyInstanceContext.purs+1−1
@@ -19,4 +19,4 @@ test2 = state $ \o -> o { foo = o.foo ++ "!" }
19main = do
19main = do
20 let t1 = test1
20 let t1 = test1
21 let t2 = test2
21 let t2 = test2
22− Debug.Trace.trace "Done"
22+ Control.Monad.Eff.Console.log "Done"
examples/passing/RuntimeScopeIssue.purs+1−1
@@ -16,4 +16,4 @@ instance bNumber :: B Number where
16 b 0.0 = false
16 b 0.0 = false
17 b n = a (n - 1.0)
17 b n = a (n - 1.0)
18
18
19−main = Debug.Trace.print $ a 10.0
19+main = Control.Monad.Eff.Console.print $ a 10.0
examples/passing/ScopedTypeVariables.purs+1−1
@@ -33,4 +33,4 @@ test4 = h
33 j x = x
33 j x = x
34
34
35
35
36−main = Debug.Trace.trace "Done"
36+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Sequence.purs+1−1
@@ -12,4 +12,4 @@ instance sequenceList :: Sequence List where
12 sequence Nil = pure Nil
12 sequence Nil = pure Nil
13 sequence (Cons x xs) = Cons <$> x <*> sequence xs
13 sequence (Cons x xs) = Cons <$> x <*> sequence xs
14
14
15−main = sequence $ Cons (Debug.Trace.trace "Done") Nil
15+main = sequence $ Cons (Control.Monad.Eff.Console.log "Done") Nil
examples/passing/SequenceDesugared.purs+4−4
@@ -31,7 +31,7 @@ sequenceList''' = Sequence ((\val -> case val of
31 Cons x xs -> Cons <$> x <*> sequence sequenceList''' xs) :: forall m a. (Monad m) => List (m a) -> m (List a))
31 Cons x xs -> Cons <$> x <*> sequence sequenceList''' xs) :: forall m a. (Monad m) => List (m a) -> m (List a))
32
32
33main = do
33main = do
34− sequence sequenceList $ Cons (Debug.Trace.trace "Done") Nil
34+ sequence sequenceList $ Cons (Control.Monad.Eff.Console.log "Done") Nil
35− sequence sequenceList' $ Cons (Debug.Trace.trace "Done") Nil
35+ sequence sequenceList' $ Cons (Control.Monad.Eff.Console.log "Done") Nil
36− sequence sequenceList'' $ Cons (Debug.Trace.trace "Done") Nil
36+ sequence sequenceList'' $ Cons (Control.Monad.Eff.Console.log "Done") Nil
37− sequence sequenceList''' $ Cons (Debug.Trace.trace "Done") Nil
37+ sequence sequenceList''' $ Cons (Control.Monad.Eff.Console.log "Done") Nil
examples/passing/ShadowedRename.purs+3−3
@@ -2,8 +2,8 @@ module Main where
2
2
3import Prelude
3import Prelude
4import Control.Monad.Eff
4import Control.Monad.Eff
5−import Debug.Trace
5+import Control.Monad.Eff.Console
6−import Assert
6+import Test.Assert
7
7
8foo foo = let foo_1 = \_ -> foo
8foo foo = let foo_1 = \_ -> foo
9 foo_2 = foo_1 unit + 1.0
9 foo_2 = foo_1 unit + 1.0
@@ -11,4 +11,4 @@ foo foo = let foo_1 = \_ -> foo
11
11
12main = do
12main = do
13 assert $ foo 1.0 == 2.0
13 assert $ foo 1.0 == 2.0
14− trace "Done"
14+ log "Done"
examples/passing/ShadowedTCO.purs+2−2
@@ -1,6 +1,6 @@
1module Main where
1module Main where
2
2
3−import Prelude
3+import Prelude hiding (add)
4
4
5runNat f = f 0.0 (\n -> n + 1.0)
5runNat f = f 0.0 (\n -> n + 1.0)
6
6
@@ -15,4 +15,4 @@ two = succ one'
15four = add two two
15four = add two two
16fourNumber = runNat four
16fourNumber = runNat four
17
17
18−main = Debug.Trace.trace $ show fourNumber
18+main = Control.Monad.Eff.Console.log $ show fourNumber
examples/passing/ShadowedTCOLet.purs+1−1
@@ -6,4 +6,4 @@ f x y z =
6 let f 1.0 2.0 3.0 = 1.0
6 let f 1.0 2.0 3.0 = 1.0
7 in f x z y
7 in f x z y
8
8
9−main = Debug.Trace.trace $ show $ f 1.0 3.0 2.0
9+main = Control.Monad.Eff.Console.log $ show $ f 1.0 3.0 2.0
examples/passing/SignedNumericLiterals.purs+1−1
@@ -14,4 +14,4 @@ f x = -x
14
14
15test1 = 2.0 - 1.0
15test1 = 2.0 - 1.0
16
16
17−main = Debug.Trace.trace "Done"
17+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Superclasses1.purs+1−1
@@ -17,4 +17,4 @@ instance clNumber :: Cl Number where
17test :: forall a. (Cl a) => a -> a
17test :: forall a. (Cl a) => a -> a
18test a = su (cl a a)
18test a = su (cl a a)
19
19
20−main = Debug.Trace.print $ test 10.0
20+main = Control.Monad.Eff.Console.print $ test 10.0
examples/passing/Superclasses2.purs+1−2
@@ -1,7 +1,6 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Prelude.Unsafe (unsafeIndex)
5
4
6class Su a where
5class Su a where
7 su :: a -> a
6 su :: a -> a
@@ -21,4 +20,4 @@ instance clNumber :: Cl Number where
21test :: forall a. (Cl a) => a -> Array a
20test :: forall a. (Cl a) => a -> Array a
22test x = su [cl x x]
21test x = su [cl x x]
23
22
24−main = Debug.Trace.print $ test 10.0 `unsafeIndex` 0.0
23+main = Control.Monad.Eff.Console.print $ test 10.0
examples/passing/Superclasses3.purs+7−7
@@ -1,7 +1,7 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
5import Control.Monad.Eff
5import Control.Monad.Eff
6
6
7class (Monad m) <= MonadWriter w m where
7class (Monad m) <= MonadWriter w m where
@@ -16,26 +16,26 @@ test w = do
16 tell w
16 tell w
17 tell w
17 tell w
18
18
19−data MTrace a = MTrace (Eff (trace :: Trace) a)
19+data MTrace a = MTrace (Eff (console :: CONSOLE) a)
20
20
21−runMTrace :: forall a. MTrace a -> Eff (trace :: Trace) a
21+runMTrace :: forall a. MTrace a -> Eff (console :: CONSOLE) a
22runMTrace (MTrace a) = a
22runMTrace (MTrace a) = a
23
23
24instance functorMTrace :: Functor MTrace where
24instance functorMTrace :: Functor MTrace where
25− (<$>) = liftM1
25+ map = liftM1
26
26
27instance applyMTrace :: Apply MTrace where
27instance applyMTrace :: Apply MTrace where
28− (<*>) = ap
28+ apply = ap
29
29
30instance applicativeMTrace :: Applicative MTrace where
30instance applicativeMTrace :: Applicative MTrace where
31 pure = MTrace <<< return
31 pure = MTrace <<< return
32
32
33instance bindMTrace :: Bind MTrace where
33instance bindMTrace :: Bind MTrace where
34− (>>=) m f = MTrace (runMTrace m >>= (runMTrace <<< f))
34+ bind m f = MTrace (runMTrace m >>= (runMTrace <<< f))
35
35
36instance monadMTrace :: Monad MTrace
36instance monadMTrace :: Monad MTrace
37
37
38instance writerMTrace :: MonadWriter String MTrace where
38instance writerMTrace :: MonadWriter String MTrace where
39− tell s = MTrace (trace s)
39+ tell s = MTrace (log s)
40
40
41main = runMTrace $ test "Done"
41main = runMTrace $ test "Done"
examples/passing/TCOCase.purs+1−1
@@ -4,7 +4,7 @@ import Prelude
4
4
5data Data = One | More Data
5data Data = One | More Data
6
6
7−main = Debug.Trace.trace (from (to 10000.0 One))
7+main = Control.Monad.Eff.Console.log (from (to 10000.0 One))
8 where
8 where
9 to 0.0 a = a
9 to 0.0 a = a
10 to n a = to (n - 1.0) (More a)
10 to n a = to (n - 1.0) (More a)
examples/passing/TailCall.purs+1−1
@@ -14,4 +14,4 @@ loop x = loop (x + 1.0)
14notATailCall = \x ->
14notATailCall = \x ->
15 (\notATailCall -> notATailCall x) (\x -> x)
15 (\notATailCall -> notATailCall x) (\x -> x)
16
16
17−main = Debug.Trace.print (test 0.0 (1.0 `C` (2.0 `C` (3.0 `C` N))))
17+main = Control.Monad.Eff.Console.print (test 0.0 (1.0 `C` (2.0 `C` (3.0 `C` N))))
examples/passing/Tick.purs+1−1
@@ -4,4 +4,4 @@ import Prelude
4
4
5test' x = x
5test' x = x
6
6
7−main = Debug.Trace.trace "Done"
7+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TopLevelCase.purs+3−3
@@ -5,8 +5,8 @@ import Prelude
5gcd :: Number -> Number -> Number
5gcd :: Number -> Number -> Number
6gcd 0.0 x = x
6gcd 0.0 x = x
7gcd x 0.0 = x
7gcd x 0.0 = x
8−gcd x y | x > y = gcd (x % y) y
8+gcd x y | x > y = gcd (x `mod` y) y
9−gcd x y = gcd (y % x) x
9+gcd x y = gcd (y `mod` x) x
10
10
11guardsTest [x] | x > 0.0 = []
11guardsTest [x] | x > 0.0 = []
12guardsTest xs = xs
12guardsTest xs = xs
@@ -15,4 +15,4 @@ data A = A
15
15
16parseTest A 0.0 = 0.0
16parseTest A 0.0 = 0.0
17
17
18−main = Debug.Trace.trace "Done"
18+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypeClassMemberOrderChange.purs+1−1
@@ -10,4 +10,4 @@ instance testBoolean :: Test Boolean where
10 val = true
10 val = true
11 fn x y = y
11 fn x y = y
12
12
13−main = Debug.Trace.trace (show (fn true val))
13+main = Control.Monad.Eff.Console.log (show (fn true val))
examples/passing/TypeClasses.purs+8−8
@@ -22,33 +22,33 @@ instance showData :: (Prelude.Show a) => Prelude.Show (Data a) where
22test3 = \_ -> show (Data "testing")
22test3 = \_ -> show (Data "testing")
23
23
24instance functorData :: Functor Data where
24instance functorData :: Functor Data where
25− (<$>) = liftM1
25+ map = liftM1
26
26
27instance applyData :: Apply Data where
27instance applyData :: Apply Data where
28− (<*>) = ap
28+ apply = ap
29
29
30instance applicativeData :: Applicative Data where
30instance applicativeData :: Applicative Data where
31 pure = Data
31 pure = Data
32
32
33instance bindData :: Bind Data where
33instance bindData :: Bind Data where
34− (>>=) (Data a) f = f a
34+ bind (Data a) f = f a
35
35
36instance monadData :: Monad Data
36instance monadData :: Monad Data
37
37
38data Maybe a = Nothing | Just a
38data Maybe a = Nothing | Just a
39
39
40instance functorMaybe :: Functor Maybe where
40instance functorMaybe :: Functor Maybe where
41− (<$>) = liftM1
41+ map = liftM1
42
42
43instance applyMaybe :: Apply Maybe where
43instance applyMaybe :: Apply Maybe where
44− (<*>) = ap
44+ apply = ap
45
45
46instance applicativeMaybe :: Applicative Maybe where
46instance applicativeMaybe :: Applicative Maybe where
47 pure = Just
47 pure = Just
48
48
49instance bindMaybe :: Bind Maybe where
49instance bindMaybe :: Bind Maybe where
50− (>>=) Nothing _ = Nothing
50+ bind Nothing _ = Nothing
51− (>>=) (Just a) f = f a
51+ bind (Just a) f = f a
52
52
53instance monadMaybe :: Monad Maybe
53instance monadMaybe :: Monad Maybe
54
54
@@ -65,5 +65,5 @@ test9 _ = runReader 0.0 $ do
65 n <- ask
65 n <- ask
66 return $ n + 1.0
66 return $ n + 1.0
67
67
68−main = Debug.Trace.trace (test7 "Done")
68+main = Control.Monad.Eff.Console.log (test7 "Done")
69
69
examples/passing/TypeClassesInOrder.purs+1−1
@@ -8,4 +8,4 @@ class Foo a where
8instance fooString :: Foo String where
8instance fooString :: Foo String where
9 foo s = s
9 foo s = s
10
10
11−main = Debug.Trace.trace $ foo "Done"
11+main = Control.Monad.Eff.Console.log $ foo "Done"
examples/passing/TypeClassesWithOverlappingTypeVariables.purs+3−3
@@ -5,7 +5,7 @@ import Prelude
5data Either a b = Left a | Right b
5data Either a b = Left a | Right b
6
6
7instance functorEither :: Prelude.Functor (Either a) where
7instance functorEither :: Prelude.Functor (Either a) where
8− (<$>) _ (Left x) = Left x
8+ map _ (Left x) = Left x
9− (<$>) f (Right y) = Right (f y)
9+ map f (Right y) = Right (f y)
10
10
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypeDecl.purs+1−1
@@ -9,4 +9,4 @@ iterate :: forall a. Number -> (a -> a) -> a -> a
9iterate 0.0 f a = a
9iterate 0.0 f a = a
10iterate n f a = iterate (n - 1.0) f (f a)
10iterate n f a = iterate (n - 1.0) f (f a)
11
11
12−main = Debug.Trace.trace "Done"
12+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypeSynonymInData.purs+1−1
@@ -8,4 +8,4 @@ data Foo a = Foo (A a) | Bar
8
8
9foo (Foo []) = Bar
9foo (Foo []) = Bar
10
10
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypeSynonyms.purs+1−1
@@ -24,4 +24,4 @@ fst =
24test1 :: forall a b c. Lens (Pair (Pair a b) c) a
24test1 :: forall a b c. Lens (Pair (Pair a b) c) a
25test1 = composeLenses fst fst
25test1 = composeLenses fst fst
26
26
27−main = Debug.Trace.trace "Done"
27+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypeWildcards.purs+1−1
@@ -12,4 +12,4 @@ test f a = go (f a) a
12 go a1 a2 | a1 == a2 = a1
12 go a1 a2 | a1 == a2 = a1
13 go a1 _ = go (f a1) a1
13 go a1 _ = go (f a1) a1
14
14
15−main = Debug.Trace.trace "Done"
15+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypeWildcardsRecordExtension.purs+1−1
@@ -5,4 +5,4 @@ import Prelude
5foo :: forall a. {b :: Number | a} -> {b :: Number | _}
5foo :: forall a. {b :: Number | a} -> {b :: Number | _}
6foo f = f
6foo f = f
7
7
8−main = Debug.Trace.trace "Done"
8+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypedWhere.purs+1−1
@@ -14,4 +14,4 @@ lefts = go N
14 go ls (C (L a) rest) = go (C a ls) rest
14 go ls (C (L a) rest) = go (C a ls) rest
15 go ls (C _ rest) = go ls rest
15 go ls (C _ rest) = go ls rest
16
16
17−main = Debug.Trace.trace "Done"
17+main = Control.Monad.Eff.Console.log "Done"
examples/passing/UnderscoreIdent.purs+1−1
@@ -8,4 +8,4 @@ type Type_name = Data_type
8
8
9done (Con_2 s) = s
9done (Con_2 s) = s
10
10
11−main = Debug.Trace.trace (done (Con_2 "Done"))
11+main = Control.Monad.Eff.Console.log (done (Con_2 "Done"))
examples/passing/Unit.purs+1−1
@@ -1,6 +1,6 @@
1module Main where
1module Main where
2
2
3import Prelude
3import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
5
5
6main = print (const unit $ "Hello world")
6main = print (const unit $ "Hello world")
examples/passing/UnknownInTypeClassLookup.purs+1−1
@@ -11,4 +11,4 @@ test _ _ = "Done"
11
11
12runTest a = test a a
12runTest a = test a a
13
13
14−main = Debug.Trace.trace $ runTest 0.0
14+main = Control.Monad.Eff.Console.log $ runTest 0.0
examples/passing/Where.purs+7−7
@@ -40,10 +40,10 @@ test7 x = go x
40 go y = go $ (y + x / y) / 2.0
40 go y = go $ (y + x / y) / 2.0
41
41
42main = do
42main = do
43− Debug.Trace.print (test1 1.0)
43+ Control.Monad.Eff.Console.print (test1 1.0)
44− Debug.Trace.print (test2 1.0 2.0)
44+ Control.Monad.Eff.Console.print (test2 1.0 2.0)
45− Debug.Trace.print test3
45+ Control.Monad.Eff.Console.print test3
46− Debug.Trace.print test4
46+ Control.Monad.Eff.Console.print test4
47− Debug.Trace.print test5
47+ Control.Monad.Eff.Console.print test5
48− Debug.Trace.print test6
48+ Control.Monad.Eff.Console.print test6
49− Debug.Trace.print (test7 100.0)
49+ Control.Monad.Eff.Console.print (test7 100.0)
examples/passing/iota.purs+1−1
@@ -6,4 +6,4 @@ k = \x -> \y -> x
6
6
7iota = \x -> x s k
7iota = \x -> x s k
8
8
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/s.purs+1−1
@@ -4,4 +4,4 @@ import Prelude
4
4
5s = \x y z -> x z (y z)
5s = \x y z -> x z (y z)
6
6
7−main = Debug.Trace.trace "Done"
7+main = Control.Monad.Eff.Console.log "Done"
hierarchy/Main.hs+9−5
@@ -13,6 +13,8 @@
13--
13--
14-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
15
15
16+{-# LANGUAGE TupleSections #-}
17+
16module Main where
18module Main where
17
19
18import Control.Monad (unless)
20import Control.Monad (unless)
@@ -24,6 +26,7 @@ import Data.Version (showVersion)
24import Options.Applicative
26import Options.Applicative
25import System.Directory (createDirectoryIfMissing)
27import System.Directory (createDirectoryIfMissing)
26import System.FilePath ((</>))
28import System.FilePath ((</>))
29+import System.FilePath.Glob (glob)
27import System.Exit (exitFailure, exitSuccess)
30import System.Exit (exitFailure, exitSuccess)
28import System.IO (hPutStr, stderr)
31import System.IO (hPutStr, stderr)
29
32
@@ -50,13 +53,14 @@ instance Ord SuperMap where
50runModuleName :: P.ModuleName -> String
53runModuleName :: P.ModuleName -> String
51runModuleName (P.ModuleName pns) = intercalate "_" (P.runProperName `map` pns)
54runModuleName (P.ModuleName pns) = intercalate "_" (P.runProperName `map` pns)
52
55
53−readInput :: FilePath -> IO (Either P.MultipleErrors [P.Module])
56+readInput :: [FilePath] -> IO (Either P.MultipleErrors [P.Module])
54−readInput filename = do
57+readInput paths = do
55− content <- readFile filename
58+ content <- mapM (\path -> (path, ) <$> readFile path) paths
56− return $ map snd <$> P.parseModulesFromFiles id [(filename, content)]
59+ return $ map snd <$> P.parseModulesFromFiles id content
57
60
58compile :: HierarchyOptions -> IO ()
61compile :: HierarchyOptions -> IO ()
59−compile (HierarchyOptions input mOutput) = do
62+compile (HierarchyOptions inputGlob mOutput) = do
63+ input <- glob inputGlob
60 modules <- readInput input
64 modules <- readInput input
61 case modules of
65 case modules of
62 Left errs -> hPutStr stderr (P.prettyPrintMultipleErrors False errs) >> exitFailure
66 Left errs -> hPutStr stderr (P.prettyPrintMultipleErrors False errs) >> exitFailure
license-generator/generate+1−1
@@ -21,7 +21,7 @@ echo_header() {
21
21
22echo_deps_names() {
22echo_deps_names() {
23 cabal-dependency-licenses \
23 cabal-dependency-licenses \
24− | grep '^- ' | sed 's/^..//' | sort -h
24+ | grep '^- ' | sed 's/^..//' | gsort -h
25}
25}
26
26
27echo_deps_licenses() {
27echo_deps_licenses() {
psc-bundle/Main.hsnew file+138
@@ -0,0 +1,138 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : psc-bundle
4+-- Copyright : (c) Phil Freeman 2015
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- | Bundles compiled PureScript modules for the browser.
12+--
13+-----------------------------------------------------------------------------
14+
15+{-# LANGUAGE PatternGuards #-}
16+{-# LANGUAGE FlexibleContexts #-}
17+{-# LANGUAGE ScopedTypeVariables #-}
18+{-# LANGUAGE TupleSections #-}
19+{-# LANGUAGE RecordWildCards #-}
20+
21+module Main (main) where
22+
23+import Data.Traversable (for)
24+import Data.Version (showVersion)
25+
26+import Control.Applicative
27+import Control.Monad
28+import Control.Monad.Error.Class
29+import Control.Monad.Trans.Except
30+import Control.Monad.IO.Class
31+
32+import System.FilePath (takeFileName, takeDirectory)
33+import System.FilePath.Glob (glob)
34+import System.Exit (exitFailure)
35+import System.IO (stderr, hPutStrLn)
36+import System.Directory (createDirectoryIfMissing)
37+
38+import Language.PureScript.Bundle
39+
40+import Options.Applicative as Opts
41+
42+import qualified Paths_purescript as Paths
43+
44+-- | Command line options.
45+data Options = Options
46+ { optionsInputFiles :: [FilePath]
47+ , optionsOutputFile :: Maybe FilePath
48+ , optionsEntryPoints :: [String]
49+ , optionsMainModule :: Maybe String
50+ , optionsNamespace :: String
51+ } deriving Show
52+
53+-- | Given a filename, assuming it is in the correct place on disk, infer a ModuleIdentifier.
54+guessModuleIdentifier :: (Applicative m, MonadError ErrorMessage m) => FilePath -> m ModuleIdentifier
55+guessModuleIdentifier filename = ModuleIdentifier (takeFileName (takeDirectory filename)) <$> (guessModuleType (takeFileName filename))
56+ where
57+ guessModuleType "index.js" = pure Regular
58+ guessModuleType "foreign.js" = pure Foreign
59+ guessModuleType name = throwError $ UnsupportedModulePath name
60+
61+-- | The main application function.
62+-- This function parses the input files, performs dead code elimination, filters empty modules
63+-- and generates and prints the final Javascript bundle.
64+app :: forall m. (Applicative m, MonadError ErrorMessage m, MonadIO m) => Options -> m String
65+app Options{..} = do
66+ inputFiles <- concat <$> mapM (liftIO . glob) optionsInputFiles
67+ when (null inputFiles) . liftIO $ do
68+ hPutStrLn stderr "psc-bundle: No input files."
69+ exitFailure
70+ input <- for inputFiles $ \filename -> do
71+ js <- liftIO (readFile filename)
72+ mid <- guessModuleIdentifier filename
73+ return (mid, js)
74+
75+ let entryIds = (map (`ModuleIdentifier` Regular) optionsEntryPoints)
76+
77+ bundle input entryIds optionsMainModule optionsNamespace
78+
79+-- | Command line options parser.
80+options :: Parser Options
81+options = Options <$> some inputFile
82+ <*> optional outputFile
83+ <*> many entryPoint
84+ <*> optional mainModule
85+ <*> namespace
86+ where
87+ inputFile :: Parser FilePath
88+ inputFile = strArgument $
89+ metavar "FILE"
90+ <> help "The input .js file(s)"
91+
92+ outputFile :: Parser FilePath
93+ outputFile = strOption $
94+ short 'o'
95+ <> long "output"
96+ <> help "The output .js file"
97+
98+ entryPoint :: Parser String
99+ entryPoint = strOption $
100+ short 'm'
101+ <> long "module"
102+ <> help "Entry point module name(s). All code which is not a transitive dependency of an entry point module will be removed."
103+
104+ mainModule :: Parser String
105+ mainModule = strOption $
106+ long "main"
107+ <> help "Generate code to run the main method in the specified module."
108+
109+ namespace :: Parser String
110+ namespace = strOption $
111+ short 'n'
112+ <> long "namespace"
113+ <> Opts.value "PS"
114+ <> showDefault
115+ <> help "Specify the namespace that PureScript modules will be exported to when running in the browser."
116+
117+-- | Make it go.
118+main :: IO ()
119+main = do
120+ opts <- execParser (info (version <*> helper <*> options) infoModList)
121+ output <- runExceptT (app opts)
122+ case output of
123+ Left err -> do
124+ hPutStrLn stderr (unlines (printErrorMessage err))
125+ exitFailure
126+ Right js ->
127+ case optionsOutputFile opts of
128+ Just outputFile -> do
129+ createDirectoryIfMissing True (takeDirectory outputFile)
130+ writeFile outputFile js
131+ Nothing -> putStrLn js
132+ where
133+ infoModList = fullDesc <> headerInfo <> footerInfo
134+ headerInfo = header "psc-bundle - Bundles compiled PureScript modules for the browser"
135+ footerInfo = footer $ "psc-bundle " ++ showVersion Paths.version
136+
137+ version :: Parser (a -> a)
138+ version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> help "Show the version number" <> hidden
psc-bundle/README.mdnew file+18
@@ -0,0 +1,18 @@
1+# psc-bundle
2+
3+A dead code elimination tool for PureScript-style CommonJS modules. This can be used as an alternative to Browserify.
4+
5+## Usage
6+
7+ psc-bundle FILE (-m|--module ARG) [--main ARG] [--namespace ARG]
8+
9+Options:
10+
11+- The input .js file(s)
12+- Entry point module name(s) are specified with `-m` or `--module`. All code which is not a transitive dependency of an entry point module will be removed.
13+- The main module is (optionally) specified using `--main`. If specified, this will generate code to run the main method in the specified module.
14+- The browser namespace defaults to `PS`, and can be overridden with `--namespace`.
15+
16+For example, to bundle the modules in the `output` directory, with main module `Main`:
17+
18+ psc-bundle output/**/*.js -m Main --main Main
psc-docs/Main.hs+3−1
@@ -34,6 +34,7 @@ import System.Exit (exitFailure)
34import System.IO (hPutStrLn, stderr)
34import System.IO (hPutStrLn, stderr)
35import System.Directory (createDirectoryIfMissing)
35import System.Directory (createDirectoryIfMissing)
36import System.FilePath (takeDirectory)
36import System.FilePath (takeDirectory)
37+import System.FilePath.Glob (glob)
37
38
38import Etags
39import Etags
39import Ctags
40import Ctags
@@ -61,7 +62,8 @@ data PSCDocsOptions = PSCDocsOptions
61 deriving (Show)
62 deriving (Show)
62
63
63docgen :: PSCDocsOptions -> IO ()
64docgen :: PSCDocsOptions -> IO ()
64−docgen (PSCDocsOptions fmt input output) =
65+docgen (PSCDocsOptions fmt inputGlob output) = do
66+ input <- concat <$> mapM glob inputGlob
65 case fmt of
67 case fmt of
66 Etags -> dumpTags input dumpEtags
68 Etags -> dumpTags input dumpEtags
67 Ctags -> dumpTags input dumpCtags
69 Ctags -> dumpTags input dumpCtags
psc-make/Main.hsdeleted−164
@@ -1,164 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Main
4−-- Copyright : (c) Phil Freeman 2013
5−-- License : MIT
6−--
7−-- Maintainer : Phil Freeman <paf31@cantab.net>
8−-- Stability : experimental
9−-- Portability :
10−--
11−-- |
12−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE DataKinds #-}
16−{-# LANGUAGE FlexibleContexts #-}
17−{-# LANGUAGE RecordWildCards #-}
18−{-# LANGUAGE TupleSections #-}
19−
20−module Main where
21−
22−import Control.Applicative
23−import Control.Monad
24−import Control.Monad.Error.Class (MonadError(..))
25−import Control.Monad.Writer
26−
27−import Data.Version (showVersion)
28−import qualified Data.Map as M
29−
30−import Options.Applicative as Opts
31−
32−import System.Exit (exitSuccess, exitFailure)
33−import System.IO (hPutStrLn, stderr)
34−
35−import qualified Language.PureScript as P
36−import qualified Paths_purescript as Paths
37−
38−import Make
39−
40−data PSCMakeOptions = PSCMakeOptions
41− { pscmInput :: [FilePath]
42− , pscmForeignInput :: [FilePath]
43− , pscmOutputDir :: FilePath
44− , pscmOpts :: P.Options P.Make
45− , pscmUsePrefix :: Bool
46− }
47−
48−data InputOptions = InputOptions
49− { ioInputFiles :: [FilePath]
50− }
51−
52−compile :: PSCMakeOptions -> IO ()
53−compile (PSCMakeOptions input inputForeign outputDir opts usePrefix) = do
54− moduleFiles <- readInput (InputOptions input)
55− foreignFiles <- forM inputForeign (\inFile -> (inFile,) <$> readFile inFile)
56− case runWriterT (parseInputs moduleFiles foreignFiles) of
57− Left errs -> do
58− hPutStrLn stderr (P.prettyPrintMultipleErrors (P.optionsVerboseErrors opts) errs)
59− exitFailure
60− Right ((ms, foreigns), warnings) -> do
61− when (P.nonEmpty warnings) $
62− hPutStrLn stderr (P.prettyPrintMultipleWarnings (P.optionsVerboseErrors opts) warnings)
63− let filePathMap = M.fromList $ map (\(fp, P.Module _ mn _ _) -> (mn, fp)) ms
64− makeActions = buildMakeActions outputDir filePathMap foreigns usePrefix
65− e <- runMake opts $ P.make makeActions ms
66− case e of
67− Left errs -> do
68− putStrLn (P.prettyPrintMultipleErrors (P.optionsVerboseErrors opts) errs)
69− exitFailure
70− Right (_, warnings') -> do
71− when (P.nonEmpty warnings') $
72− putStrLn (P.prettyPrintMultipleWarnings (P.optionsVerboseErrors opts) warnings')
73− exitSuccess
74−
75−readInput :: InputOptions -> IO [(Either P.RebuildPolicy FilePath, String)]
76−readInput InputOptions{..} = forM ioInputFiles $ \inFile -> (Right inFile, ) <$> readFile inFile
77−
78−parseInputs :: (Functor m, Applicative m, MonadError P.MultipleErrors m, MonadWriter P.MultipleErrors m)
79− => [(Either P.RebuildPolicy FilePath, String)]
80− -> [(FilePath, P.ForeignJS)]
81− -> m ([(Either P.RebuildPolicy FilePath, P.Module)], M.Map P.ModuleName (FilePath, P.ForeignJS))
82−parseInputs modules foreigns =
83− (,) <$> P.parseModulesFromFiles (either (const "") id) modules
84− <*> P.parseForeignModulesFromFiles foreigns
85−
86−inputFile :: Parser FilePath
87−inputFile = strArgument $
88− metavar "FILE"
89− <> help "The input .purs file(s)"
90−
91−inputForeignFile :: Parser FilePath
92−inputForeignFile = strOption $
93− short 'f'
94− <> long "ffi"
95− <> help "The input .js file(s) providing foreign import implementations"
96−
97−outputDirectory :: Parser FilePath
98−outputDirectory = strOption $
99− short 'o'
100− <> long "output"
101− <> Opts.value "output"
102− <> showDefault
103− <> help "The output directory"
104−
105−noTco :: Parser Bool
106−noTco = switch $
107− long "no-tco"
108− <> help "Disable tail call optimizations"
109−
110−noMagicDo :: Parser Bool
111−noMagicDo = switch $
112− long "no-magic-do"
113− <> help "Disable the optimization that overloads the do keyword to generate efficient code specifically for the Eff monad."
114−
115−noOpts :: Parser Bool
116−noOpts = switch $
117− long "no-opts"
118− <> help "Skip the optimization phase."
119−
120−comments :: Parser Bool
121−comments = switch $
122− short 'c'
123− <> long "comments"
124− <> help "Include comments in the generated code."
125−
126−verboseErrors :: Parser Bool
127−verboseErrors = switch $
128− short 'v'
129− <> long "verbose-errors"
130− <> help "Display verbose error messages"
131−
132−noPrefix :: Parser Bool
133−noPrefix = switch $
134− short 'p'
135− <> long "no-prefix"
136− <> help "Do not include comment header"
137−
138−
139−options :: Parser (P.Options P.Make)
140−options = P.Options <$> noTco
141− <*> noMagicDo
142− <*> pure Nothing
143− <*> noOpts
144− <*> verboseErrors
145− <*> (not <$> comments)
146− <*> pure P.MakeOptions
147−
148−pscMakeOptions :: Parser PSCMakeOptions
149−pscMakeOptions = PSCMakeOptions <$> many inputFile
150− <*> many inputForeignFile
151− <*> outputDirectory
152− <*> options
153− <*> (not <$> noPrefix)
154−
155−main :: IO ()
156−main = execParser opts >>= compile
157− where
158− opts = info (version <*> helper <*> pscMakeOptions) infoModList
159− infoModList = fullDesc <> headerInfo <> footerInfo
160− headerInfo = header "psc-make - Compiles PureScript to Javascript"
161− footerInfo = footer $ "psc-make " ++ showVersion Paths.version
162−
163− version :: Parser (a -> a)
164− version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> help "Show the version number" <> hidden
psc-make/Make.hsdeleted−138
@@ -1,138 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Make
4−-- Copyright : (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors
5−-- License : MIT
6−--
7−-- Maintainer : Phil Freeman <paf31@cantab.net>
8−-- Stability : experimental
9−-- Portability :
10−--
11−-- |
12−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE DataKinds #-}
16−{-# LANGUAGE FlexibleContexts #-}
17−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
18−{-# LANGUAGE TupleSections #-}
19−
20−module Make
21− ( Make(..)
22− , runMake
23− , buildMakeActions
24− ) where
25−
26−import Control.Applicative
27−import Control.Monad
28−import Control.Monad.Error.Class (MonadError(..))
29−import Control.Monad.Trans.Except
30−import Control.Monad.Reader
31−import Control.Monad.Writer
32−
33−import Data.Maybe (fromMaybe)
34−import Data.Time.Clock
35−import Data.Traversable (traverse)
36−import Data.Version (showVersion)
37−import qualified Data.Map as M
38−
39−import System.Directory
40− (doesFileExist, getModificationTime, createDirectoryIfMissing)
41−import System.FilePath ((</>), takeDirectory)
42−import System.IO.Error (tryIOError)
43−
44−import qualified Language.PureScript as P
45−import qualified Language.PureScript.CodeGen.JS as J
46−import qualified Language.PureScript.CoreFn as CF
47−import qualified Paths_purescript as Paths
48−
49−newtype Make a = Make { unMake :: ReaderT (P.Options P.Make) (WriterT P.MultipleErrors (ExceptT P.MultipleErrors IO)) a }
50− deriving (Functor, Applicative, Monad, MonadIO, MonadError P.MultipleErrors, MonadWriter P.MultipleErrors, MonadReader (P.Options P.Make))
51−
52−runMake :: P.Options P.Make -> Make a -> IO (Either P.MultipleErrors (a, P.MultipleErrors))
53−runMake opts = runExceptT . runWriterT . flip runReaderT opts . unMake
54−
55−makeIO :: (IOError -> P.ErrorMessage) -> IO a -> Make a
56−makeIO f io = do
57− e <- liftIO $ tryIOError io
58− either (throwError . P.singleError . f) return e
59−
60−-- Traverse (Either e) instance (base 4.7)
61−traverseEither :: Applicative f => (a -> f b) -> Either e a -> f (Either e b)
62−traverseEither _ (Left x) = pure (Left x)
63−traverseEither f (Right y) = Right <$> f y
64−
65−buildMakeActions :: FilePath
66− -> M.Map P.ModuleName (Either P.RebuildPolicy String)
67− -> M.Map P.ModuleName (FilePath, P.ForeignJS)
68− -> Bool
69− -> P.MakeActions Make
70−buildMakeActions outputDir filePathMap foreigns usePrefix =
71− P.MakeActions getInputTimestamp getOutputTimestamp readExterns codegen progress
72− where
73−
74− getInputTimestamp :: P.ModuleName -> Make (Either P.RebuildPolicy (Maybe UTCTime))
75− getInputTimestamp mn = do
76− let path = fromMaybe (error "Module has no filename in 'make'") $ M.lookup mn filePathMap
77− traverseEither getTimestamp path
78−
79− getOutputTimestamp :: P.ModuleName -> Make (Maybe UTCTime)
80− getOutputTimestamp mn = do
81− let filePath = P.runModuleName mn
82− jsFile = outputDir </> filePath </> "index.js"
83− externsFile = outputDir </> filePath </> "externs.purs"
84− min <$> getTimestamp jsFile <*> getTimestamp externsFile
85−
86− readExterns :: P.ModuleName -> Make (FilePath, String)
87− readExterns mn = do
88− let path = outputDir </> P.runModuleName mn </> "externs.purs"
89− (path, ) <$> readTextFile path
90−
91− codegen :: CF.Module CF.Ann -> P.Environment -> P.SupplyVar -> P.Externs -> Make ()
92− codegen m _ nextVar exts = do
93− let mn = CF.moduleName m
94− foreignInclude <- case mn `M.lookup` foreigns of
95− Just (path, _)
96− | not $ requiresForeign m -> do
97− tell $ P.errorMessage $ P.UnnecessaryFFIModule mn path
98− return Nothing
99− | otherwise -> return $ Just $ J.JSApp (J.JSVar "require") [J.JSStringLiteral "./foreign"]
100− Nothing | requiresForeign m -> throwError . P.errorMessage $ P.MissingFFIModule mn
101− | otherwise -> return Nothing
102− pjs <- P.evalSupplyT nextVar $ P.prettyPrintJS <$> J.moduleToJs m foreignInclude
103− let filePath = P.runModuleName mn
104− jsFile = outputDir </> filePath </> "index.js"
105− externsFile = outputDir </> filePath </> "externs.purs"
106− foreignFile = outputDir </> filePath </> "foreign.js"
107− prefix = ["Generated by psc-make version " ++ showVersion Paths.version | usePrefix]
108− js = unlines $ map ("// " ++) prefix ++ [pjs]
109− writeTextFile jsFile js
110− maybe (return ()) (writeTextFile foreignFile . snd) $ mn `M.lookup` foreigns
111− writeTextFile externsFile exts
112−
113− requiresForeign :: CF.Module a -> Bool
114− requiresForeign = not . null . CF.moduleForeign
115−
116− getTimestamp :: FilePath -> Make (Maybe UTCTime)
117− getTimestamp path = makeIO (const (P.SimpleErrorWrapper $ P.CannotGetFileInfo path)) $ do
118− exists <- doesFileExist path
119− traverse (const $ getModificationTime path) $ guard exists
120−
121− readTextFile :: FilePath -> Make String
122− readTextFile path = do
123− verboseErrorsEnabled <- asks P.optionsVerboseErrors
124− makeIO (const (P.SimpleErrorWrapper $ P.CannotReadFile path)) $ do
125− when verboseErrorsEnabled $ putStrLn $ "Reading " ++ path
126− readFile path
127−
128− writeTextFile :: FilePath -> String -> Make ()
129− writeTextFile path text = makeIO (const (P.SimpleErrorWrapper $ P.CannotWriteFile path)) $ do
130− mkdirp path
131− putStrLn $ "Writing " ++ path
132− writeFile path text
133− where
134− mkdirp :: FilePath -> IO ()
135− mkdirp = createDirectoryIfMissing True . takeDirectory
136−
137− progress :: String -> Make ()
138− progress = liftIO . putStrLn
psc-publish/Main.hs+29−271
@@ -1,280 +1,38 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE RecordWildCards #-}
3−{-# LANGUAGE TupleSections #-}
4−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5
1
6−import Prelude hiding (userError)
2+module Main where
7−
8−import Data.Maybe
9−import Data.Char (isSpace)
10−import Data.String (fromString)
11−import Data.List (stripPrefix, isSuffixOf, (\\))
12−import Data.List.Split (splitOn)
13−import Data.List.NonEmpty (NonEmpty(..))
14−import Data.Version
15−import Safe (headMay)
16−
17−import qualified Data.ByteString.Lazy.Char8 as BL
18−import qualified Data.Text as T
19
3
4+import Data.Version (Version(..), showVersion)
20import qualified Data.Aeson as A
5import qualified Data.Aeson as A
21−import Data.Aeson.BetterErrors
6+import qualified Data.ByteString.Lazy.Char8 as BL
22−
23−import Control.Applicative
24−import Control.Category ((>>>))
25−import Control.Arrow ((***))
26−import Control.Exception (catch, try)
27−import Control.Monad.Trans.Except
28−import Control.Monad.Error.Class (MonadError(..))
29−import Control.Monad.Writer
30
7
31−import System.Directory (doesFileExist)
8+import Options.Applicative hiding (str)
32−import System.Process (readProcess)
33−import System.Exit (exitFailure)
34−import qualified System.FilePath.Glob as Glob
35
9
36−import Web.Bower.PackageMeta (PackageMeta(..), BowerError(..), PackageName,
10+import qualified Paths_purescript as Paths
37− runPackageName, parsePackageName, Repository(..))
11+import Language.PureScript.Publish
38−import qualified Web.Bower.PackageMeta as Bower
39
12
40−import qualified Language.PureScript.Docs as D
13+dryRun :: Parser Bool
41−import Utils
14+dryRun = switch $
42−import ErrorsWarnings
15+ long "dry-run"
16+ <> help "Produce no output, and don't require a tagged version to be checked out."
43
17
44main :: IO ()
18main :: IO ()
45−main = do
19+main = execParser opts >>= publish
46− pkg <- preparePackage
47− BL.putStrLn (A.encode pkg)
48−
49−-- | Attempt to retrieve package metadata from the current directory.
50−-- Calls exitFailure if no package metadata could be retrieved.
51−preparePackage :: IO D.UploadedPackage
52−preparePackage =
53− runPrepareM preparePackage'
54− >>= either (\e -> printError e >> exitFailure)
55− handleWarnings
56− where
57− handleWarnings (result, warns) = do
58− printWarnings warns
59− return result
60−
61−newtype PrepareM a =
62− PrepareM { unPrepareM :: WriterT [PackageWarning] (ExceptT PackageError IO) a }
63− deriving (Functor, Applicative, Monad,
64− MonadWriter [PackageWarning],
65− MonadError PackageError)
66−
67−-- This MonadIO instance ensures that IO errors don't crash the program.
68−instance MonadIO PrepareM where
69− liftIO act =
70− lift' (try act) >>= either (otherError . IOExceptionThrown) return
71− where
72− lift' :: IO a -> PrepareM a
73− lift' = PrepareM . lift . lift
74−
75−runPrepareM :: PrepareM a -> IO (Either PackageError (a, [PackageWarning]))
76−runPrepareM = runExceptT . runWriterT . unPrepareM
77−
78−warn :: PackageWarning -> PrepareM ()
79−warn w = tell [w]
80−
81−userError :: UserError -> PrepareM a
82−userError = throwError . UserError
83−
84−internalError :: InternalError -> PrepareM a
85−internalError = throwError . InternalError
86−
87−otherError :: OtherError -> PrepareM a
88−otherError = throwError . OtherError
89−
90−catchLeft :: Applicative f => Either a b -> (a -> f b) -> f b
91−catchLeft a f = either f pure a
92−
93−preparePackage' :: PrepareM D.UploadedPackage
94−preparePackage' = do
95− exists <- liftIO (doesFileExist "bower.json")
96− unless exists (userError BowerJSONNotFound)
97−
98− pkgMeta <- liftIO (Bower.decodeFile "bower.json")
99− >>= flip catchLeft (userError . CouldntParseBowerJSON)
100− (pkgVersionTag, pkgVersion) <- getVersionFromGitTag
101− pkgGithub <- getBowerInfo pkgMeta
102− (pkgBookmarks, pkgModules) <- getModulesAndBookmarks
103−
104− let declaredDeps = map fst (bowerDependencies pkgMeta ++
105− bowerDevDependencies pkgMeta)
106− pkgResolvedDependencies <- getResolvedDependencies declaredDeps
107−
108− let pkgUploader = D.NotYetKnown
109−
110− return D.Package{..}
111−
112−getModulesAndBookmarks :: PrepareM ([D.Bookmark], [D.RenderedModule])
113−getModulesAndBookmarks = do
114− (inputFiles, depsFiles) <- liftIO getInputAndDepsFiles
115− liftIO (D.parseAndDesugar inputFiles depsFiles renderModules)
116− >>= either (userError . ParseAndDesugarError) return
117 where
20 where
118− renderModules bookmarks modules =
21+ opts = info (version <*> helper <*> dryRun) infoModList
119− return (bookmarks, map D.renderModule modules)
22+ infoModList = fullDesc <> headerInfo <> footerInfo
120−
23+ headerInfo = header "psc-publish - Generates documentation packages for upload to http://pursuit.purescript.org"
121−getVersionFromGitTag :: PrepareM (String, Version)
24+ footerInfo = footer $ "psc-publish " ++ showVersion Paths.version
122−getVersionFromGitTag = do
25+
123− out <- readProcess' "git" ["tag", "--list", "--points-at", "HEAD"] ""
26+ version :: Parser (a -> a)
124− let vs = map trimWhitespace (lines out)
27+ version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> help "Show the version number" <> hidden
125− case mapMaybe parseMay vs of
28+
126− [] -> userError TagMustBeCheckedOut
29+publish :: Bool -> IO ()
127− [x] -> return x
30+publish isDryRun =
128− xs -> userError (AmbiguousVersions (map snd xs))
31+ if isDryRun
129− where
32+ then do
130− trimWhitespace =
33+ let dummyVersion = ("0.0.0", Version [0,0,0] [])
131− dropWhile isSpace >>> reverse >>> dropWhile isSpace >>> reverse
34+ _ <- preparePackage $ defaultPublishOptions { publishGetVersion = return dummyVersion }
132− parseMay str =
35+ putStrLn "Dry run completed, no errors."
133− (str,) <$> D.parseVersion' (dropPrefix "v" str)
134− dropPrefix prefix str =
135− fromMaybe str (stripPrefix prefix str)
136−
137−getBowerInfo :: PackageMeta -> PrepareM (D.GithubUser, D.GithubRepo)
138−getBowerInfo = either (userError . BadRepositoryField) return . tryExtract
139− where
140− tryExtract pkgMeta =
141− case bowerRepository pkgMeta of
142− Nothing -> Left RepositoryFieldMissing
143− Just Repository{..} -> do
144− unless (repositoryType == "git")
145− (Left (BadRepositoryType repositoryType))
146− maybe (Left NotOnGithub) Right (extractGithub repositoryUrl)
147−
148−extractGithub :: String -> Maybe (D.GithubUser, D.GithubRepo)
149−extractGithub =
150− stripPrefix "git://github.com/"
151− >>> fmap (splitOn "/")
152− >=> takeTwo
153− >>> fmap (D.GithubUser *** (D.GithubRepo . dropDotGit))
154−
155− where
156− takeTwo :: [a] -> Maybe (a, a)
157− takeTwo [x, y] = Just (x, y)
158− takeTwo _ = Nothing
159−
160− dropDotGit :: String -> String
161− dropDotGit str
162− | ".git" `isSuffixOf` str = take (length str - 4) str
163− | otherwise = str
164−
165−readProcess' :: String -> [String] -> String -> PrepareM String
166−readProcess' prog args stdin = do
167− out <- liftIO (catch (Right <$> readProcess prog args stdin)
168− (return . Left))
169− either (otherError . ProcessFailed prog args) return out
170−
171−data DependencyStatus
172− = Missing
173− | ResolvedOther String
174− -- ^ Resolved, but to something other than a version. The String argument
175− -- is the resolution type. The values it can take that I'm aware of are
176− -- "commit" and "branch".
177− | ResolvedVersion String
178− -- ^ Resolved to a version. The String argument is the resolution tag (eg,
179− -- "v0.1.0").
180− deriving (Show, Eq)
181−
182−-- Go through all bower dependencies which contain purescript code, and
183−-- extract their versions.
184−--
185−-- In the case where a bower dependency is taken from a particular version,
186−-- that's easy; take that version. In any other case (eg, a branch, or a commit
187−-- sha) we print a warning that documentation links will not work, and avoid
188−-- linking to documentation for any types from that package.
189−--
190−-- The rationale for this is: people will prefer to use a released version
191−-- where possible. If they are not using a released version, then this is
192−-- probably for a reason. However, docs are only ever available for released
193−-- versions. Therefore there will probably be no version of the docs which is
194−-- appropriate to link to, and we should omit links.
195−getResolvedDependencies :: [PackageName] -> PrepareM [(PackageName, Version)]
196−getResolvedDependencies declaredDeps = do
197− depsBS <- fromString <$> readProcess' "bower" ["list", "--json", "--offline"] ""
198−
199− deps <- catchLeft (parse asBowerResolvedDependencies depsBS)
200− (internalError . JSONError FromBowerList)
201−
202− warnUndeclared declaredDeps (map fst deps)
203− handleDeps deps
204−
205− where
206− asBowerResolvedDependencies ::
207− Parse BowerError [(PackageName, DependencyStatus)]
208− asBowerResolvedDependencies =
209− key "dependencies"
210− (eachInObjectWithKey (parsePackageName . T.unpack) asDependencyStatus)
211−
212−asDependencyStatus :: Parse e DependencyStatus
213−asDependencyStatus = do
214− isMissing <- keyOrDefault "missing" False asBool
215− if isMissing
216− then
217− return Missing
218− else
36+ else do
219− key "pkgMeta" $
37+ pkg <- preparePackage defaultPublishOptions
220− key "_resolution" $ do
38+ BL.putStrLn (A.encode pkg)
221− type_ <- key "type" asString
222− case type_ of
223− "version" -> ResolvedVersion <$> key "tag" asString
224− other -> return (ResolvedOther other)
225−
226−warnUndeclared :: [PackageName] -> [PackageName] -> PrepareM ()
227−warnUndeclared declared actual =
228− mapM_ (warn . UndeclaredDependency) (actual \\ declared)
229−
230−handleDeps ::
231− [(PackageName, DependencyStatus)] -> PrepareM [(PackageName, Version)]
232−handleDeps deps = do
233− let (missing, notVersion, installed) = partitionDeps deps
234− case missing of
235− (x:xs) ->
236− userError (MissingDependencies (x :| xs))
237− [] -> do
238− mapM_ (warn . ResolutionNotVersion . fst) notVersion
239− let withVersions = mapMaybe tryExtractVersion installed
240− filterM (liftIO . isPureScript . bowerDir . fst) withVersions
241−
242− where
243− partitionDeps = foldr go ([], [], [])
244− go (pkgName, d) (ms, os, is) =
245− case d of
246− Missing -> (pkgName : ms, os, is)
247− ResolvedOther o -> (ms, (pkgName, o) : os, is)
248− ResolvedVersion v -> (ms, os, (pkgName, v) : is)
249−
250− bowerDir pkgName = "bower_components/" ++ runPackageName pkgName
251−
252−tryExtractVersion :: (PackageName, String) -> Maybe (PackageName, Version)
253−tryExtractVersion (pkgName, tag) =
254− let tag' = fromMaybe tag (stripPrefix "v" tag)
255− in (pkgName,) <$> D.parseVersion' tag'
256−
257−-- | Returns whether it looks like there is a purescript package checked out
258−-- in the given directory.
259−isPureScript :: FilePath -> IO Bool
260−isPureScript dir = do
261− files <- Glob.globDir1 purescriptSourceFiles dir
262− return (not (null files))
263−
264−getInputAndDepsFiles :: IO ([FilePath], [(PackageName, FilePath)])
265−getInputAndDepsFiles = do
266− inputFiles <- globRelative purescriptSourceFiles
267− depsFiles' <- globRelative purescriptDepsFiles
268− return (inputFiles, mapMaybe withPackageName depsFiles')
269−
270−withPackageName :: FilePath -> Maybe (PackageName, FilePath)
271−withPackageName fp = (,fp) <$> getPackageName fp
272−
273−getPackageName :: FilePath -> Maybe PackageName
274−getPackageName fp = do
275− let xs = splitOn "/" fp
276− ys <- stripPrefix ["bower_components"] xs
277− y <- headMay ys
278− case Bower.mkPackageName y of
279− Right name -> Just name
280− Left _ -> Nothing
psc-publish/Utils.hsdeleted−22
@@ -1,22 +0,0 @@
1−
2−module Utils where
3−
4−import Data.List
5−import Data.Maybe
6−import System.Directory
7−import qualified System.FilePath.Glob as Glob
8−
9−-- | Glob relative to the current directory, and produce relative pathnames.
10−globRelative :: Glob.Pattern -> IO [FilePath]
11−globRelative pat = do
12− currentDir <- getCurrentDirectory
13− filesAbsolute <- Glob.globDir1 pat currentDir
14− return (mapMaybe (stripPrefix (currentDir ++ "/")) filesAbsolute)
15−
16−-- | Glob pattern for PureScript source files.
17−purescriptSourceFiles :: Glob.Pattern
18−purescriptSourceFiles = Glob.compile "src/**/*.purs"
19−
20−-- | Glob pattern for PureScript dependency files.
21−purescriptDepsFiles :: Glob.Pattern
22−purescriptDepsFiles = Glob.compile "bower_components/*/src/**/*.purs"
psc-publish/tests/Test.hs+13−10
@@ -1,5 +1,6 @@
1{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
1{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
2{-# OPTIONS_GHC -fno-warn-unused-imports #-}
2{-# OPTIONS_GHC -fno-warn-unused-imports #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
3
4
4-- | To run these tests:
5-- | To run these tests:
5--
6--
@@ -11,6 +12,7 @@ module Test where
11
12
12import Control.Monad
13import Control.Monad
13import Control.Applicative
14import Control.Applicative
15+import Control.Exception
14import System.Process
16import System.Process
15import System.Directory
17import System.Directory
16import qualified Data.ByteString.Lazy as BL
18import qualified Data.ByteString.Lazy as BL
@@ -21,17 +23,17 @@ import Data.Aeson.BetterErrors
21import Main
23import Main
22import Language.PureScript.Docs
24import Language.PureScript.Docs
23
25
24−packageName = "purescript-integers"
26+pkgName = "purescript-prelude"
25−packageUrl = "https://github.com/purescript/" ++ packageName
27+packageUrl = "https://github.com/purescript/" ++ pkgName
26−packageDir = "tmp/" ++ packageName
28+packageDir = "tmp/" ++ pkgName
27
29
28−pushd :: FilePath -> IO a -> IO a
30+pushd :: forall a. FilePath -> IO a -> IO a
29pushd dir act = do
31pushd dir act = do
30 original <- getCurrentDirectory
32 original <- getCurrentDirectory
31 setCurrentDirectory dir
33 setCurrentDirectory dir
32− result <- act
34+ result <- try act :: IO (Either IOException a)
33 setCurrentDirectory original
35 setCurrentDirectory original
34− return result
36+ either throwIO return result
35
37
36clonePackage :: IO ()
38clonePackage :: IO ()
37clonePackage = do
39clonePackage = do
@@ -39,8 +41,9 @@ clonePackage = do
39 pushd packageDir $ do
41 pushd packageDir $ do
40 exists <- doesDirectoryExist ".git"
42 exists <- doesDirectoryExist ".git"
41 unless exists $ do
43 unless exists $ do
42− putStrLn ("Cloning " ++ packageName ++ " into " ++ packageDir ++ "...")
44+ putStrLn ("Cloning " ++ pkgName ++ " into " ++ packageDir ++ "...")
43 readProcess "git" ["clone", packageUrl, "."] "" >>= putStr
45 readProcess "git" ["clone", packageUrl, "."] "" >>= putStr
46+ readProcess "git" ["tag", "v999.0.0"] "" >>= putStr
44
47
45bowerInstall :: IO ()
48bowerInstall :: IO ()
46bowerInstall = do
49bowerInstall = do
@@ -54,7 +57,7 @@ getPackage = do
54 pushd packageDir preparePackage
57 pushd packageDir preparePackage
55
58
56data TestResult
59data TestResult
57− = ParseFailed (ParseError UploadedPackageError)
60+ = ParseFailed String
58 | Mismatch ByteString ByteString -- ^ encoding before, encoding after
61 | Mismatch ByteString ByteString -- ^ encoding before, encoding after
59 | Pass ByteString
62 | Pass ByteString
60 deriving (Show)
63 deriving (Show)
@@ -67,10 +70,10 @@ test = roundTrip <$> getPackage
67roundTrip :: UploadedPackage -> TestResult
70roundTrip :: UploadedPackage -> TestResult
68roundTrip pkg =
71roundTrip pkg =
69 let before = A.encode pkg
72 let before = A.encode pkg
70− in case parse asUploadedPackage before of
73+ in case A.eitherDecode before of
71 Left err -> ParseFailed err
74 Left err -> ParseFailed err
72 Right parsed -> do
75 Right parsed -> do
73− let after = A.encode parsed
76+ let after = A.encode (parsed :: UploadedPackage)
74 if before == after
77 if before == after
75 then Pass before
78 then Pass before
76 else Mismatch before after
79 else Mismatch before after
psc/Main.hs+78−130
@@ -15,7 +15,6 @@
15{-# LANGUAGE DataKinds #-}
15{-# LANGUAGE DataKinds #-}
16{-# LANGUAGE FlexibleContexts #-}
16{-# LANGUAGE FlexibleContexts #-}
17{-# LANGUAGE RecordWildCards #-}
17{-# LANGUAGE RecordWildCards #-}
18−{-# LANGUAGE ScopedTypeVariables #-}
19{-# LANGUAGE TupleSections #-}
18{-# LANGUAGE TupleSections #-}
20
19
21module Main where
20module Main where
@@ -23,52 +22,42 @@ module Main where
23import Control.Applicative
22import Control.Applicative
24import Control.Monad
23import Control.Monad
25import Control.Monad.Error.Class (MonadError(..))
24import Control.Monad.Error.Class (MonadError(..))
26−import Control.Monad.Reader
27import Control.Monad.Writer
25import Control.Monad.Writer
28
26
29−import Data.Maybe (fromMaybe)
30import Data.Version (showVersion)
27import Data.Version (showVersion)
28+import qualified Data.Map as M
31
29
32import Options.Applicative as Opts
30import Options.Applicative as Opts
33
31
34−import System.Directory (createDirectoryIfMissing)
35import System.Exit (exitSuccess, exitFailure)
32import System.Exit (exitSuccess, exitFailure)
36−import System.FilePath (takeDirectory)
37import System.IO (hPutStrLn, stderr)
33import System.IO (hPutStrLn, stderr)
34+import System.FilePath.Glob (glob)
38
35
39−import qualified Data.Map as M
40import qualified Language.PureScript as P
36import qualified Language.PureScript as P
41import qualified Paths_purescript as Paths
37import qualified Paths_purescript as Paths
42
38
43−data PSCOptions = PSCOptions
39+import Language.PureScript.Make
40+
41+data PSCMakeOptions = PSCMakeOptions
44− { pscInput :: [FilePath]
42+ { pscmInput :: [FilePath]
45− , pscForeignInput :: [FilePath]
43+ , pscmForeignInput :: [FilePath]
44+ , pscmOutputDir :: FilePath
46− , pscOpts :: P.Options P.Compile
45+ , pscmOpts :: P.Options
47− , pscStdIn :: Bool
46+ , pscmUsePrefix :: Bool
48− , pscOutput :: Maybe FilePath
49− , pscExterns :: Maybe FilePath
50− , pscUsePrefix :: Bool
51 }
47 }
52
48
53data InputOptions = InputOptions
49data InputOptions = InputOptions
54− { ioUseStdIn :: Bool
55− , ioInputFiles :: [FilePath]
50+ { ioInputFiles :: [FilePath]
56 }
51 }
57
52
58−readInput :: InputOptions -> IO [(Maybe FilePath, String)]
53+compile :: PSCMakeOptions -> IO ()
59−readInput InputOptions{..}
54+compile (PSCMakeOptions inputGlob inputForeignGlob outputDir opts usePrefix) = do
60− | ioUseStdIn = return . (Nothing ,) <$> getContents
55+ input <- concat <$> mapM glob inputGlob
61− | otherwise = forM ioInputFiles $ \inFile -> (Just inFile, ) <$> readFile inFile
56+ when (null input) $ do
62−
57+ hPutStrLn stderr "psc: No input files."
63−type PSC = ReaderT (P.Options P.Compile) (WriterT P.MultipleErrors (Either P.MultipleErrors))
58+ exitFailure
64−
65−runPSC :: P.Options P.Compile -> PSC a -> Either P.MultipleErrors (a, P.MultipleErrors)
66−runPSC opts rwe = runWriterT (runReaderT rwe opts)
67−
68−compile :: PSCOptions -> IO ()
69−compile (PSCOptions input inputForeign opts stdin output externs usePrefix) = do
70− let prefix = ["Generated by psc version " ++ showVersion Paths.version | usePrefix]
71− moduleFiles <- readInput (InputOptions stdin input)
59+ moduleFiles <- readInput (InputOptions input)
60+ inputForeign <- concat <$> mapM glob inputForeignGlob
72 foreignFiles <- forM inputForeign (\inFile -> (inFile,) <$> readFile inFile)
61 foreignFiles <- forM inputForeign (\inFile -> (inFile,) <$> readFile inFile)
73 case runWriterT (parseInputs moduleFiles foreignFiles) of
62 case runWriterT (parseInputs moduleFiles foreignFiles) of
74 Left errs -> do
63 Left errs -> do
@@ -77,115 +66,80 @@ compile (PSCOptions input inputForeign opts stdin output externs usePrefix) = do
77 Right ((ms, foreigns), warnings) -> do
66 Right ((ms, foreigns), warnings) -> do
78 when (P.nonEmpty warnings) $
67 when (P.nonEmpty warnings) $
79 hPutStrLn stderr (P.prettyPrintMultipleWarnings (P.optionsVerboseErrors opts) warnings)
68 hPutStrLn stderr (P.prettyPrintMultipleWarnings (P.optionsVerboseErrors opts) warnings)
80− case runPSC opts (P.compileJS ms foreigns prefix) of
69+ let filePathMap = M.fromList $ map (\(fp, P.Module _ mn _ _) -> (mn, fp)) ms
70+ makeActions = buildMakeActions outputDir filePathMap foreigns usePrefix
71+ e <- runMake opts $ P.make makeActions (map snd ms)
72+ case e of
81 Left errs -> do
73 Left errs -> do
82 hPutStrLn stderr (P.prettyPrintMultipleErrors (P.optionsVerboseErrors opts) errs)
74 hPutStrLn stderr (P.prettyPrintMultipleErrors (P.optionsVerboseErrors opts) errs)
83 exitFailure
75 exitFailure
84− Right ((js, exts, _), warnings') -> do
76+ Right (_, warnings') -> do
85 when (P.nonEmpty warnings') $
77 when (P.nonEmpty warnings') $
86 hPutStrLn stderr (P.prettyPrintMultipleWarnings (P.optionsVerboseErrors opts) warnings')
78 hPutStrLn stderr (P.prettyPrintMultipleWarnings (P.optionsVerboseErrors opts) warnings')
87− case output of
88− Just path -> mkdirp path >> writeFile path js
89− Nothing -> putStrLn js
90− case externs of
91− Just path -> mkdirp path >> writeFile path exts
92− Nothing -> return ()
93 exitSuccess
79 exitSuccess
94
80
81+readInput :: InputOptions -> IO [(Either P.RebuildPolicy FilePath, String)]
82+readInput InputOptions{..} = forM ioInputFiles $ \inFile -> (Right inFile, ) <$> readFile inFile
83+
95parseInputs :: (Functor m, Applicative m, MonadError P.MultipleErrors m, MonadWriter P.MultipleErrors m)
84parseInputs :: (Functor m, Applicative m, MonadError P.MultipleErrors m, MonadWriter P.MultipleErrors m)
85+ => [(Either P.RebuildPolicy FilePath, String)]
86+ -> [(FilePath, P.ForeignJS)]
96− => [(Maybe FilePath, String)] -> [(FilePath, P.ForeignJS)] -> m ([P.Module], M.Map P.ModuleName (FilePath, P.ForeignJS))
87+ -> m ([(Either P.RebuildPolicy FilePath, P.Module)], M.Map P.ModuleName (FilePath, P.ForeignJS))
97parseInputs modules foreigns =
88parseInputs modules foreigns =
98− (,) <$> (map snd <$> P.parseModulesFromFiles (fromMaybe "") modules)
89+ (,) <$> P.parseModulesFromFiles (either (const "") id) modules
99 <*> P.parseForeignModulesFromFiles foreigns
90 <*> P.parseForeignModulesFromFiles foreigns
100
91
101−mkdirp :: FilePath -> IO ()
92+inputFile :: Parser FilePath
102−mkdirp = createDirectoryIfMissing True . takeDirectory
93+inputFile = strArgument $
103−
94+ metavar "FILE"
104−codeGenModule :: Parser String
95+ <> help "The input .purs file(s)"
105−codeGenModule = strOption $
106− long "codegen"
107− <> help "A list of modules for which Javascript and externs should be generated. This argument can be used multiple times."
108
96
109−dceModule :: Parser String
97+inputForeignFile :: Parser FilePath
110−dceModule = strOption $
98+inputForeignFile = strOption $
111− short 'm'
99+ short 'f'
112− <> long "module"
100+ <> long "ffi"
113− <> help "Enables dead code elimination, all code which is not a transitive dependency of a specified module will be removed. This argument can be used multiple times."
101+ <> help "The input .js file(s) providing foreign import implementations"
114
102
115−browserNamespace :: Parser String
103+outputDirectory :: Parser FilePath
116−browserNamespace = strOption $
104+outputDirectory = strOption $
117− long "browser-namespace"
105+ short 'o'
106+ <> long "output"
118− <> Opts.value "PS"
107+ <> Opts.value "output"
119 <> showDefault
108 <> showDefault
120− <> help "Specify the namespace that PureScript modules will be exported to when running in the browser."
109+ <> help "The output directory"
121
110
122−verboseErrors :: Parser Bool
111+requirePath :: Parser (Maybe FilePath)
123−verboseErrors = switch $
112+requirePath = optional $ strOption $
124− short 'v'
113+ short 'r'
125− <> long "verbose-errors"
114+ <> long "require-path"
126− <> help "Display verbose error messages"
115+ <> help "The path prefix to use for require() calls in the generated JavaScript"
127
116
128−noOpts :: Parser Bool
117+noTco :: Parser Bool
129−noOpts = switch $
118+noTco = switch $
130− long "no-opts"
119+ long "no-tco"
131− <> help "Skip the optimization phase."
120+ <> help "Disable tail call optimizations"
132−
133−runMain :: Parser (Maybe String)
134−runMain = optional $ noArgs <|> withArgs
135− where
136− defaultVal = "Main"
137− noArgs = flag' defaultVal (long "main")
138− withArgs = strOption $
139− long "main"
140− <> help (concat [
141− "Generate code to run the main method in the specified module. ",
142− "(no argument: \"", defaultVal, "\")"
143− ])
144
121
145noMagicDo :: Parser Bool
122noMagicDo :: Parser Bool
146noMagicDo = switch $
123noMagicDo = switch $
147 long "no-magic-do"
124 long "no-magic-do"
148− <> help "Disable the optimization that overloads the do keyword to generate efficient code specifically for the Eff monad."
125+ <> help "Disable the optimization that overloads the do keyword to generate efficient code specifically for the Eff monad"
149
126
150−noTco :: Parser Bool
127+noOpts :: Parser Bool
151−noTco = switch $
128+noOpts = switch $
152− long "no-tco"
129+ long "no-opts"
153− <> help "Disable tail call optimizations"
130+ <> help "Skip the optimization phase"
154
131
155comments :: Parser Bool
132comments :: Parser Bool
156comments = switch $
133comments = switch $
157 short 'c'
134 short 'c'
158 <> long "comments"
135 <> long "comments"
159− <> help "Include comments in the generated code."
136+ <> help "Include comments in the generated code"
160−
161−useStdIn :: Parser Bool
162−useStdIn = switch $
163− short 's'
164− <> long "stdin"
165− <> help "Read from standard input"
166−
167−inputFile :: Parser FilePath
168−inputFile = strArgument $
169− metavar "FILE"
170− <> help "The input .purs file(s)"
171
137
172−inputForeignFile :: Parser FilePath
138+verboseErrors :: Parser Bool
173−inputForeignFile = strOption $
139+verboseErrors = switch $
174− short 'f'
140+ short 'v'
175− <> long "ffi"
141+ <> long "verbose-errors"
176− <> help "The input .js file(s) providing foreign import implementations"
142+ <> help "Display verbose error messages"
177−
178−outputFile :: Parser (Maybe FilePath)
179−outputFile = optional . strOption $
180− short 'o'
181− <> long "output"
182− <> help "The output .js file"
183−
184−externsFile :: Parser (Maybe FilePath)
185−externsFile = optional . strOption $
186− short 'e'
187− <> long "externs"
188− <> help "The output .e.purs file"
189
143
190noPrefix :: Parser Bool
144noPrefix :: Parser Bool
191noPrefix = switch $
145noPrefix = switch $
@@ -193,33 +147,27 @@ noPrefix = switch $
193 <> long "no-prefix"
147 <> long "no-prefix"
194 <> help "Do not include comment header"
148 <> help "Do not include comment header"
195
149
150+
196−options :: Parser (P.Options P.Compile)
151+options :: Parser P.Options
197options = P.Options <$> noTco
152options = P.Options <$> noTco
198 <*> noMagicDo
153 <*> noMagicDo
199− <*> runMain
154+ <*> pure Nothing
200 <*> noOpts
155 <*> noOpts
201 <*> verboseErrors
156 <*> verboseErrors
202 <*> (not <$> comments)
157 <*> (not <$> comments)
203− <*> additionalOptions
158+ <*> requirePath
204− where
159+
205− additionalOptions =
160+pscMakeOptions :: Parser PSCMakeOptions
206− P.CompileOptions <$> browserNamespace
161+pscMakeOptions = PSCMakeOptions <$> many inputFile
207− <*> many dceModule
208− <*> many codeGenModule
209−
210−pscOptions :: Parser PSCOptions
211−pscOptions = PSCOptions <$> many inputFile
212− <*> many inputForeignFile
162+ <*> many inputForeignFile
163+ <*> outputDirectory
213− <*> options
164+ <*> options
214− <*> useStdIn
215− <*> outputFile
216− <*> externsFile
217− <*> (not <$> noPrefix)
165+ <*> (not <$> noPrefix)
218
166
219main :: IO ()
167main :: IO ()
220main = execParser opts >>= compile
168main = execParser opts >>= compile
221 where
169 where
222− opts = info (version <*> helper <*> pscOptions) infoModList
170+ opts = info (version <*> helper <*> pscMakeOptions) infoModList
223 infoModList = fullDesc <> headerInfo <> footerInfo
171 infoModList = fullDesc <> headerInfo <> footerInfo
224 headerInfo = header "psc - Compiles PureScript to Javascript"
172 headerInfo = header "psc - Compiles PureScript to Javascript"
225 footerInfo = footer $ "psc " ++ showVersion Paths.version
173 footerInfo = footer $ "psc " ++ showVersion Paths.version
psci/Completion.hs+9−6
@@ -6,6 +6,7 @@ import Data.Char (isUpper)
6import Data.Function (on)
6import Data.Function (on)
7import Data.Traversable (traverse)
7import Data.Traversable (traverse)
8
8
9+import Control.Arrow (second)
9import Control.Applicative ((<$>), (<*>))
10import Control.Applicative ((<$>), (<*>))
10import Control.Monad.Trans.Reader (asks, runReaderT, ReaderT)
11import Control.Monad.Trans.Reader (asks, runReaderT, ReaderT)
11import Control.Monad.Trans.State.Strict
12import Control.Monad.Trans.State.Strict
@@ -196,13 +197,15 @@ typeDecls = mapMaybe getTypeName . filter P.isDataDecl . P.exportedDeclarations
196 getTypeName _ = Nothing
197 getTypeName _ = Nothing
197
198
198identNames :: P.Module -> [(N.Ident, P.Declaration)]
199identNames :: P.Module -> [(N.Ident, P.Declaration)]
199−identNames = nubOnFst . mapMaybe getDeclName . P.exportedDeclarations
200+identNames = nubOnFst . concatMap getDeclNames . P.exportedDeclarations
200 where
201 where
201− getDeclName :: P.Declaration -> Maybe (P.Ident, P.Declaration)
202+ getDeclNames :: P.Declaration -> [(P.Ident, P.Declaration)]
202− getDeclName d@(P.ValueDeclaration ident _ _ _) = Just (ident, d)
203+ getDeclNames d@(P.ValueDeclaration ident _ _ _) = [(ident, d)]
204+ getDeclNames d@(P.TypeDeclaration ident _ ) = [(ident, d)]
203− getDeclName d@(P.ExternDeclaration ident _) = Just (ident, d)
205+ getDeclNames d@(P.ExternDeclaration ident _) = [(ident, d)]
206+ getDeclNames d@(P.TypeClassDeclaration _ _ _ ds) = map (second (const d)) $ concatMap getDeclNames ds
204− getDeclName (P.PositionedDeclaration _ _ d) = getDeclName d
207+ getDeclNames (P.PositionedDeclaration _ _ d) = getDeclNames d
205− getDeclName _ = Nothing
208+ getDeclNames _ = []
206
209
207dctorNames :: P.Module -> [(N.ProperName, P.Declaration)]
210dctorNames :: P.Module -> [(N.ProperName, P.Declaration)]
208dctorNames = nubOnFst . concatMap go . P.exportedDeclarations
211dctorNames = nubOnFst . concatMap go . P.exportedDeclarations
psci/Make.hsdeleted−127
@@ -1,127 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Make
4−-- Copyright : (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors
5−-- License : MIT
6−--
7−-- Maintainer : Phil Freeman <paf31@cantab.net>
8−-- Stability : experimental
9−-- Portability :
10−--
11−-- |
12−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE DataKinds #-}
16−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
17−{-# LANGUAGE TupleSections #-}
18−
19−module Make where
20−
21−import Data.List (isPrefixOf)
22−import Data.Maybe (fromMaybe)
23−import Data.Time.Clock
24−import Data.Traversable (traverse)
25−import qualified Data.Map as M
26−
27−import Control.Applicative
28−import Control.Monad
29−import Control.Monad.Error.Class (MonadError(..))
30−import Control.Monad.IO.Class (MonadIO, liftIO)
31−import Control.Monad.Reader (MonadReader, ReaderT, runReaderT)
32−import Control.Monad.Trans.Except (ExceptT(..), runExceptT)
33−import Control.Monad.Writer (MonadWriter, WriterT, runWriterT, tell)
34−
35−import System.Directory (getModificationTime, doesFileExist)
36−import System.FilePath ((</>), pathSeparator)
37−import System.IO.Error (tryIOError)
38−
39−import qualified Language.PureScript as P
40−import qualified Language.PureScript.CodeGen.JS as J
41−import qualified Language.PureScript.CoreFn as CF
42−
43−import IO (mkdirp)
44−
45−options :: P.Options P.Make
46−options = P.Options False False Nothing False False False P.MakeOptions
47−
48−modulesDir :: FilePath
49−modulesDir = ".psci_modules" ++ pathSeparator : "node_modules"
50−
51−newtype Make a = Make { unMake :: ReaderT (P.Options P.Make) (WriterT P.MultipleErrors (ExceptT P.MultipleErrors IO)) a }
52− deriving (Functor, Applicative, Monad, MonadIO, MonadError P.MultipleErrors, MonadWriter P.MultipleErrors, MonadReader (P.Options P.Make))
53−
54−runMake :: Make a -> IO (Either P.MultipleErrors a)
55−runMake = runExceptT . fmap fst . runWriterT . flip runReaderT options . unMake
56−
57−makeIO :: (IOError -> P.ErrorMessage) -> IO a -> Make a
58−makeIO f io = do
59− e <- liftIO $ tryIOError io
60− either (throwError . P.singleError . f) return e
61−
62−-- Traverse (Either e) instance (base 4.7)
63−traverseEither :: Applicative f => (a -> f b) -> Either e a -> f (Either e b)
64−traverseEither _ (Left x) = pure (Left x)
65−traverseEither f (Right y) = Right <$> f y
66−
67−buildMakeActions :: M.Map P.ModuleName (Either P.RebuildPolicy String)
68− -> M.Map P.ModuleName P.ForeignJS
69− -> P.MakeActions Make
70−buildMakeActions filePathMap foreigns =
71− P.MakeActions getInputTimestamp getOutputTimestamp readExterns codegen progress
72− where
73−
74− getInputTimestamp :: P.ModuleName -> Make (Either P.RebuildPolicy (Maybe UTCTime))
75− getInputTimestamp mn = do
76− let path = fromMaybe (error "Module has no filename in 'make'") $ M.lookup mn filePathMap
77− traverseEither getTimestamp path
78−
79− getOutputTimestamp :: P.ModuleName -> Make (Maybe UTCTime)
80− getOutputTimestamp mn = do
81− let filePath = P.runModuleName mn
82− jsFile = modulesDir </> filePath </> "index.js"
83− externsFile = modulesDir </> filePath </> "externs.purs"
84− min <$> getTimestamp jsFile <*> getTimestamp externsFile
85−
86− readExterns :: P.ModuleName -> Make (FilePath, String)
87− readExterns mn = do
88− let path = modulesDir </> P.runModuleName mn </> "externs.purs"
89− (path, ) <$> readTextFile path
90−
91− codegen :: CF.Module CF.Ann -> P.Environment -> P.SupplyVar -> P.Externs -> Make ()
92− codegen m _ nextVar exts = do
93− let mn = CF.moduleName m
94− foreignInclude <- case CF.moduleName m `M.lookup` foreigns of
95− Just path
96− | not $ requiresForeign m -> do tell $ P.errorMessage $ P.UnnecessaryFFIModule mn path
97− return Nothing
98− | otherwise -> return $ Just $ J.JSApp (J.JSVar "require") [J.JSStringLiteral "./foreign"]
99− Nothing | requiresForeign m -> throwError . P.errorMessage $ P.MissingFFIModule mn
100− | otherwise -> return Nothing
101− pjs <- P.evalSupplyT nextVar $ P.prettyPrintJS <$> J.moduleToJs m foreignInclude
102− let filePath = P.runModuleName $ CF.moduleName m
103− jsFile = modulesDir </> filePath </> "index.js"
104− externsFile = modulesDir </> filePath </> "externs.purs"
105− foreignFile = modulesDir </> filePath </> "foreign.js"
106− writeTextFile jsFile pjs
107− maybe (return ()) (writeTextFile foreignFile) $ CF.moduleName m `M.lookup` foreigns
108− writeTextFile externsFile exts
109−
110− requiresForeign :: CF.Module a -> Bool
111− requiresForeign = not . null . CF.moduleForeign
112−
113− getTimestamp :: FilePath -> Make (Maybe UTCTime)
114− getTimestamp path = makeIO (const (P.SimpleErrorWrapper $ P.CannotGetFileInfo path)) $ do
115− exists <- doesFileExist path
116− traverse (const $ getModificationTime path) $ guard exists
117−
118− readTextFile :: FilePath -> Make String
119− readTextFile path = makeIO (const (P.SimpleErrorWrapper $ P.CannotReadFile path)) $ readFile path
120−
121− writeTextFile :: FilePath -> String -> Make ()
122− writeTextFile path text = makeIO (const (P.SimpleErrorWrapper $ P.CannotWriteFile path)) $ do
123− mkdirp path
124− writeFile path text
125−
126− progress :: String -> Make ()
127− progress s = unless ("Compiling $PSCI" `isPrefixOf` s) $ liftIO . putStrLn $ s
psci/PSCi.hs+56−23
@@ -30,10 +30,12 @@ import qualified Data.Map as M
30import Control.Applicative
30import Control.Applicative
31import Control.Arrow (first)
31import Control.Arrow (first)
32import Control.Monad
32import Control.Monad
33+import Control.Monad.Error.Class (MonadError(..))
33import Control.Monad.Trans.Class
34import Control.Monad.Trans.Class
34import Control.Monad.Trans.Except (runExceptT)
35import Control.Monad.Trans.Except (runExceptT)
35import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
36import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
36import Control.Monad.Trans.State.Strict
37import Control.Monad.Trans.State.Strict
38+import Control.Monad.IO.Class (liftIO)
37import Control.Monad.Writer (runWriter)
39import Control.Monad.Writer (runWriter)
38import qualified Control.Monad.Trans.State.Lazy as L
40import qualified Control.Monad.Trans.State.Lazy as L
39
41
@@ -43,7 +45,9 @@ import System.Console.Haskeline
43import System.Directory (doesFileExist, findExecutable, getHomeDirectory, getCurrentDirectory)
45import System.Directory (doesFileExist, findExecutable, getHomeDirectory, getCurrentDirectory)
44import System.Exit
46import System.Exit
45import System.FilePath (pathSeparator, (</>), isPathSeparator)
47import System.FilePath (pathSeparator, (</>), isPathSeparator)
48+import System.FilePath.Glob (glob)
46import System.Process (readProcessWithExitCode)
49import System.Process (readProcessWithExitCode)
50+import System.IO.Error (tryIOError)
47
51
48import qualified Language.PureScript as P
52import qualified Language.PureScript as P
49import qualified Language.PureScript.Names as N
53import qualified Language.PureScript.Names as N
@@ -52,7 +56,6 @@ import qualified Paths_purescript as Paths
52import qualified Directive as D
56import qualified Directive as D
53import Completion (completion)
57import Completion (completion)
54import IO (mkdirp)
58import IO (mkdirp)
55−import Make
56import Parser (parseCommand)
59import Parser (parseCommand)
57import Types
60import Types
58
61
@@ -88,12 +91,15 @@ supportModule =
88
91
89-- File helpers
92-- File helpers
90
93
94+onFirstFileMatching :: Monad m => (b -> m (Maybe a)) -> [b] -> m (Maybe a)
95+onFirstFileMatching f pathVariants = runMaybeT . msum $ map (MaybeT . f) pathVariants
96+
91-- |
97-- |
92-- Locates the node executable.
98-- Locates the node executable.
93-- Checks for either @nodejs@ or @node@.
99-- Checks for either @nodejs@ or @node@.
94--
100--
95findNodeProcess :: IO (Maybe String)
101findNodeProcess :: IO (Maybe String)
96−findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names
102+findNodeProcess = onFirstFileMatching findExecutable names
97 where names = ["nodejs", "node"]
103 where names = ["nodejs", "node"]
98
104
99-- |
105-- |
@@ -216,12 +222,12 @@ createTemporaryModule exec PSCiState{psciImportedModules = imports, psciLetBindi
216-- Makes a volatile module to hold a non-qualified type synonym for a fully-qualified data type declaration.
222-- Makes a volatile module to hold a non-qualified type synonym for a fully-qualified data type declaration.
217--
223--
218createTemporaryModuleForKind :: PSCiState -> P.Type -> P.Module
224createTemporaryModuleForKind :: PSCiState -> P.Type -> P.Module
219−createTemporaryModuleForKind PSCiState{psciImportedModules = imports} typ =
225+createTemporaryModuleForKind PSCiState{psciImportedModules = imports, psciLetBindings = lets} typ =
220 let
226 let
221 moduleName = P.ModuleName [P.ProperName "$PSCI"]
227 moduleName = P.ModuleName [P.ProperName "$PSCI"]
222 itDecl = P.TypeSynonymDeclaration (P.ProperName "IT") [] typ
228 itDecl = P.TypeSynonymDeclaration (P.ProperName "IT") [] typ
223 in
229 in
224− P.Module [] moduleName ((importDecl `map` imports) ++ [itDecl]) Nothing
230+ P.Module [] moduleName ((importDecl `map` imports) ++ lets ++ [itDecl]) Nothing
225
231
226-- |
232-- |
227-- Makes a volatile module to execute the current imports.
233-- Makes a volatile module to execute the current imports.
@@ -239,10 +245,25 @@ importDecl (mn, declType, asQ) = P.ImportDeclaration mn declType asQ
239indexFile :: FilePath
245indexFile :: FilePath
240indexFile = ".psci_modules" ++ pathSeparator : "index.js"
246indexFile = ".psci_modules" ++ pathSeparator : "index.js"
241
247
248+modulesDir :: FilePath
249+modulesDir = ".psci_modules" ++ pathSeparator : "node_modules"
250+
251+-- | This is different than the runMake in 'Language.PureScript.Make' in that it specifies the
252+-- options and ignores the warning messages.
253+runMake :: P.Make a -> IO (Either P.MultipleErrors a)
254+runMake mk = fmap (fmap fst) $ P.runMake P.defaultOptions mk
255+
256+makeIO :: (IOError -> P.ErrorMessage) -> IO a -> P.Make a
257+makeIO f io = do
258+ e <- liftIO $ tryIOError io
259+ either (throwError . P.singleError . f) return e
260+
242−make :: PSCiState -> [(Either P.RebuildPolicy FilePath, P.Module)] -> Make P.Environment
261+make :: PSCiState -> [(Either P.RebuildPolicy FilePath, P.Module)] -> P.Make P.Environment
243−make PSCiState{..} ms =
262+make PSCiState{..} ms = P.make actions' (map snd (psciLoadedModules ++ ms))
263+ where
244− let filePathMap = M.fromList $ (first P.getModuleName . swap) `map` (psciLoadedModules ++ ms)
264+ filePathMap = M.fromList $ (first P.getModuleName . swap) `map` (psciLoadedModules ++ ms)
245− in P.make (buildMakeActions filePathMap (M.map snd psciForeignFiles)) (psciLoadedModules ++ ms)
265+ actions = P.buildMakeActions modulesDir filePathMap psciForeignFiles False
266+ actions' = actions { P.progress = const (return ()) }
246
267
247-- |
268-- |
248-- Takes a value declaration and evaluates it with the current state.
269-- Takes a value declaration and evaluates it with the current state.
@@ -314,6 +335,7 @@ handleShowImportedModules = do
314 showRef (P.ValueRef ident) = show ident
335 showRef (P.ValueRef ident) = show ident
315 showRef (P.TypeClassRef pn) = show pn
336 showRef (P.TypeClassRef pn) = show pn
316 showRef (P.TypeInstanceRef ident) = show ident
337 showRef (P.TypeInstanceRef ident) = show ident
338+ showRef (P.ModuleRef name) = "module " ++ show name
317 showRef (P.PositionedDeclarationRef _ _ ref) = showRef ref
339 showRef (P.PositionedDeclarationRef _ _ ref) = showRef ref
318
340
319 commaList :: [String] -> String
341 commaList :: [String] -> String
@@ -467,18 +489,27 @@ whenFileExists filePath f = do
467 then f absPath
489 then f absPath
468 else PSCI . outputStrLn $ "Couldn't locate: " ++ filePath
490 else PSCI . outputStrLn $ "Couldn't locate: " ++ filePath
469
491
492+-- |
493+-- Attempts to read initial commands from '.psci' in the present working
494+-- directory then the user's home
495+--
470loadUserConfig :: IO (Maybe [Command])
496loadUserConfig :: IO (Maybe [Command])
471−loadUserConfig = do
497+loadUserConfig = onFirstFileMatching readCommands pathGetters
498+ where
499+ pathGetters = [getCurrentDirectory, getHomeDirectory]
500+ readCommands :: IO FilePath -> IO (Maybe [Command])
501+ readCommands path = do
472− configFile <- (</> ".psci") <$> getCurrentDirectory
502+ configFile <- (</> ".psci") <$> path
473− exists <- doesFileExist configFile
503+ exists <- doesFileExist configFile
474− if exists
504+ if exists
475− then do
505+ then do
476− ls <- lines <$> readFile configFile
506+ ls <- lines <$> readFile configFile
477− case mapM parseCommand ls of
507+ case mapM parseCommand ls of
478− Left err -> print err >> exitFailure
508+ Left err -> print err >> exitFailure
479− Right cs -> return $ Just cs
509+ Right cs -> return $ Just cs
480− else
510+ else
481− return Nothing
511+ return Nothing
512+
482
513
483-- | Checks if the Console module is defined
514-- | Checks if the Console module is defined
484consoleIsDefined :: [P.Module] -> Bool
515consoleIsDefined :: [P.Module] -> Bool
@@ -490,19 +521,21 @@ consoleIsDefined = any ((== P.ModuleName (map P.ProperName [ "Control", "Monad",
490loop :: PSCiOptions -> IO ()
521loop :: PSCiOptions -> IO ()
491loop PSCiOptions{..} = do
522loop PSCiOptions{..} = do
492 config <- loadUserConfig
523 config <- loadUserConfig
524+ inputFiles <- concat <$> mapM glob psciInputFile
525+ foreignFiles <- concat <$> mapM glob psciForeignInputFiles
493− modulesOrFirstError <- loadAllModules psciInputFile
526+ modulesOrFirstError <- loadAllModules inputFiles
494 case modulesOrFirstError of
527 case modulesOrFirstError of
495 Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> exitFailure
528 Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> exitFailure
496 Right modules -> do
529 Right modules -> do
497 historyFilename <- getHistoryFilename
530 historyFilename <- getHistoryFilename
498 let settings = defaultSettings { historyFile = Just historyFilename }
531 let settings = defaultSettings { historyFile = Just historyFilename }
499 foreignsOrError <- runMake $ do
532 foreignsOrError <- runMake $ do
500− foreignFiles <- forM psciForeignInputFiles (\inFile -> (inFile,) <$> makeIO (const (P.SimpleErrorWrapper $ P.CannotReadFile inFile)) (readFile inFile))
533+ foreignFilesContent <- forM foreignFiles (\inFile -> (inFile,) <$> makeIO (const (P.SimpleErrorWrapper $ P.CannotReadFile inFile)) (readFile inFile))
501− P.parseForeignModulesFromFiles foreignFiles
534+ P.parseForeignModulesFromFiles foreignFilesContent
502 case foreignsOrError of
535 case foreignsOrError of
503 Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> exitFailure
536 Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> exitFailure
504 Right foreigns ->
537 Right foreigns ->
505− flip evalStateT (PSCiState psciInputFile [] modules foreigns [] psciInputNodeFlags) . runInputT (setComplete completion settings) $ do
538+ flip evalStateT (PSCiState inputFiles [] modules foreigns [] psciInputNodeFlags) . runInputT (setComplete completion settings) $ do
506 outputStrLn prologueMessage
539 outputStrLn prologueMessage
507 traverse_ (mapM_ (runPSCI . handleCommand)) config
540 traverse_ (mapM_ (runPSCI . handleCommand)) config
508 modules' <- lift $ gets psciLoadedModules
541 modules' <- lift $ gets psciLoadedModules
psci/tests/Main.hs+35−29
@@ -8,12 +8,13 @@ import Control.Applicative
8import Control.Monad.Writer (runWriterT)
8import Control.Monad.Writer (runWriterT)
9import Control.Monad.Trans.Except (runExceptT)
9import Control.Monad.Trans.Except (runExceptT)
10
10
11−import Data.List (isSuffixOf, sort)
11+import Data.List (sort)
12
12
13import System.Exit (exitFailure)
13import System.Exit (exitFailure)
14import System.Console.Haskeline
14import System.Console.Haskeline
15import System.FilePath ((</>))
15import System.FilePath ((</>))
16−import System.Directory (getCurrentDirectory, getDirectoryContents)
16+import System.Directory (getCurrentDirectory)
17+import qualified System.FilePath.Glob as Glob
17
18
18import Test.HUnit
19import Test.HUnit
19
20
@@ -48,9 +49,14 @@ completionTestData =
48 , (":mo", [":module"])
49 , (":mo", [":module"])
49 , (":b", [":browse"])
50 , (":b", [":browse"])
50
51
51− -- :browse should complete modules
52+ -- :browse should complete module names
52− , (":b Prel", [":b Prelude", ":b Prelude.Unsafe"])
53+ , (":b Control.Monad.E", map (":b Control.Monad.Eff" ++) ["", ".Unsafe", ".Class", ".Console"])
53− , (":b Prelude.", [":b Prelude.Unsafe"])
54+ , (":b Control.Monad.Eff.", map (":b Control.Monad.Eff" ++) [".Unsafe", ".Class", ".Console"])
55+
56+ -- import should complete module names
57+ , ("import Control.Monad.E", map ("import Control.Monad.Eff" ++) ["", ".Unsafe", ".Class", ".Console"])
58+ , ("import Control.Monad.Eff.", map ("import Control.Monad.Eff" ++) [".Unsafe", ".Class", ".Console"])
59+ , ("import qualified Control.Monad.Eff.", map ("import qualified Control.Monad.Eff" ++) [".Unsafe", ".Class", ".Console"])
54
60
55 -- :load, :module should complete file paths
61 -- :load, :module should complete file paths
56 , (":l psci/tests/data/", [":l psci/tests/data/Sample.purs"])
62 , (":l psci/tests/data/", [":l psci/tests/data/Sample.purs"])
@@ -66,8 +72,8 @@ completionTestData =
66 , (":show a", [])
72 , (":show a", [])
67
73
68 -- :type should complete values and data constructors in scope
74 -- :type should complete values and data constructors in scope
69− , (":type Prelude.Unsafe.un", [":type Prelude.Unsafe.unsafeIndex"])
75+ , (":type Control.Monad.Eff.Console.lo", [":type Control.Monad.Eff.Console.log"])
70− , (":type un", [":type unit"])
76+ , (":type uni", [":type unit"])
71 , (":type E", [":type EQ"])
77 , (":type E", [":type EQ"])
72
78
73 -- :kind should complete types in scope
79 -- :kind should complete types in scope
@@ -79,25 +85,19 @@ completionTestData =
79 , (":type EQ ", [])
85 , (":type EQ ", [])
80 , (":kind Ordering ", [])
86 , (":kind Ordering ", [])
81
87
82− -- import should complete module names
83− , ("import Control.Monad.S", ["import Control.Monad.ST"])
84− , ("import qualified Control.Monad.S", ["import qualified Control.Monad.ST"])
85− , ("import Control.Monad.", map ("import Control.Monad." ++)
86− ["Eff", "ST"])
87−
88 -- a few other import tests
88 -- a few other import tests
89 , ("impor", ["import"])
89 , ("impor", ["import"])
90 , ("import q", ["import qualified"])
90 , ("import q", ["import qualified"])
91− , ("import ", map ("import " ++) allModuleNames ++ ["import qualified"])
91+ , ("import ", map ("import " ++) supportModules ++ ["import qualified"])
92− , ("import Prelude.Unsafe ", [])
92+ , ("import Prelude ", [])
93
93
94 -- String and number literals should not be completed
94 -- String and number literals should not be completed
95 , ("\"hi", [])
95 , ("\"hi", [])
96 , ("34", [])
96 , ("34", [])
97
97
98 -- Identifiers and data constructors should be completed
98 -- Identifiers and data constructors should be completed
99− , ("un", ["unit"])
99+ , ("uni", ["unit"])
100− , ("Debug.Trace.", map ("Debug.Trace." ++) ["print", "trace"])
100+ , ("Control.Monad.Eff.Class.", ["Control.Monad.Eff.Class.liftEff"])
101 , ("G", ["GT"])
101 , ("G", ["GT"])
102 , ("Prelude.L", ["Prelude.LT"])
102 , ("Prelude.L", ["Prelude.LT"])
103
103
@@ -107,14 +107,6 @@ completionTestData =
107 , ("Control.Monad.ST.new", ["Control.Monad.ST.newSTRef"])
107 , ("Control.Monad.ST.new", ["Control.Monad.ST.newSTRef"])
108 ]
108 ]
109 where
109 where
110− allModuleNames = [ "Assert"
111− , "Control.Monad.Eff"
112− , "Control.Monad.ST"
113− , "Data.Function"
114− , "Debug.Trace"
115− , "Prelude"
116− , "Prelude.Unsafe"
117− ]
118
110
119assertCompletedOk :: (String, [String]) -> Assertion
111assertCompletedOk :: (String, [String]) -> Assertion
120assertCompletedOk (line, expecteds) = do
112assertCompletedOk (line, expecteds) = do
@@ -131,10 +123,12 @@ runCM act = do
131getPSCiState :: IO PSCiState
123getPSCiState :: IO PSCiState
132getPSCiState = do
124getPSCiState = do
133 cwd <- getCurrentDirectory
125 cwd <- getCurrentDirectory
134− let preludeDir = cwd </> "tests" </> "prelude"
126+ let supportDir = cwd </> "tests" </> "support" </> "flattened"
135− jsDir = preludeDir </> "js"
127+ let supportFiles ext = Glob.globDir1 (Glob.compile ("*." ++ ext)) supportDir
136− modulesOrFirstError <- loadAllModules [ preludeDir </> "Prelude.purs" ]
128+ pursFiles <- supportFiles "purs"
137− jsFiles <- map (jsDir </>) . filter (".js" `isSuffixOf`) <$> getDirectoryContents jsDir
129+ jsFiles <- supportFiles "js"
130+
131+ modulesOrFirstError <- loadAllModules pursFiles
138 foreignFiles <- forM jsFiles (\f -> (f,) <$> readFile f)
132 foreignFiles <- forM jsFiles (\f -> (f,) <$> readFile f)
139 Right (foreigns, _) <- runExceptT $ runWriterT $ P.parseForeignModulesFromFiles foreignFiles
133 Right (foreigns, _) <- runExceptT $ runWriterT $ P.parseForeignModulesFromFiles foreignFiles
140 case modulesOrFirstError of
134 case modulesOrFirstError of
@@ -148,3 +142,15 @@ controlMonadSTasST :: ImportedModule
148controlMonadSTasST = (s "Control.Monad.ST", P.Implicit, Just (s "ST"))
142controlMonadSTasST = (s "Control.Monad.ST", P.Implicit, Just (s "ST"))
149 where
143 where
150 s = P.moduleNameFromString
144 s = P.moduleNameFromString
145+
146+supportModules :: [String]
147+supportModules =
148+ [ "Control.Monad.Eff.Class"
149+ , "Control.Monad.Eff.Console"
150+ , "Control.Monad.Eff"
151+ , "Control.Monad.Eff.Unsafe"
152+ , "Control.Monad.ST"
153+ , "Data.Function"
154+ , "Prelude"
155+ , "Test.Assert"
156+ ]
purescript.cabal+52−35
@@ -1,10 +1,10 @@
1name: purescript
1name: purescript
2−version: 0.7.0.0
2+version: 0.7.2.0
3cabal-version: >=1.8
3cabal-version: >=1.8
4build-type: Simple
4build-type: Simple
5license: MIT
5license: MIT
6license-file: LICENSE
6license-file: LICENSE
7−copyright: (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors
7+copyright: (c) 2013-15 Phil Freeman, (c) 2014-15 Gary Burgess
8maintainer: Phil Freeman <paf31@cantab.net>
8maintainer: Phil Freeman <paf31@cantab.net>
9stability: experimental
9stability: experimental
10synopsis: PureScript Programming Language Compiler
10synopsis: PureScript Programming Language Compiler
@@ -13,12 +13,17 @@ category: Language
13Homepage: http://www.purescript.org/
13Homepage: http://www.purescript.org/
14author: Phil Freeman <paf31@cantab.net>,
14author: Phil Freeman <paf31@cantab.net>,
15 Gary Burgess <gary.burgess@gmail.com>,
15 Gary Burgess <gary.burgess@gmail.com>,
16− Hardy Jones <jones3.hardy@gmail.com>
16+ Hardy Jones <jones3.hardy@gmail.com>,
17+ Harry Garrood <harry@garrood.me>
17
18
18tested-with: GHC==7.8
19tested-with: GHC==7.8
19
20
20extra-source-files: examples/passing/*.purs
21extra-source-files: examples/passing/*.purs
21 , examples/failing/*.purs
22 , examples/failing/*.purs
23+ , tests/support/setup.js
24+ , tests/support/package.json
25+ , tests/support/bower.json
26+ , psci/tests/data/Sample.purs
22
27
23source-repository head
28source-repository head
24 type: git
29 type: git
@@ -42,10 +47,16 @@ library
42 aeson >= 0.8 && < 0.9,
47 aeson >= 0.8 && < 0.9,
43 vector -any,
48 vector -any,
44 bower-json >= 0.7,
49 bower-json >= 0.7,
45− aeson-better-errors >= 0.7,
50+ aeson-better-errors >= 0.8,
46 bytestring -any,
51 bytestring -any,
47 text -any,
52 text -any,
48− split -any
53+ split -any,
54+ language-javascript == 0.5.*,
55+ syb -any,
56+ Glob >= 0.7 && < 0.8,
57+ process >= 1.2.0 && < 1.3,
58+ safe >= 0.3.9 && < 0.4,
59+ semigroups >= 0.16.2 && < 0.17
49
60
50 exposed-modules: Language.PureScript
61 exposed-modules: Language.PureScript
51 Language.PureScript.AST
62 Language.PureScript.AST
@@ -55,6 +66,7 @@ library
55 Language.PureScript.AST.SourcePos
66 Language.PureScript.AST.SourcePos
56 Language.PureScript.AST.Traversals
67 Language.PureScript.AST.Traversals
57 Language.PureScript.AST.Exported
68 Language.PureScript.AST.Exported
69+ Language.PureScript.Bundle
58 Language.PureScript.CodeGen
70 Language.PureScript.CodeGen
59 Language.PureScript.CodeGen.Externs
71 Language.PureScript.CodeGen.Externs
60 Language.PureScript.CodeGen.JS
72 Language.PureScript.CodeGen.JS
@@ -78,11 +90,12 @@ library
78 Language.PureScript.CoreFn.Module
90 Language.PureScript.CoreFn.Module
79 Language.PureScript.CoreFn.Traversals
91 Language.PureScript.CoreFn.Traversals
80 Language.PureScript.Comments
92 Language.PureScript.Comments
81− Language.PureScript.DeadCodeElimination
82 Language.PureScript.Environment
93 Language.PureScript.Environment
83 Language.PureScript.Errors
94 Language.PureScript.Errors
84 Language.PureScript.Kinds
95 Language.PureScript.Kinds
85 Language.PureScript.Linter
96 Language.PureScript.Linter
97+ Language.PureScript.Linter.Exhaustive
98+ Language.PureScript.Make
86 Language.PureScript.ModuleDependencies
99 Language.PureScript.ModuleDependencies
87 Language.PureScript.Names
100 Language.PureScript.Names
88 Language.PureScript.Options
101 Language.PureScript.Options
@@ -126,6 +139,7 @@ library
126 Language.PureScript.Types
139 Language.PureScript.Types
127
140
128 Language.PureScript.Docs
141 Language.PureScript.Docs
142+ Language.PureScript.Docs.Convert
129 Language.PureScript.Docs.Render
143 Language.PureScript.Docs.Render
130 Language.PureScript.Docs.Types
144 Language.PureScript.Docs.Types
131 Language.PureScript.Docs.RenderedCode
145 Language.PureScript.Docs.RenderedCode
@@ -135,6 +149,11 @@ library
135 Language.PureScript.Docs.ParseAndDesugar
149 Language.PureScript.Docs.ParseAndDesugar
136 Language.PureScript.Docs.Utils.MonoidExtras
150 Language.PureScript.Docs.Utils.MonoidExtras
137
151
152+ Language.PureScript.Publish
153+ Language.PureScript.Publish.Utils
154+ Language.PureScript.Publish.ErrorsWarnings
155+ Language.PureScript.Publish.BoxesHelpers
156+
138 Control.Monad.Unify
157 Control.Monad.Unify
139 Control.Monad.Supply
158 Control.Monad.Supply
140 Control.Monad.Supply.Class
159 Control.Monad.Supply.Class
@@ -148,28 +167,17 @@ library
148executable psc
167executable psc
149 build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
168 build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
150 mtl -any, optparse-applicative >= 0.10.0, parsec -any, purescript -any,
169 mtl -any, optparse-applicative >= 0.10.0, parsec -any, purescript -any,
151− transformers -any
170+ time -any, transformers -any, transformers-compat -any, Glob >= 0.7 && < 0.8
152 main-is: Main.hs
171 main-is: Main.hs
153 buildable: True
172 buildable: True
154 hs-source-dirs: psc
173 hs-source-dirs: psc
155− other-modules:
156− ghc-options: -Wall -O2 -fno-warn-unused-do-bind
157−
158−executable psc-make
159− build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
160− mtl -any, optparse-applicative >= 0.10.0, parsec -any, purescript -any,
161− time -any, transformers -any, transformers-compat -any
162− main-is: Main.hs
163− buildable: True
164− hs-source-dirs: psc-make
165− other-modules: Make
166 ghc-options: -Wall -O2 -fno-warn-unused-do-bind
174 ghc-options: -Wall -O2 -fno-warn-unused-do-bind
167
175
168executable psci
176executable psci
169 build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
177 build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
170 mtl -any, optparse-applicative >= 0.10.0, parsec -any,
178 mtl -any, optparse-applicative >= 0.10.0, parsec -any,
171 haskeline >= 0.7.0.0, purescript -any, transformers -any,
179 haskeline >= 0.7.0.0, purescript -any, transformers -any,
172− transformers-compat -any, process -any, time -any
180+ transformers-compat -any, process -any, time -any, Glob -any
173
181
174 main-is: Main.hs
182 main-is: Main.hs
175 buildable: True
183 buildable: True
@@ -179,15 +187,14 @@ executable psci
179 Directive
187 Directive
180 Completion
188 Completion
181 PSCi
189 PSCi
182− Make
183 IO
190 IO
184 ghc-options: -Wall -O2
191 ghc-options: -Wall -O2
185
192
186executable psc-docs
193executable psc-docs
187 build-depends: base >=4 && <5, purescript -any,
194 build-depends: base >=4 && <5, purescript -any,
188 optparse-applicative >= 0.10.0, process -any, mtl -any,
195 optparse-applicative >= 0.10.0, process -any, mtl -any,
189− split -any, ansi-wl-pprint -any, directory -any, filepath
196+ split -any, ansi-wl-pprint -any, directory -any,
190− -any
197+ filepath -any, Glob -any
191 main-is: Main.hs
198 main-is: Main.hs
192 buildable: True
199 buildable: True
193 hs-source-dirs: psc-docs
200 hs-source-dirs: psc-docs
@@ -197,34 +204,43 @@ executable psc-docs
197 ghc-options: -Wall -O2
204 ghc-options: -Wall -O2
198
205
199executable psc-publish
206executable psc-publish
200− build-depends: base >=4 && <5, purescript -any,
207+ build-depends: base >=4 && <5, purescript -any, bytestring -any, aeson -any, optparse-applicative -any
201− optparse-applicative >= 0.10.0, process -any, mtl -any,
202− pattern-arrows -any, aeson -any, bytestring -any,
203− directory -any, transformers -any, text -any, containers
204− -any, boxes -any, split -any, Glob -any, aeson-better-errors
205− -any, transformers-compat -any, bower-json -any, semigroups
206− -any, safe -any
207 main-is: Main.hs
208 main-is: Main.hs
208 buildable: True
209 buildable: True
209 hs-source-dirs: psc-publish
210 hs-source-dirs: psc-publish
210− other-modules: Utils
211− ErrorsWarnings
212− BoxesHelpers
213 ghc-options: -Wall -O2
211 ghc-options: -Wall -O2
214
212
215executable psc-hierarchy
213executable psc-hierarchy
216 build-depends: base >=4 && <5, purescript -any, optparse-applicative >= 0.10.0,
214 build-depends: base >=4 && <5, purescript -any, optparse-applicative >= 0.10.0,
217− process -any, mtl -any, parsec -any, filepath -any, directory -any
215+ process -any, mtl -any, parsec -any, filepath -any, directory -any,
216+ Glob -any
218 main-is: Main.hs
217 main-is: Main.hs
219 buildable: True
218 buildable: True
220 hs-source-dirs: hierarchy
219 hs-source-dirs: hierarchy
221 other-modules:
220 other-modules:
222 ghc-options: -Wall -O2
221 ghc-options: -Wall -O2
223
222
223+executable psc-bundle
224+ main-is: Main.hs
225+ other-modules:
226+ other-extensions:
227+ build-depends: base >=4 && <5,
228+ purescript -any,
229+ filepath -any,
230+ directory -any,
231+ mtl -any,
232+ transformers -any,
233+ transformers-compat -any,
234+ optparse-applicative >= 0.10.0,
235+ Glob -any
236+ ghc-options: -Wall -O2
237+ hs-source-dirs: psc-bundle
238+
224test-suite tests
239test-suite tests
225 build-depends: base >=4 && <5, containers -any, directory -any,
240 build-depends: base >=4 && <5, containers -any, directory -any,
226 filepath -any, mtl -any, parsec -any, purescript -any,
241 filepath -any, mtl -any, parsec -any, purescript -any,
227− transformers -any, process -any, transformers-compat -any
242+ transformers -any, process -any, transformers-compat -any, time -any,
243+ Glob -any
228 type: exitcode-stdio-1.0
244 type: exitcode-stdio-1.0
229 main-is: Main.hs
245 main-is: Main.hs
230 buildable: True
246 buildable: True
@@ -234,7 +250,8 @@ test-suite psci-tests
234 build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
250 build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
235 mtl -any, optparse-applicative >= 0.10.0, parsec -any,
251 mtl -any, optparse-applicative >= 0.10.0, parsec -any,
236 haskeline >= 0.7.0.0, purescript -any, transformers -any,
252 haskeline >= 0.7.0.0, purescript -any, transformers -any,
237− transformers-compat -any, process -any, HUnit -any, time -any
253+ transformers-compat -any, process -any, HUnit -any, time -any,
254+ Glob -any
238 type: exitcode-stdio-1.0
255 type: exitcode-stdio-1.0
239 main-is: Main.hs
256 main-is: Main.hs
240 buildable: True
257 buildable: True
src/Language/PureScript.hs+1−244
@@ -20,41 +20,18 @@
20
20
21module Language.PureScript
21module Language.PureScript
22 ( module P
22 ( module P
23− , compile
24− , compile'
25− , compileJS
26− , RebuildPolicy(..)
27− , MakeActions(..)
28− , SupplyVar()
29− , Externs()
30− , make
31 , version
23 , version
32 ) where
24 ) where
33
25
34−import Data.Function (on)
35−import Data.List (sortBy, groupBy, intercalate)
36−import Data.Maybe (fromMaybe)
37−import Data.Time.Clock
38import Data.Version (Version)
26import Data.Version (Version)
39−import qualified Data.Map as M
40−import qualified Data.Set as S
41−
42−import Control.Applicative
43−import Control.Arrow ((&&&))
44−import Control.Monad
45−import Control.Monad.Error.Class (MonadError(..))
46−import Control.Monad.Reader
47−import Control.Monad.Writer
48−import Control.Monad.Supply.Class (MonadSupply, fresh)
49
27
50import Language.PureScript.AST as P
28import Language.PureScript.AST as P
51import Language.PureScript.Comments as P
29import Language.PureScript.Comments as P
52−import Language.PureScript.CodeGen.Externs (moduleToPs)
53−import Language.PureScript.DeadCodeElimination as P
54import Language.PureScript.Environment as P
30import Language.PureScript.Environment as P
55import Language.PureScript.Errors as P
31import Language.PureScript.Errors as P
56import Language.PureScript.Kinds as P
32import Language.PureScript.Kinds as P
57import Language.PureScript.Linter as P
33import Language.PureScript.Linter as P
34+import Language.PureScript.Make as P
58import Language.PureScript.ModuleDependencies as P
35import Language.PureScript.ModuleDependencies as P
59import Language.PureScript.Names as P
36import Language.PureScript.Names as P
60import Language.PureScript.Options as P
37import Language.PureScript.Options as P
@@ -65,228 +42,8 @@ import Language.PureScript.Sugar as P
65import Control.Monad.Supply as P
42import Control.Monad.Supply as P
66import Language.PureScript.TypeChecker as P
43import Language.PureScript.TypeChecker as P
67import Language.PureScript.Types as P
44import Language.PureScript.Types as P
68−import qualified Language.PureScript.CoreFn as CoreFn
69−import qualified Language.PureScript.Constants as C
70−import qualified Language.PureScript.CodeGen.JS as J
71
45
72import qualified Paths_purescript as Paths
46import qualified Paths_purescript as Paths
73
47
74−-- |
75−-- Compile a collection of modules
76−--
77−-- The compilation pipeline proceeds as follows:
78−--
79−-- * Sort the modules based on module dependencies, checking for cyclic dependencies.
80−--
81−-- * Perform a set of desugaring passes.
82−--
83−-- * Type check, and elaborate values to include type annotations and type class dictionaries.
84−--
85−-- * Regroup values to take into account new value dependencies introduced by elaboration.
86−--
87−-- * Eliminate dead code.
88−--
89−-- * Generate Javascript, and perform optimization passes.
90−--
91−-- * Pretty-print the generated Javascript
92−--
93−compile :: (Functor m, Applicative m, MonadError MultipleErrors m, MonadWriter MultipleErrors m, MonadReader (Options Compile) m)
94− => [Module] -> m ([CoreFn.Module CoreFn.Ann], Environment, SupplyVar, Externs)
95−compile = compile' initEnvironment
96−
97−compile' :: (Functor m, Applicative m, MonadError MultipleErrors m, MonadWriter MultipleErrors m, MonadReader (Options Compile) m)
98− => Environment -> [Module] -> m ([CoreFn.Module CoreFn.Ann], Environment, SupplyVar, Externs)
99−compile' env ms = do
100− additional <- asks optionsAdditional
101− mainModuleIdent <- asks (fmap moduleNameFromString . optionsMain)
102− (sorted, _) <- sortModules $ map importPrim ms
103− mapM_ lint sorted
104− (desugared, nextVar) <- runSupplyT 0 $ desugar sorted
105− (elaborated, env') <- runCheck' env $ forM desugared $ typeCheckModule mainModuleIdent
106− regrouped <- createBindingGroupsModule . collapseBindingGroupsModule $ elaborated
107− let corefn = map (CoreFn.moduleToCoreFn env') regrouped
108− entryPoints = moduleNameFromString `map` entryPointModules additional
109− elim = if null entryPoints then corefn else eliminateDeadCode entryPoints corefn
110− renamed = renameInModules elim
111− codeGenModuleNames = moduleNameFromString `map` codeGenModules additional
112− modulesToCodeGen = if null codeGenModuleNames then renamed else filter (\(CoreFn.Module _ mn _ _ _ _) -> mn `elem` codeGenModuleNames) renamed
113− exts = intercalate "\n" . map (`moduleToPs` env') $ regrouped
114− return (modulesToCodeGen, env', nextVar, exts)
115−
116−-- |
117−-- Compile a collection of modules to JavaScript and externs files
118−--
119−compileJS :: forall m. (Functor m, Applicative m, MonadError P.MultipleErrors m, MonadWriter P.MultipleErrors m, MonadReader (P.Options P.Compile) m)
120− => [P.Module] -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> [String] -> m (String, String, Environment)
121−compileJS ms foreigns prefix = do
122− (modulesToCodeGen, env, nextVar, exts) <- compile ms
123− js <- concat <$> evalSupplyT nextVar (P.parU modulesToCodeGen codegenModule)
124− js' <- generateMain env js
125− let pjs = unlines $ map ("// " ++) prefix ++ [P.prettyPrintJS js']
126− return (pjs, exts, env)
127−
128− where
129−
130− codegenModule :: (Functor n, Applicative n, MonadError P.MultipleErrors n, MonadWriter P.MultipleErrors n, MonadReader (P.Options P.Compile) n, MonadSupply n)
131− => CoreFn.Module CoreFn.Ann -> n [J.JS]
132− codegenModule m =
133− let requiresForeign = not $ null (CoreFn.moduleForeign m)
134− mn = CoreFn.moduleName m
135− in case mn `M.lookup` foreigns of
136− Just (path, js)
137− | not requiresForeign -> do
138− tell $ P.errorMessage $ P.UnnecessaryFFIModule mn path
139− J.moduleToJs m Nothing
140− | otherwise -> J.moduleToJs m $ Just $
141− J.JSApp (J.JSFunction Nothing [] $
142− J.JSBlock [ J.JSVariableIntroduction "exports" (Just $ J.JSObjectLiteral [])
143− , J.JSRaw js
144− , J.JSReturn (J.JSVar "exports")
145− ]) []
146− Nothing | requiresForeign -> throwError . P.errorMessage $ P.MissingFFIModule mn
147− | otherwise -> J.moduleToJs m Nothing
148−
149− generateMain :: P.Environment -> [J.JS] -> m [J.JS]
150− generateMain env js = do
151− mainName <- asks P.optionsMain
152− additional <- asks P.optionsAdditional
153− case P.moduleNameFromString <$> mainName of
154− Just mmi -> do
155− when ((mmi, P.Ident C.main) `M.notMember` P.names env) $
156− throwError . P.errorMessage $ P.NameIsUndefined (P.Ident C.main)
157− return $ js ++ [J.mainCall mmi (P.browserNamespace additional)]
158− _ -> return js
159−
160−-- |
161−-- Actions that require implementations when running in "make" mode.
162−--
163−data MakeActions m = MakeActions {
164− -- |
165− -- Get the timestamp for the input file(s) for a module. If there are multiple
166− -- files (.purs and foreign files, for example) the timestamp should be for
167− -- the most recently modified file.
168− --
169− getInputTimestamp :: ModuleName -> m (Either RebuildPolicy (Maybe UTCTime))
170− -- |
171− -- Get the timestamp for the output files for a module. This should be the
172− -- timestamp for the oldest modified file, or Nothing if any of the required
173− -- output files are missing.
174− --
175− , getOutputTimestamp :: ModuleName -> m (Maybe UTCTime)
176− -- |
177− -- Read the externs file for a module as a string and also return the actual
178− -- path for the file.
179− , readExterns :: ModuleName -> m (FilePath, String)
180− -- |
181− -- Run the code generator for the module and write any required output files.
182− --
183− , codegen :: CoreFn.Module CoreFn.Ann -> Environment -> SupplyVar -> Externs -> m ()
184− -- |
185− -- Respond to a progress update.
186− --
187− , progress :: String -> m ()
188− }
189−
190−-- |
191−-- Generated code for an externs file.
192−--
193−type Externs = String
194−
195−-- |
196−-- A value to be used in the Supply monad.
197−--
198−type SupplyVar = Integer
199−
200−-- |
201−-- Determines when to rebuild a module
202−--
203−data RebuildPolicy
204− -- | Never rebuild this module
205− = RebuildNever
206− -- | Always rebuild this module
207− | RebuildAlways deriving (Show, Eq, Ord)
208−
209−-- |
210−-- Compiles in "make" mode, compiling each module separately to a js files and an externs file
211−--
212−-- If timestamps have not changed, the externs file can be used to provide the module's types without
213−-- having to typecheck the module again.
214−--
215−make :: forall m. (Functor m, Applicative m, Monad m, MonadReader (P.Options P.Make) m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
216− => MakeActions m
217− -> [(Either RebuildPolicy FilePath, Module)]
218− -> m Environment
219−make MakeActions{..} ms = do
220− (sorted, graph) <- sortModules $ map (importPrim . snd) ms
221− mapM_ lint sorted
222− toRebuild <- foldM (\s (Module _ moduleName' _ _) -> do
223− inputTimestamp <- getInputTimestamp moduleName'
224− outputTimestamp <- getOutputTimestamp moduleName'
225− return $ case (inputTimestamp, outputTimestamp) of
226− (Right (Just t1), Just t2) | t1 < t2 -> s
227− (Left RebuildNever, Just _) -> s
228− _ -> S.insert moduleName' s) S.empty sorted
229−
230− marked <- rebuildIfNecessary (reverseDependencies graph) toRebuild sorted
231− (desugared, nextVar) <- runSupplyT 0 $ zip (map fst marked) <$> desugar (map snd marked)
232− evalSupplyT nextVar $ go initEnvironment desugared
233− where
234−
235− go :: Environment -> [(Bool, Module)] -> SupplyT m Environment
236− go env [] = return env
237− go env ((False, m) : ms') = do
238− (_, env') <- lift . runCheck' env $ typeCheckModule Nothing m
239− go env' ms'
240− go env ((True, m@(Module coms moduleName' _ exps)) : ms') = do
241− lift $ progress $ "Compiling " ++ runModuleName moduleName'
242− (Module _ _ elaborated _, env') <- lift . runCheck' env $ typeCheckModule Nothing m
243− regrouped <- createBindingGroups moduleName' . collapseBindingGroups $ elaborated
244− let mod' = Module coms moduleName' regrouped exps
245− corefn = CoreFn.moduleToCoreFn env' mod'
246− [renamed] = renameInModules [corefn]
247− exts = moduleToPs mod' env'
248− nextVar <- fresh
249− lift $ codegen renamed env' nextVar exts
250− go env' ms'
251−
252− rebuildIfNecessary :: M.Map ModuleName [ModuleName] -> S.Set ModuleName -> [Module] -> m [(Bool, Module)]
253− rebuildIfNecessary _ _ [] = return []
254− rebuildIfNecessary graph toRebuild (m@(Module _ moduleName' _ _) : ms') | moduleName' `S.member` toRebuild = do
255− let deps = fromMaybe [] $ moduleName' `M.lookup` graph
256− toRebuild' = toRebuild `S.union` S.fromList deps
257− (:) (True, m) <$> rebuildIfNecessary graph toRebuild' ms'
258− rebuildIfNecessary graph toRebuild (Module _ moduleName' _ _ : ms') = do
259− (path, externs) <- readExterns moduleName'
260− externsModules <- fmap (map snd) . alterErrors $ P.parseModulesFromFiles id [(path, externs)]
261− case externsModules of
262− [m'@(Module _ moduleName'' _ _)] | moduleName'' == moduleName' -> (:) (False, m') <$> rebuildIfNecessary graph toRebuild ms'
263− _ -> throwError . errorMessage . InvalidExternsFile $ path
264− where
265− alterErrors = flip catchError $ \(MultipleErrors errs) ->
266− throwError . MultipleErrors $ flip map errs $ \e -> case e of
267− SimpleErrorWrapper (ErrorParsingModule err) -> SimpleErrorWrapper (ErrorParsingExterns err)
268− _ -> e
269−
270−reverseDependencies :: ModuleGraph -> M.Map ModuleName [ModuleName]
271−reverseDependencies g = combine [ (dep, mn) | (mn, deps) <- g, dep <- deps ]
272− where
273− combine :: (Ord a) => [(a, b)] -> M.Map a [b]
274− combine = M.fromList . map ((fst . head) &&& map snd) . groupBy ((==) `on` fst) . sortBy (compare `on` fst)
275−
276−-- |
277−-- Add an import declaration for a module if it does not already explicitly import it.
278−--
279−addDefaultImport :: ModuleName -> Module -> Module
280−addDefaultImport toImport m@(Module coms mn decls exps) =
281− if isExistingImport `any` decls || mn == toImport then m
282− else Module coms mn (ImportDeclaration toImport Implicit Nothing : decls) exps
283− where
284− isExistingImport (ImportDeclaration mn' _ _) | mn' == toImport = True
285− isExistingImport (PositionedDeclaration _ _ d) = isExistingImport d
286− isExistingImport _ = False
287−
288−importPrim :: Module -> Module
289−importPrim = addDefaultImport (ModuleName [ProperName C.prim])
290−
291version :: Version
48version :: Version
292version = Paths.version
49version = Paths.version
src/Language/PureScript/AST/Binders.hs+1−1
@@ -69,7 +69,7 @@ data Binder
69 -- |
69 -- |
70 -- A binder with source position information
70 -- A binder with source position information
71 --
71 --
72− | PositionedBinder SourceSpan [Comment] Binder deriving (Show, D.Data, D.Typeable)
72+ | PositionedBinder SourceSpan [Comment] Binder deriving (Show, Eq, D.Data, D.Typeable)
73
73
74-- |
74-- |
75-- Collect all names introduced in binders in an expression
75-- Collect all names introduced in binders in an expression
src/Language/PureScript/AST/Declarations.hs+7−1
@@ -17,6 +17,7 @@
17module Language.PureScript.AST.Declarations where
17module Language.PureScript.AST.Declarations where
18
18
19import qualified Data.Data as D
19import qualified Data.Data as D
20+import qualified Data.Map as M
20
21
21import Language.PureScript.AST.Binders
22import Language.PureScript.AST.Binders
22import Language.PureScript.AST.Operators
23import Language.PureScript.AST.Operators
@@ -60,6 +61,10 @@ data DeclarationRef
60 --
61 --
61 | TypeInstanceRef Ident
62 | TypeInstanceRef Ident
62 -- |
63 -- |
64+ -- A module, in its entirety
65+ --
66+ | ModuleRef ModuleName
67+ -- |
63 -- A declaration reference with source position information
68 -- A declaration reference with source position information
64 --
69 --
65 | PositionedDeclarationRef SourceSpan [Comment] DeclarationRef
70 | PositionedDeclarationRef SourceSpan [Comment] DeclarationRef
@@ -70,6 +75,7 @@ instance Eq DeclarationRef where
70 (ValueRef name) == (ValueRef name') = name == name'
75 (ValueRef name) == (ValueRef name') = name == name'
71 (TypeClassRef name) == (TypeClassRef name') = name == name'
76 (TypeClassRef name) == (TypeClassRef name') = name == name'
72 (TypeInstanceRef name) == (TypeInstanceRef name') = name == name'
77 (TypeInstanceRef name) == (TypeInstanceRef name') = name == name'
78+ (ModuleRef name) == (ModuleRef name') = name == name'
73 (PositionedDeclarationRef _ _ r) == r' = r == r'
79 (PositionedDeclarationRef _ _ r) == r' = r == r'
74 r == (PositionedDeclarationRef _ _ r') = r == r'
80 r == (PositionedDeclarationRef _ _ r') = r == r'
75 _ == _ = False
81 _ == _ = False
@@ -360,7 +366,7 @@ data Expr
360 -- at superclass implementations when searching for a dictionary, the type class name and
366 -- at superclass implementations when searching for a dictionary, the type class name and
361 -- instance type, and the type class dictionaries in scope.
367 -- instance type, and the type class dictionaries in scope.
362 --
368 --
363− | TypeClassDictionary Bool Constraint [TypeClassDictionaryInScope]
369+ | TypeClassDictionary Bool Constraint (M.Map (Maybe ModuleName) (M.Map (Qualified ProperName) (M.Map (Qualified Ident) TypeClassDictionaryInScope)))
364 -- |
370 -- |
365 -- A typeclass dictionary accessor, the implementation is left unspecified until CoreFn desugaring.
371 -- A typeclass dictionary accessor, the implementation is left unspecified until CoreFn desugaring.
366 --
372 --
src/Language/PureScript/AST/Exported.hs+12−8
@@ -98,8 +98,10 @@ typeInstanceConstituents _ = []
98
98
99
99
100-- |
100-- |
101−-- Test if a declaration is exported, given a module's export list. Prefer
101+-- Test if a declaration is exported, given a module's export list. Note that
102+-- this function does not account for type instance declarations of
103+-- non-exported types, or non-exported data constructors. Therefore, you should
102−-- 'exportedDeclarations' to this function, where possible.
104+-- prefer 'exportedDeclarations' to this function, where possible.
103--
105--
104isExported :: Maybe [DeclarationRef] -> Declaration -> Bool
106isExported :: Maybe [DeclarationRef] -> Declaration -> Bool
105isExported Nothing _ = True
107isExported Nothing _ = True
@@ -107,13 +109,15 @@ isExported _ TypeInstanceDeclaration{} = True
107isExported exps (PositionedDeclaration _ _ d) = isExported exps d
109isExported exps (PositionedDeclaration _ _ d) = isExported exps d
108isExported (Just exps) decl = any (matches decl) exps
110isExported (Just exps) decl = any (matches decl) exps
109 where
111 where
110− matches (TypeDeclaration ident _) (ValueRef ident') = ident == ident'
112+ matches (TypeDeclaration ident _) (ValueRef ident') = ident == ident'
111− matches (ValueDeclaration ident _ _ _) (ValueRef ident') = ident == ident'
113+ matches (ValueDeclaration ident _ _ _) (ValueRef ident') = ident == ident'
112− matches (ExternDeclaration ident _) (ValueRef ident') = ident == ident'
114+ matches (ExternDeclaration ident _) (ValueRef ident') = ident == ident'
115+ matches (FixityDeclaration _ name) (ValueRef ident') = name == runIdent ident'
113− matches (DataDeclaration _ ident _ _) (TypeRef ident' _) = ident == ident'
116+ matches (DataDeclaration _ ident _ _) (TypeRef ident' _) = ident == ident'
114− matches (ExternDataDeclaration ident _) (TypeRef ident' _) = ident == ident'
117+ matches (ExternDataDeclaration ident _) (TypeRef ident' _) = ident == ident'
115− matches (TypeSynonymDeclaration ident _ _) (TypeRef ident' _) = ident == ident'
118+ matches (TypeSynonymDeclaration ident _ _) (TypeRef ident' _) = ident == ident'
116 matches (TypeClassDeclaration ident _ _ _) (TypeClassRef ident') = ident == ident'
119 matches (TypeClassDeclaration ident _ _ _) (TypeClassRef ident') = ident == ident'
120+
117 matches (PositionedDeclaration _ _ d) r = d `matches` r
121 matches (PositionedDeclaration _ _ d) r = d `matches` r
118 matches d (PositionedDeclarationRef _ _ r) = d `matches` r
122 matches d (PositionedDeclarationRef _ _ r) = d `matches` r
119 matches _ _ = False
123 matches _ _ = False
src/Language/PureScript/AST/Operators.hs+14−2
@@ -12,11 +12,14 @@
12--
12--
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
14
14
15+{-# LANGUAGE OverloadedStrings #-}
15{-# LANGUAGE DeriveDataTypeable #-}
16{-# LANGUAGE DeriveDataTypeable #-}
16
17
17module Language.PureScript.AST.Operators where
18module Language.PureScript.AST.Operators where
18
19
19import qualified Data.Data as D
20import qualified Data.Data as D
21+import Data.Aeson ((.=))
22+import qualified Data.Aeson as A
20
23
21-- |
24-- |
22-- A precedence level for an infix operator
25-- A precedence level for an infix operator
@@ -26,14 +29,23 @@ type Precedence = Integer
26-- |
29-- |
27-- Associativity for infix operators
30-- Associativity for infix operators
28--
31--
29−data Associativity = Infixl | Infixr | Infix deriving (D.Data, D.Typeable)
32+data Associativity = Infixl | Infixr | Infix deriving (Eq, Ord, D.Data, D.Typeable)
30
33
31instance Show Associativity where
34instance Show Associativity where
32 show Infixl = "infixl"
35 show Infixl = "infixl"
33 show Infixr = "infixr"
36 show Infixr = "infixr"
34 show Infix = "infix"
37 show Infix = "infix"
35
38
39+instance A.ToJSON Associativity where
40+ toJSON = A.toJSON . show
41+
36-- |
42-- |
37-- Fixity data for infix operators
43-- Fixity data for infix operators
38--
44--
39−data Fixity = Fixity Associativity Precedence deriving (Show, D.Data, D.Typeable)
45+data Fixity = Fixity Associativity Precedence deriving (Show, Eq, Ord, D.Data, D.Typeable)
46+
47+instance A.ToJSON Fixity where
48+ toJSON (Fixity associativity precedence) =
49+ A.object [ "associativity" .= associativity
50+ , "precedence" .= precedence
51+ ]
src/Language/PureScript/AST/SourcePos.hs+6−2
@@ -57,11 +57,15 @@ data SourceSpan = SourceSpan
57 , spanEnd :: SourcePos
57 , spanEnd :: SourcePos
58 } deriving (Eq, Ord, Show, D.Data, D.Typeable)
58 } deriving (Eq, Ord, Show, D.Data, D.Typeable)
59
59
60+displayStartEndPos :: SourceSpan -> String
61+displayStartEndPos sp =
62+ displaySourcePos (spanStart sp) ++ " - " ++
63+ displaySourcePos (spanEnd sp)
64+
60displaySourceSpan :: SourceSpan -> String
65displaySourceSpan :: SourceSpan -> String
61displaySourceSpan sp =
66displaySourceSpan sp =
62 spanName sp ++ " " ++
67 spanName sp ++ " " ++
63− displaySourcePos (spanStart sp) ++ " - " ++
68+ displayStartEndPos sp
64− displaySourcePos (spanEnd sp)
65
69
66instance A.ToJSON SourceSpan where
70instance A.ToJSON SourceSpan where
67 toJSON SourceSpan{..} =
71 toJSON SourceSpan{..} =
src/Language/PureScript/Bundle.hsnew file+545
@@ -0,0 +1,545 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : psc-bundle
4+-- Copyright : (c) Phil Freeman 2015
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- | Bundles compiled PureScript modules for the browser.
12+--
13+-- This module takes as input the individual generated modules from 'Language.PureScript.Make' and
14+-- performs dead code elimination, filters empty modules,
15+-- and generates the final Javascript bundle.
16+-----------------------------------------------------------------------------
17+
18+{-# LANGUAGE PatternGuards #-}
19+{-# LANGUAGE FlexibleContexts #-}
20+{-# LANGUAGE ScopedTypeVariables #-}
21+{-# LANGUAGE TupleSections #-}
22+{-# LANGUAGE RecordWildCards #-}
23+
24+module Language.PureScript.Bundle (
25+ bundle
26+ , ModuleIdentifier(..)
27+ , moduleName
28+ , ModuleType(..)
29+ , ErrorMessage(..)
30+ , printErrorMessage
31+) where
32+
33+import Data.List (nub)
34+import Data.Maybe (mapMaybe, catMaybes)
35+import Data.Generics (everything, everywhere, mkQ, mkT)
36+import Data.Graph
37+import Data.Version (showVersion)
38+
39+import qualified Data.Set as S
40+
41+import Control.Applicative
42+import Control.Monad
43+import Control.Monad.Error.Class
44+import Language.JavaScript.Parser
45+
46+import qualified Paths_purescript as Paths
47+
48+-- | The type of error messages. We separate generation and rendering of errors using a data
49+-- type, in case we need to match on error types later.
50+data ErrorMessage
51+ = UnsupportedModulePath String
52+ | InvalidTopLevel
53+ | UnableToParseModule String
54+ | UnsupportedExport
55+ | ErrorInModule ModuleIdentifier ErrorMessage
56+ deriving Show
57+
58+-- | Modules are either "regular modules" (i.e. those generated by psc) or foreign modules.
59+data ModuleType
60+ = Regular
61+ | Foreign
62+ deriving (Show, Eq, Ord)
63+
64+-- | A module is identified by its module name and its type.
65+data ModuleIdentifier = ModuleIdentifier String ModuleType deriving (Show, Eq, Ord)
66+
67+moduleName :: ModuleIdentifier -> String
68+moduleName (ModuleIdentifier name _) = name
69+
70+-- | A piece of code is identified by its module and its name. These keys are used to label vertices
71+-- in the dependency graph.
72+type Key = (ModuleIdentifier, String)
73+
74+-- | An export is either a "regular export", which exports a name from the regular module we are in,
75+-- or a reexport of a declaration in the corresponding foreign module.
76+--
77+-- Regular exports are labelled, since they might re-export an operator with another name.
78+data ExportType
79+ = RegularExport String
80+ | ForeignReexport
81+ deriving (Show, Eq, Ord)
82+
83+-- | There are four types of module element we are interested in:
84+--
85+-- 1) Require statements
86+-- 2) Member declarations
87+-- 3) Export lists
88+-- 4) Everything else
89+--
90+-- Each is labelled with the original AST node which generated it, so that we can dump it back
91+-- into the output during codegen.
92+data ModuleElement
93+ = Require JSNode String ModuleIdentifier
94+ | Member JSNode Bool String [JSNode] [Key]
95+ | ExportsList [(ExportType, String, JSNode, [Key])]
96+ | Other JSNode
97+ deriving Show
98+
99+-- | A module is just a list of elements of the types listed above.
100+data Module = Module ModuleIdentifier [ModuleElement] deriving Show
101+
102+-- | Prepare an error message for consumption by humans.
103+printErrorMessage :: ErrorMessage -> [String]
104+printErrorMessage (UnsupportedModulePath s) =
105+ [ "A CommonJS module has an unsupported name (" ++ show s ++ ")."
106+ , "The following file names are supported:"
107+ , " 1) index.js (psc native modules)"
108+ , " 2) foreign.js (psc foreign modules)"
109+ ]
110+printErrorMessage InvalidTopLevel =
111+ [ "Expected a list of source elements at the top level." ]
112+printErrorMessage (UnableToParseModule err) =
113+ [ "The module could not be parsed:"
114+ , err
115+ ]
116+printErrorMessage UnsupportedExport =
117+ [ "An export was unsupported. Exports can be defined in one of two ways: "
118+ , " 1) exports.name = ..."
119+ , " 2) exports = { ... }"
120+ ]
121+printErrorMessage (ErrorInModule mid e) =
122+ ("Error in module " ++ displayIdentifier mid ++ ":")
123+ : ""
124+ : map (" " ++) (printErrorMessage e)
125+ where
126+ displayIdentifier (ModuleIdentifier name ty) =
127+ name ++ " (" ++ show ty ++ ")"
128+
129+-- | Unpack the node inside a JSNode. This is useful when pattern matching.
130+node :: JSNode -> Node
131+node (NN n) = n
132+node (NT n _ _) = n
133+
134+-- | Calculate the ModuleIdentifier which a require(...) statement imports.
135+checkImportPath :: String -> ModuleIdentifier -> S.Set String -> Maybe ModuleIdentifier
136+checkImportPath "./foreign" m _ =
137+ Just (ModuleIdentifier (moduleName m) Foreign)
138+checkImportPath name _ names
139+ | name `S.member` names = Just (ModuleIdentifier name Regular)
140+checkImportPath _ _ _ = Nothing
141+
142+-- | Compute the dependencies of all elements in a module, and add them to the tree.
143+--
144+-- Members and exports can have dependencies. A dependency is of one of the following forms:
145+--
146+-- 1) module.name or member["name"]
147+--
148+-- where module was imported using
149+--
150+-- var module = require("Module.Name");
151+--
152+-- 2) name
153+--
154+-- where name is the name of a member defined in the current module.
155+withDeps :: Module -> Module
156+withDeps (Module modulePath es) = Module modulePath (map expandDeps es)
157+ where
158+ -- | Collects all modules which are imported, so that we can identify dependencies of the first type.
159+ imports :: [(String, ModuleIdentifier)]
160+ imports = mapMaybe toImport es
161+ where
162+ toImport :: ModuleElement -> Maybe (String, ModuleIdentifier)
163+ toImport (Require _ nm mid) = Just (nm, mid)
164+ toImport _ = Nothing
165+
166+ -- | Collects all member names in scope, so that we can identify dependencies of the second type.
167+ boundNames :: [String]
168+ boundNames = mapMaybe toBoundName es
169+ where
170+ toBoundName :: ModuleElement -> Maybe String
171+ toBoundName (Member _ _ nm _ _) = Just nm
172+ toBoundName _ = Nothing
173+
174+ -- | Calculate dependencies and add them to the current element.
175+ expandDeps :: ModuleElement -> ModuleElement
176+ expandDeps (Member n f nm decl _) = Member n f nm decl (nub (concatMap (dependencies modulePath) decl))
177+ expandDeps (ExportsList exps) = ExportsList (map expand exps)
178+ where
179+ expand (ty, nm, n1, _) = (ty, nm, n1, nub (dependencies modulePath n1))
180+ expandDeps other = other
181+
182+ dependencies :: ModuleIdentifier -> JSNode -> [(ModuleIdentifier, String)]
183+ dependencies m = everything (++) (mkQ [] toReference)
184+ where
185+ toReference :: Node -> [(ModuleIdentifier, String)]
186+ toReference (JSMemberDot [ mn ] _ nm)
187+ | JSIdentifier mn' <- node mn
188+ , JSIdentifier nm' <- node nm
189+ , Just mid <- lookup mn' imports
190+ = [(mid, nm')]
191+ toReference (JSMemberSquare [ mn ] _ nm _)
192+ | JSIdentifier mn' <- node mn
193+ , JSExpression [ s ] <- node nm
194+ , JSStringLiteral _ nm' <- node s
195+ , Just mid <- lookup mn' imports
196+ = [(mid, nm')]
197+ toReference (JSIdentifier nm)
198+ | nm `elem` boundNames
199+ = [(m, nm)]
200+ toReference _ = []
201+
202+-- | Attempt to create a Module from a Javascript AST.
203+--
204+-- Each type of module element is matched using pattern guards, and everything else is bundled into the
205+-- Other constructor.
206+toModule :: forall m. (Applicative m, MonadError ErrorMessage m) => S.Set String -> ModuleIdentifier -> JSNode -> m Module
207+toModule mids mid top
208+ | JSSourceElementsTop ns <- node top = Module mid <$> mapM toModuleElement ns
209+ | otherwise = err InvalidTopLevel
210+ where
211+ err = throwError . ErrorInModule mid
212+
213+ toModuleElement :: JSNode -> m ModuleElement
214+ toModuleElement n
215+ | JSVariables var [ varIntro ] _ <- node n
216+ , JSLiteral "var" <- node var
217+ , JSVarDecl impN [ eq, req, impP ] <- node varIntro
218+ , JSIdentifier importName <- node impN
219+ , JSLiteral "=" <- node eq
220+ , JSIdentifier "require" <- node req
221+ , JSArguments _ [ impS ] _ <- node impP
222+ , JSStringLiteral _ importPath <- node impS
223+ , Just importPath' <- checkImportPath importPath mid mids
224+ = pure (Require n importName importPath')
225+ toModuleElement n
226+ | JSVariables var [ varIntro ] _ <- node n
227+ , JSLiteral "var" <- node var
228+ , JSVarDecl declN (eq : decl) <- node varIntro
229+ , JSIdentifier name <- node declN
230+ , JSLiteral "=" <- node eq
231+ = pure (Member n False name decl [])
232+ toModuleElement n
233+ | JSExpression (e : op : decl) <- node n
234+ , Just name <- accessor (node e)
235+ , JSOperator eq <- node op
236+ , JSLiteral "=" <- node eq
237+ = pure (Member n True name decl [])
238+ where
239+ accessor :: Node -> Maybe String
240+ accessor (JSMemberDot [ exports ] _ nm)
241+ | JSIdentifier "exports" <- node exports
242+ , JSIdentifier name <- node nm
243+ = Just name
244+ accessor (JSMemberSquare [ exports ] _ nm _)
245+ | JSIdentifier "exports" <- node exports
246+ , JSExpression [e] <- node nm
247+ , JSStringLiteral _ name <- node e
248+ = Just name
249+ accessor _ = Nothing
250+ toModuleElement n
251+ | JSExpression (mnExp : op : obj: _) <- node n
252+ , JSMemberDot [ mn ] _ e <- node mnExp
253+ , JSIdentifier "module" <- node mn
254+ , JSIdentifier "exports" <- node e
255+ , JSOperator eq <- node op
256+ , JSLiteral "=" <- node eq
257+ , JSObjectLiteral _ props _ <- node obj
258+ = ExportsList <$> mapM toExport (filter (not . isSeparator) (map node props))
259+ where
260+ toExport :: Node -> m (ExportType, String, JSNode, [Key])
261+ toExport (JSPropertyNameandValue name _ [val] ) =
262+ (,,val,[]) <$> exportType (node val)
263+ <*> extractLabel (node name)
264+ toExport _ = err UnsupportedExport
265+
266+ exportType :: Node -> m ExportType
267+ exportType (JSMemberDot [f] _ _)
268+ | JSIdentifier "$foreign" <- node f
269+ = pure ForeignReexport
270+ exportType (JSMemberSquare [f] _ _ _)
271+ | JSIdentifier "$foreign" <- node f
272+ = pure ForeignReexport
273+ exportType (JSIdentifier s) = pure (RegularExport s)
274+ exportType _ = err UnsupportedExport
275+
276+ extractLabel :: Node -> m String
277+ extractLabel (JSStringLiteral _ nm) = pure nm
278+ extractLabel (JSIdentifier nm) = pure nm
279+ extractLabel _ = err UnsupportedExport
280+
281+ isSeparator :: Node -> Bool
282+ isSeparator (JSLiteral ",") = True
283+ isSeparator _ = False
284+ toModuleElement other = pure (Other other)
285+
286+-- | Eliminate unused code based on the specified entry point set.
287+compile :: [Module] -> [ModuleIdentifier] -> [Module]
288+compile modules [] = modules
289+compile modules entryPoints = filteredModules
290+ where
291+ (graph, _, vertexFor) = graphFromEdges verts
292+
293+ -- | The vertex set
294+ verts :: [(ModuleElement, Key, [Key])]
295+ verts = do
296+ Module mid els <- modules
297+ concatMap (toVertices mid) els
298+ where
299+ -- | Create a set of vertices for a module element.
300+ --
301+ -- Some special cases worth commenting on:
302+ --
303+ -- 1) Regular exports which simply export their own name do not count as dependencies.
304+ -- Regular exports which rename and reexport an operator do count, however.
305+ --
306+ -- 2) Require statements don't contribute towards dependencies, since they effectively get
307+ -- inlined wherever they are used inside other module elements.
308+ toVertices :: ModuleIdentifier -> ModuleElement -> [(ModuleElement, Key, [Key])]
309+ toVertices p m@(Member _ _ nm _ deps) = [(m, (p, nm), deps)]
310+ toVertices p m@(ExportsList exps) = mapMaybe toVertex exps
311+ where
312+ toVertex (ForeignReexport, nm, _, ks) = Just (m, (p, nm), ks)
313+ toVertex (RegularExport nm, nm1, _, ks) | nm /= nm1 = Just (m, (p, nm1), ks)
314+ toVertex _ = Nothing
315+ toVertices _ _ = []
316+
317+ -- | The set of vertices whose connected components we are interested in keeping.
318+ entryPointVertices :: [Vertex]
319+ entryPointVertices = catMaybes $ do
320+ (_, k@(mid, _), _) <- verts
321+ guard $ mid `elem` entryPoints
322+ return (vertexFor k)
323+
324+ -- | The set of vertices reachable from an entry point
325+ reachableSet :: S.Set Vertex
326+ reachableSet = S.fromList (concatMap (reachable graph) entryPointVertices)
327+
328+ filteredModules :: [Module]
329+ filteredModules = map filterUsed modules
330+ where
331+ filterUsed :: Module -> Module
332+ filterUsed (Module mid ds) = Module mid (map filterExports (go ds))
333+ where
334+ go :: [ModuleElement] -> [ModuleElement]
335+ go [] = []
336+ go (d : Other semi : rest)
337+ | JSLiteral ";" <- node semi
338+ , not (isDeclUsed d)
339+ = go rest
340+ go (d : rest)
341+ | not (isDeclUsed d) = go rest
342+ | otherwise = d : go rest
343+
344+ -- | Filter out the exports for members which aren't used.
345+ filterExports :: ModuleElement -> ModuleElement
346+ filterExports (ExportsList exps) = ExportsList (filter (\(_, nm, _, _) -> isKeyUsed (mid, nm)) exps)
347+ filterExports me = me
348+
349+ isDeclUsed :: ModuleElement -> Bool
350+ isDeclUsed (Member _ _ nm _ _) = isKeyUsed (mid, nm)
351+ isDeclUsed _ = True
352+
353+ isKeyUsed :: Key -> Bool
354+ isKeyUsed k
355+ | Just me <- vertexFor k = me `S.member` reachableSet
356+ | otherwise = False
357+
358+-- | Topologically sort the module dependency graph, so that when we generate code, modules can be
359+-- defined in the right order.
360+sortModules :: [Module] -> [Module]
361+sortModules modules = map (\v -> case nodeFor v of (n, _, _) -> n) (reverse (topSort graph))
362+ where
363+ (graph, nodeFor, _) = graphFromEdges $ do
364+ m@(Module mid els) <- modules
365+ return (m, mid, mapMaybe getKey els)
366+
367+ getKey :: ModuleElement -> Maybe ModuleIdentifier
368+ getKey (Require _ _ mi) = Just mi
369+ getKey _ = Nothing
370+
371+-- | A module is empty if it contains no exported members (in other words,
372+-- if the only things left after dead code elimination are module imports and
373+-- "other" foreign code).
374+--
375+-- If a module is empty, we don't want to generate code for it.
376+isModuleEmpty :: Module -> Bool
377+isModuleEmpty (Module _ els) = all isElementEmpty els
378+ where
379+ isElementEmpty :: ModuleElement -> Bool
380+ isElementEmpty (ExportsList exps) = null exps
381+ isElementEmpty (Require _ _ _) = True
382+ isElementEmpty (Other _) = True
383+ isElementEmpty _ = False
384+
385+-- | Generate code for a set of modules, including a call to main().
386+--
387+-- Modules get defined on the global PS object, as follows:
388+--
389+-- var PS = { };
390+-- (function(exports) {
391+-- ...
392+-- })(PS["Module.Name"] = PS["Module.Name"] || {});
393+--
394+-- In particular, a module and its foreign imports share the same namespace inside PS.
395+-- This saves us from having to generate unique names for a module and its foreign imports,
396+-- and is safe since a module shares a namespace with its foreign imports in PureScript as well
397+-- (so there is no way to have overlaps in code generated by psc).
398+codeGen :: Maybe String -- ^ main module
399+ -> String -- ^ namespace
400+ -> [Module] -- ^ input modules
401+ -> String
402+codeGen optionsMainModule optionsNamespace ms = renderToString (NN (JSSourceElementsTop (prelude ++ concatMap moduleToJS ms ++ maybe [] runMain optionsMainModule)))
403+ where
404+ moduleToJS :: Module -> [JSNode]
405+ moduleToJS (Module mn ds) = wrap (moduleName mn) (indent (concatMap declToJS ds))
406+ where
407+ declToJS :: ModuleElement -> [JSNode]
408+ declToJS (Member n _ _ _ _) = [n]
409+ declToJS (Other n) = [n]
410+ declToJS (Require _ nm req) =
411+ [ NN (JSVariables (NT (JSLiteral "var") tokenPosnEmpty [ WhiteSpace tokenPosnEmpty "\n " ])
412+ [ NN (JSVarDecl (sp (JSIdentifier nm))
413+ [ sp (JSLiteral "=")
414+ , moduleReference sp (moduleName req)
415+ ])
416+ ]
417+ (nt (JSLiteral ";"))) ]
418+ declToJS (ExportsList exps) = map toExport exps
419+
420+ where
421+ toExport :: (ExportType, String, JSNode, [Key]) -> JSNode
422+ toExport (_, nm, val, _) =
423+ NN (JSExpression [ NN (JSMemberSquare [ NT (JSIdentifier "exports") tokenPosnEmpty [ WhiteSpace tokenPosnEmpty "\n " ] ]
424+ (nt (JSLiteral "["))
425+ (NN (JSExpression [ nt (JSStringLiteral '"' nm) ]))
426+ (nt (JSLiteral "]")))
427+ , NN (JSOperator (sp (JSLiteral "=")))
428+ , reindent val
429+ , nt (JSLiteral ";")
430+ ])
431+
432+ reindent :: JSNode -> JSNode
433+ reindent (NT n _ _) = sp n
434+ reindent nn = nn
435+
436+ indent :: [JSNode] -> [JSNode]
437+ indent = everywhere (mkT squash)
438+ where
439+ squash (NT n pos ann) = NT n (keepCol pos) (map splat ann)
440+ squash nn = nn
441+
442+ splat (CommentA pos s) = CommentA (keepCol pos) s
443+ splat (WhiteSpace pos w) = WhiteSpace (keepCol pos) w
444+ splat ann = ann
445+
446+ keepCol (TokenPn _ _ c) = TokenPn 0 0 (c + 2)
447+
448+ prelude :: [JSNode]
449+ prelude =
450+ [ NN (JSVariables (NT (JSLiteral "var") tokenPosnEmpty [ CommentA tokenPosnEmpty ("// Generated by psc-bundle " ++ showVersion Paths.version)
451+ , WhiteSpace tokenPosnEmpty "\n"
452+ ])
453+ [ NN (JSVarDecl (sp (JSIdentifier optionsNamespace))
454+ [ sp (JSLiteral "=")
455+ , NN (JSObjectLiteral (sp (JSLiteral "{"))
456+ []
457+ (sp (JSLiteral "}")))
458+ ])
459+ ]
460+ (nt (JSLiteral ";")))
461+ , lf
462+ ]
463+
464+ moduleReference :: (Node -> JSNode) -> String -> JSNode
465+ moduleReference f mn =
466+ NN (JSMemberSquare [ f (JSIdentifier optionsNamespace) ]
467+ (nt (JSLiteral "["))
468+ (NN (JSExpression [ nt (JSStringLiteral '"' mn) ]))
469+ (nt (JSLiteral "]")))
470+
471+ wrap :: String -> [JSNode] -> [JSNode]
472+ wrap mn ds =
473+ [ NN (JSExpression [ NN (JSExpressionParen (nt (JSLiteral "("))
474+ (NN (JSExpression [ NN (JSFunctionExpression (nt (JSLiteral "function"))
475+ []
476+ (nt (JSLiteral "(") ) [nt (JSIdentifier "exports")] (nt (JSLiteral ")"))
477+ (NN (JSBlock [sp (JSLiteral "{")]
478+ (lf : ds)
479+ [nl (JSLiteral "}")])))]))
480+ (nt (JSLiteral ")")))
481+ , NN (JSArguments (nt (JSLiteral "("))
482+ [ NN (JSExpression [ moduleReference nt mn
483+ , NN (JSOperator (sp (JSLiteral "=")))
484+ , NN (JSExpressionBinary "||"
485+ [ moduleReference sp mn ]
486+ (sp (JSLiteral "||"))
487+ [ emptyObj ])
488+ ])
489+ ]
490+ (nt (JSLiteral ")")))
491+ ])
492+ , nt (JSLiteral ";")
493+ , lf
494+ ]
495+ where
496+ emptyObj = NN (JSObjectLiteral (sp (JSLiteral "{")) [] (nt (JSLiteral "}")))
497+
498+ runMain :: String -> [JSNode]
499+ runMain mn =
500+ [ NN (JSExpression [ NN (JSMemberDot [ NN (JSMemberSquare [ nl (JSIdentifier optionsNamespace) ]
501+ (nt (JSLiteral "["))
502+ (NN (JSExpression [ nt (JSStringLiteral '"' mn) ]))
503+ (nt (JSLiteral "]")))
504+ ]
505+ (nt (JSLiteral "."))
506+ (nt (JSIdentifier "main")))
507+ , NN (JSArguments (nt (JSLiteral "(")) [] (nt (JSLiteral ")")))
508+ ])
509+ , nt (JSLiteral ";")
510+ ]
511+
512+ nt :: Node -> JSNode
513+ nt n = NT n tokenPosnEmpty []
514+
515+ lf :: JSNode
516+ lf = NT (JSLiteral "") tokenPosnEmpty [ WhiteSpace tokenPosnEmpty "\n" ]
517+
518+ sp :: Node -> JSNode
519+ sp n = NT n tokenPosnEmpty [ WhiteSpace tokenPosnEmpty " " ]
520+
521+ nl :: Node -> JSNode
522+ nl n = NT n tokenPosnEmpty [ WhiteSpace tokenPosnEmpty "\n" ]
523+
524+-- | The bundling function.
525+-- This function performs dead code elimination, filters empty modules
526+-- and generates and prints the final Javascript bundle.
527+bundle :: forall m. (Applicative m, MonadError ErrorMessage m)
528+ => [(ModuleIdentifier, String)] -- ^ The input modules. Each module should be javascript rendered from 'Language.PureScript.Make' or @psc@.
529+ -> [ModuleIdentifier] -- ^ Entry points. These module identifiers are used as the roots for dead-code elimination
530+ -> Maybe String -- ^ An optional main module.
531+ -> String -- ^ The namespace (e.g. PS).
532+ -> m String
533+bundle inputStrs entryPoints mainModule namespace = do
534+ input <- forM inputStrs $ \(ident, js) -> do
535+ ast <- either (throwError . ErrorInModule ident . UnableToParseModule) pure $ parse js (moduleName ident)
536+ return (ident, ast)
537+
538+ let mids = S.fromList (map (moduleName . fst) input)
539+
540+ modules <- mapM (fmap withDeps . uncurry (toModule mids)) input
541+
542+ let compiled = compile modules entryPoints
543+ sorted = sortModules (filter (not . isModuleEmpty) compiled)
544+
545+ return (codeGen mainModule namespace sorted)
src/Language/PureScript/CodeGen/Externs.hs+17−2
@@ -38,11 +38,24 @@ import Language.PureScript.Types
38moduleToPs :: Module -> Environment -> String
38moduleToPs :: Module -> Environment -> String
39moduleToPs (Module _ _ _ Nothing) _ = error "Module exports were not elaborated in moduleToPs"
39moduleToPs (Module _ _ _ Nothing) _ = error "Module exports were not elaborated in moduleToPs"
40moduleToPs (Module _ moduleName ds (Just exts)) env = intercalate "\n" . execWriter $ do
40moduleToPs (Module _ moduleName ds (Just exts)) env = intercalate "\n" . execWriter $ do
41+ let exps = listExports exts
41− tell [ "module " ++ runModuleName moduleName ++ " where"]
42+ tell ["module " ++ runModuleName moduleName ++ (if null exps then "" else " (" ++ exps ++ ")") ++ " where"]
42 mapM_ declToPs ds
43 mapM_ declToPs ds
43 mapM_ exportToPs exts
44 mapM_ exportToPs exts
44 where
45 where
45
46
47+ listExports :: [DeclarationRef] -> String
48+ listExports = intercalate ", " . mapMaybe listExport
49+
50+ listExport :: DeclarationRef -> Maybe String
51+ listExport (PositionedDeclarationRef _ _ d) = listExport d
52+ listExport (TypeRef name Nothing) = Just $ show name ++ "()"
53+ listExport (TypeRef name (Just dctors)) = Just $ show name ++ "(" ++ intercalate ", " (map show dctors) ++ ")"
54+ listExport (ValueRef name) = Just $ show name
55+ listExport (TypeClassRef name) = Just $ show name
56+ listExport (ModuleRef name) = Just $ "module " ++ show name
57+ listExport _ = Nothing
58+
46 declToPs :: Declaration -> Writer [String] ()
59 declToPs :: Declaration -> Writer [String] ()
47 declToPs (ImportDeclaration mn _ _) = tell ["import " ++ show mn ++ " ()"]
60 declToPs (ImportDeclaration mn _ _) = tell ["import " ++ show mn ++ " ()"]
48 declToPs (FixityDeclaration (Fixity assoc prec) op) =
61 declToPs (FixityDeclaration (Fixity assoc prec) op) =
@@ -107,12 +120,14 @@ moduleToPs (Module _ moduleName ds (Just exts)) env = intercalate "\n" . execWri
107
120
108 exportToPs (TypeInstanceRef ident) = do
121 exportToPs (TypeInstanceRef ident) = do
109 let TypeClassDictionaryInScope { tcdClassName = className, tcdInstanceTypes = tys, tcdDependencies = deps} =
122 let TypeClassDictionaryInScope { tcdClassName = className, tcdInstanceTypes = tys, tcdDependencies = deps} =
110− fromMaybe (error $ "Type class instance has no dictionary in exportToPs") . find (\tcd -> tcdName tcd == Qualified (Just moduleName) ident && tcdType tcd == TCDRegular) $ M.elems $ typeClassDictionaries env
123+ fromMaybe (error $ "Type class instance has no dictionary in exportToPs") . find (\tcd -> tcdName tcd == Qualified (Just moduleName) ident && tcdType tcd == TCDRegular) . maybe [] (M.elems >=> M.elems) . M.lookup (Just moduleName) $ typeClassDictionaries env
111 let constraintsText = case fromMaybe [] deps of
124 let constraintsText = case fromMaybe [] deps of
112 [] -> ""
125 [] -> ""
113 cs -> "(" ++ intercalate ", " (map (\(pn, tys') -> show pn ++ " " ++ unwords (map prettyPrintTypeAtom tys')) cs) ++ ") => "
126 cs -> "(" ++ intercalate ", " (map (\(pn, tys') -> show pn ++ " " ++ unwords (map prettyPrintTypeAtom tys')) cs) ++ ") => "
114 tell ["foreign import instance " ++ show ident ++ " :: " ++ constraintsText ++ show className ++ " " ++ unwords (map prettyPrintTypeAtom tys)]
127 tell ["foreign import instance " ++ show ident ++ " :: " ++ constraintsText ++ show className ++ " " ++ unwords (map prettyPrintTypeAtom tys)]
115
128
129+ exportToPs (ModuleRef _) = return ()
130+
116 toTypeVar :: (String, Maybe Kind) -> Type
131 toTypeVar :: (String, Maybe Kind) -> Type
117 toTypeVar (s, Nothing) = TypeVar s
132 toTypeVar (s, Nothing) = TypeVar s
118 toTypeVar (s, Just k) = KindedType (TypeVar s) k
133 toTypeVar (s, Just k) = KindedType (TypeVar s) k
src/Language/PureScript/CodeGen/JS.hs+7−17
@@ -44,18 +44,18 @@ import Language.PureScript.Options
44import Language.PureScript.Traversals (sndM)
44import Language.PureScript.Traversals (sndM)
45import qualified Language.PureScript.Constants as C
45import qualified Language.PureScript.Constants as C
46
46
47+import System.FilePath.Posix ((</>))
48+
47-- |
49-- |
48-- Generate code in the simplified Javascript intermediate representation for all declarations in a
50-- Generate code in the simplified Javascript intermediate representation for all declarations in a
49-- module.
51-- module.
50--
52--
51−moduleToJs :: forall m mode. (Applicative m, Monad m, MonadReader (Options mode) m, MonadSupply m)
53+moduleToJs :: forall m. (Applicative m, Monad m, MonadReader Options m, MonadSupply m)
52 => Module Ann -> Maybe JS -> m [JS]
54 => Module Ann -> Maybe JS -> m [JS]
53moduleToJs (Module coms mn imps exps foreigns decls) foreign = do
55moduleToJs (Module coms mn imps exps foreigns decls) foreign = do
54− additional <- asks optionsAdditional
55 jsImports <- T.traverse importToJs . delete (ModuleName [ProperName C.prim]) . (\\ [mn]) $ imps
56 jsImports <- T.traverse importToJs . delete (ModuleName [ProperName C.prim]) . (\\ [mn]) $ imps
56 jsDecls <- mapM bindToJs decls
57 jsDecls <- mapM bindToJs decls
57 optimized <- T.traverse (T.traverse optimize) jsDecls
58 optimized <- T.traverse (T.traverse optimize) jsDecls
58− let isModuleEmpty = null exps
59 comments <- not <$> asks optionsNoComments
59 comments <- not <$> asks optionsNoComments
60 let strict = JSStringLiteral "use strict"
60 let strict = JSStringLiteral "use strict"
61 let header = if comments && not (null coms) then JSComment coms strict else strict
61 let header = if comments && not (null coms) then JSComment coms strict else strict
@@ -65,15 +65,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign = do
65 let standardExps = exps \\ foreignExps
65 let standardExps = exps \\ foreignExps
66 let exps' = JSObjectLiteral $ map (runIdent &&& JSVar . identToJs) standardExps
66 let exps' = JSObjectLiteral $ map (runIdent &&& JSVar . identToJs) standardExps
67 ++ map (runIdent &&& foreignIdent) foreignExps
67 ++ map (runIdent &&& foreignIdent) foreignExps
68− return $ case additional of
69− MakeOptions -> moduleBody ++ [JSAssignment (JSAccessor "exports" (JSVar "module")) exps']
68+ return $ moduleBody ++ [JSAssignment (JSAccessor "exports" (JSVar "module")) exps']
70− CompileOptions ns _ _ | not isModuleEmpty ->
71− [ JSVariableIntroduction ns
72− (Just (JSBinary Or (JSVar ns) (JSObjectLiteral [])) )
73− , JSAssignment (JSAccessor (moduleNameToJs mn) (JSVar ns))
74− (JSApp (JSFunction Nothing [] (JSBlock (moduleBody ++ [JSReturn exps']))) [])
75− ]
76− _ -> []
77
69
78 where
70 where
79
71
@@ -82,10 +74,8 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign = do
82 --
74 --
83 importToJs :: ModuleName -> m JS
75 importToJs :: ModuleName -> m JS
84 importToJs mn' = do
76 importToJs mn' = do
85− additional <- asks optionsAdditional
77+ path <- asks optionsRequirePath
86− let moduleBody = case additional of
87− MakeOptions -> JSApp (JSVar "require") [JSStringLiteral (runModuleName mn')]
78+ let moduleBody = JSApp (JSVar "require") [JSStringLiteral (maybe id (</>) path $ runModuleName mn')]
88− CompileOptions ns _ _ -> JSAccessor (moduleNameToJs mn') (JSVar ns)
89 return $ JSVariableIntroduction (moduleNameToJs mn') (Just moduleBody)
79 return $ JSVariableIntroduction (moduleNameToJs mn') (Just moduleBody)
90
80
91 -- |
81 -- |
@@ -284,7 +274,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign = do
284 failedPatternError names = JSUnary JSNew $ JSApp (JSVar "Error") [JSBinary Add (JSStringLiteral errorMessage) (JSArrayLiteral $ zipWith valueError names vals)]
274 failedPatternError names = JSUnary JSNew $ JSApp (JSVar "Error") [JSBinary Add (JSStringLiteral errorMessage) (JSArrayLiteral $ zipWith valueError names vals)]
285
275
286 errorMessage :: String
276 errorMessage :: String
287− errorMessage = "Failed pattern match" ++ maybe "" ((" at " ++) . displaySourceSpan) maybeSpan ++ ": "
277+ errorMessage = "Failed pattern match" ++ maybe "" (((" at " ++ runModuleName mn ++ " ") ++) . displayStartEndPos) maybeSpan ++ ": "
288
278
289 valueError :: String -> JS -> JS
279 valueError :: String -> JS -> JS
290 valueError _ l@(JSNumericLiteral _) = l
280 valueError _ l@(JSNumericLiteral _) = l
src/Language/PureScript/CodeGen/JS/AST.hs+2−1
@@ -23,6 +23,7 @@ import Data.Data
23import Data.Traversable (traverse)
23import Data.Traversable (traverse)
24
24
25import Language.PureScript.Comments
25import Language.PureScript.Comments
26+import Language.PureScript.Traversals
26
27
27-- |
28-- |
28-- Built-in unary operators
29-- Built-in unary operators
@@ -294,7 +295,7 @@ everywhereOnJSTopDownM f = f >=> go
294 go (JSBinary op j1 j2) = JSBinary op <$> f' j1 <*> f' j2
295 go (JSBinary op j1 j2) = JSBinary op <$> f' j1 <*> f' j2
295 go (JSArrayLiteral js) = JSArrayLiteral <$> traverse f' js
296 go (JSArrayLiteral js) = JSArrayLiteral <$> traverse f' js
296 go (JSIndexer j1 j2) = JSIndexer <$> f' j1 <*> f' j2
297 go (JSIndexer j1 j2) = JSIndexer <$> f' j1 <*> f' j2
297− go (JSObjectLiteral js) = JSObjectLiteral <$> traverse (traverse f') js
298+ go (JSObjectLiteral js) = JSObjectLiteral <$> traverse (sndM f') js
298 go (JSAccessor prop j) = JSAccessor prop <$> f' j
299 go (JSAccessor prop j) = JSAccessor prop <$> f' j
299 go (JSFunction name args j) = JSFunction name args <$> f' j
300 go (JSFunction name args j) = JSFunction name args <$> f' j
300 go (JSApp j js) = JSApp <$> f' j <*> traverse f' js
301 go (JSApp j js) = JSApp <$> f' j <*> traverse f' js
src/Language/PureScript/CodeGen/JS/Optimizer.hs+2−2
@@ -55,12 +55,12 @@ import Language.PureScript.CodeGen.JS.Optimizer.Blocks
55-- |
55-- |
56-- Apply a series of optimizer passes to simplified Javascript code
56-- Apply a series of optimizer passes to simplified Javascript code
57--
57--
58−optimize :: (Monad m, MonadReader (Options mode) m, Applicative m, MonadSupply m) => JS -> m JS
58+optimize :: (Monad m, MonadReader Options m, Applicative m, MonadSupply m) => JS -> m JS
59optimize js = do
59optimize js = do
60 noOpt <- asks optionsNoOptimizations
60 noOpt <- asks optionsNoOptimizations
61 if noOpt then return js else optimize' js
61 if noOpt then return js else optimize' js
62
62
63−optimize' :: (Monad m, MonadReader (Options mode) m, Applicative m, MonadSupply m) => JS -> m JS
63+optimize' :: (Monad m, MonadReader Options m, Applicative m, MonadSupply m) => JS -> m JS
64optimize' js = do
64optimize' js = do
65 opts <- ask
65 opts <- ask
66 untilFixedPoint (inlineArrComposition . applyAll
66 untilFixedPoint (inlineArrComposition . applyAll
src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs+12−15
@@ -156,11 +156,11 @@ inlineCommonOperators = applyAll $
156 , binary semigroupString (C.<>) Add
156 , binary semigroupString (C.<>) Add
157 , binary semigroupString (C.++) Add
157 , binary semigroupString (C.++) Add
158
158
159− , binary latticeBoolean (C.&&) And
159+ , binary booleanAlgebraBoolean (C.&&) And
160− , binary latticeBoolean (C.||) Or
160+ , binary booleanAlgebraBoolean (C.||) Or
161− , binaryFunction latticeBoolean C.inf And
161+ , binaryFunction booleanAlgebraBoolean C.conj And
162− , binaryFunction latticeBoolean C.sup Or
162+ , binaryFunction booleanAlgebraBoolean C.disj Or
163− , unary complementedLatticeBoolean C.not Not
163+ , unary booleanAlgebraBoolean C.not Not
164
164
165 , binary' C.dataIntBits (C..|.) BitwiseOr
165 , binary' C.dataIntBits (C..|.) BitwiseOr
166 , binary' C.dataIntBits (C..&.) BitwiseAnd
166 , binary' C.dataIntBits (C..&.) BitwiseAnd
@@ -269,25 +269,25 @@ semiringNumber :: (String, String)
269semiringNumber = (C.prelude, C.semiringNumber)
269semiringNumber = (C.prelude, C.semiringNumber)
270
270
271semiringInt :: (String, String)
271semiringInt :: (String, String)
272−semiringInt = (C.dataInt, C.semiringInt)
272+semiringInt = (C.prelude, C.semiringInt)
273
273
274ringNumber :: (String, String)
274ringNumber :: (String, String)
275ringNumber = (C.prelude, C.ringNumber)
275ringNumber = (C.prelude, C.ringNumber)
276
276
277ringInt :: (String, String)
277ringInt :: (String, String)
278−ringInt = (C.dataInt, C.ringInt)
278+ringInt = (C.prelude, C.ringInt)
279
279
280moduloSemiringNumber :: (String, String)
280moduloSemiringNumber :: (String, String)
281moduloSemiringNumber = (C.prelude, C.moduloSemiringNumber)
281moduloSemiringNumber = (C.prelude, C.moduloSemiringNumber)
282
282
283moduloSemiringInt :: (String, String)
283moduloSemiringInt :: (String, String)
284−moduloSemiringInt = (C.dataInt, C.moduloSemiringInt)
284+moduloSemiringInt = (C.prelude, C.moduloSemiringInt)
285
285
286eqNumber :: (String, String)
286eqNumber :: (String, String)
287eqNumber = (C.prelude, C.eqNumber)
287eqNumber = (C.prelude, C.eqNumber)
288
288
289eqInt :: (String, String)
289eqInt :: (String, String)
290−eqInt = (C.dataInt, C.eqInt)
290+eqInt = (C.prelude, C.eqInt)
291
291
292eqString :: (String, String)
292eqString :: (String, String)
293eqString = (C.prelude, C.eqNumber)
293eqString = (C.prelude, C.eqNumber)
@@ -299,7 +299,7 @@ ordNumber :: (String, String)
299ordNumber = (C.prelude, C.ordNumber)
299ordNumber = (C.prelude, C.ordNumber)
300
300
301ordInt :: (String, String)
301ordInt :: (String, String)
302−ordInt = (C.dataInt, C.ordInt)
302+ordInt = (C.prelude, C.ordInt)
303
303
304semigroupString :: (String, String)
304semigroupString :: (String, String)
305semigroupString = (C.prelude, C.semigroupString)
305semigroupString = (C.prelude, C.semigroupString)
@@ -307,11 +307,8 @@ semigroupString = (C.prelude, C.semigroupString)
307boundedBoolean :: (String, String)
307boundedBoolean :: (String, String)
308boundedBoolean = (C.prelude, C.boundedBoolean)
308boundedBoolean = (C.prelude, C.boundedBoolean)
309
309
310−latticeBoolean :: (String, String)
310+booleanAlgebraBoolean :: (String, String)
311−latticeBoolean = (C.prelude, C.latticeBoolean)
311+booleanAlgebraBoolean = (C.prelude, C.booleanAlgebraBoolean)
312−
313−complementedLatticeBoolean :: (String, String)
314−complementedLatticeBoolean = (C.prelude, C.complementedLatticeBoolean)
315
312
316semigroupoidArr :: (String, String)
313semigroupoidArr :: (String, String)
317semigroupoidArr = (C.prelude, C.semigroupoidArr)
314semigroupoidArr = (C.prelude, C.semigroupoidArr)
src/Language/PureScript/CodeGen/JS/Optimizer/MagicDo.hs+3−3
@@ -27,7 +27,7 @@ import Language.PureScript.Names
27import Language.PureScript.Options
27import Language.PureScript.Options
28import qualified Language.PureScript.Constants as C
28import qualified Language.PureScript.Constants as C
29
29
30−magicDo :: Options mode -> JS -> JS
30+magicDo :: Options -> JS -> JS
31magicDo opts | optionsNoMagicDo opts = id
31magicDo opts | optionsNoMagicDo opts = id
32 | otherwise = inlineST . magicDo'
32 | otherwise = inlineST . magicDo'
33
33
@@ -81,8 +81,8 @@ magicDo' = everywhereOnJS undo . everywhereOnJSTopDown convert
81 isPure (JSApp purePoly [effDict]) | isPurePoly purePoly && isEffDict C.applicativeEffDictionary effDict = True
81 isPure (JSApp purePoly [effDict]) | isPurePoly purePoly && isEffDict C.applicativeEffDictionary effDict = True
82 isPure _ = False
82 isPure _ = False
83 -- Check if an expression represents the polymorphic >>= function
83 -- Check if an expression represents the polymorphic >>= function
84− isBindPoly (JSAccessor prop (JSVar prelude)) = prelude == C.prelude && prop == identToJs (Op (C.>>=))
84+ isBindPoly (JSAccessor prop (JSVar prelude)) = prelude == C.prelude && (prop `elem` map identToJs [Ident C.bind, Op (C.>>=)])
85− isBindPoly (JSIndexer (JSStringLiteral bind) (JSVar prelude)) = prelude == C.prelude && bind == (C.>>=)
85+ isBindPoly (JSIndexer (JSStringLiteral bind) (JSVar prelude)) = prelude == C.prelude && (bind `elem` [C.bind, (C.>>=)])
86 isBindPoly _ = False
86 isBindPoly _ = False
87 -- Check if an expression represents the polymorphic return function
87 -- Check if an expression represents the polymorphic return function
88 isRetPoly (JSAccessor returnEscaped (JSVar prelude)) = prelude == C.prelude && returnEscaped == C.returnEscaped
88 isRetPoly (JSAccessor returnEscaped (JSVar prelude)) = prelude == C.prelude && returnEscaped == C.returnEscaped
src/Language/PureScript/CodeGen/JS/Optimizer/TCO.hs+1−1
@@ -23,7 +23,7 @@ import Language.PureScript.CodeGen.JS.AST
23-- |
23-- |
24-- Eliminate tail calls
24-- Eliminate tail calls
25--
25--
26−tco :: Options mode -> JS -> JS
26+tco :: Options -> JS -> JS
27tco opts | optionsNoTco opts = id
27tco opts | optionsNoTco opts = id
28 | otherwise = tco'
28 | otherwise = tco'
29
29
src/Language/PureScript/Constants.hs+9−12
@@ -71,6 +71,9 @@ module Language.PureScript.Constants where
71(||) :: String
71(||) :: String
72(||) = "||"
72(||) = "||"
73
73
74+bind :: String
75+bind = "bind"
76+
74unsafeIndex :: String
77unsafeIndex :: String
75unsafeIndex = "unsafeIndex"
78unsafeIndex = "unsafeIndex"
76
79
@@ -94,11 +97,11 @@ negate = "negate"
94not :: String
97not :: String
95not = "not"
98not = "not"
96
99
97−sup :: String
100+conj :: String
98−sup = "sup"
101+conj = "conj"
99
102
100−inf :: String
103+disj :: String
101−inf = "inf"
104+disj = "disj"
102
105
103mod :: String
106mod :: String
104mod = "mod"
107mod = "mod"
@@ -226,11 +229,8 @@ eqBoolean = "eqBoolean"
226boundedBoolean :: String
229boundedBoolean :: String
227boundedBoolean = "boundedBoolean"
230boundedBoolean = "boundedBoolean"
228
231
229−latticeBoolean :: String
232+booleanAlgebraBoolean :: String
230−latticeBoolean = "latticeBoolean"
233+booleanAlgebraBoolean = "booleanAlgebraBoolean"
231−
232−complementedLatticeBoolean :: String
233−complementedLatticeBoolean = "complementedLatticeBoolean"
234
234
235semigroupString :: String
235semigroupString :: String
236semigroupString = "semigroupString"
236semigroupString = "semigroupString"
@@ -271,8 +271,5 @@ st = "Control_Monad_ST"
271dataFunction :: String
271dataFunction :: String
272dataFunction = "Data_Function"
272dataFunction = "Data_Function"
273
273
274−dataInt :: String
275−dataInt = "Data_Int"
276−
277dataIntBits :: String
274dataIntBits :: String
278dataIntBits = "Data_Int_Bits"
275dataIntBits = "Data_Int_Bits"
src/Language/PureScript/DeadCodeElimination.hsdeleted−102
@@ -1,102 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Language.PureScript.DeadCodeElimination
4−-- Copyright : (c) 2014 Phil Freeman
5−-- License : MIT
6−--
7−-- Maintainer : Phil Freeman <paf31@cantab.net>
8−-- Stability : experimental
9−-- Portability :
10−--
11−-- | Dead code elimination.
12−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.DeadCodeElimination (
16− eliminateDeadCode
17−) where
18−
19−import Data.Graph
20−import Data.List
21−import Data.Maybe (mapMaybe)
22−
23−import Language.PureScript.CoreFn
24−import Language.PureScript.Names
25−
26−-- |
27−-- Eliminate all declarations which are not a transitive dependency of the entry point module
28−--
29−eliminateDeadCode :: [ModuleName] -> [Module a] -> [Module a]
30−eliminateDeadCode entryPoints ms = map go ms
31− where
32− go (Module coms mn imps exps foreigns ds) = Module coms mn imps exps' foreigns' ds'
33− where
34− ds' = filter (isUsed mn graph vertexFor entryPointVertices) ds
35− foreigns' = filter (isUsed' mn graph vertexFor entryPointVertices . foreignIdent) foreigns
36− names = concatMap bindIdents ds' ++ map foreignIdent foreigns'
37− exps' = filter (`elem` names) exps
38− declarations = concatMap declarationsByModule ms
39− (graph, _, vertexFor) = graphFromEdges $ map (\(key, deps) -> (key, key, deps)) declarations
40− entryPointVertices = mapMaybe (vertexFor . fst) . filter (\((mn, _), _) -> mn `elem` entryPoints) $ declarations
41−
42−-- |
43−-- Extract declaration names for a binding group.
44−--
45−bindIdents :: Bind a -> [Ident]
46−bindIdents (NonRec name _) = [name]
47−bindIdents (Rec names) = map fst names
48−
49−-- |
50−-- Extract the ident for a foreign declaration.
51−--
52−foreignIdent :: ForeignDecl -> Ident
53−foreignIdent = fst
54−
55−-- |
56−-- Key type to use in graph
57−--
58−type Key = (ModuleName, Ident)
59−
60−-- |
61−-- Find dependencies for each member in a module.
62−--
63−declarationsByModule :: Module a -> [(Key, [Key])]
64−declarationsByModule (Module _ mn _ _ fs ds) =
65− let fs' = map ((\name -> ((mn, name), [])) . foreignIdent) fs
66− in fs' ++ concatMap go ds
67− where
68− go :: Bind a -> [(Key, [Key])]
69− go d@(NonRec name _) = [((mn, name), dependencies d)]
70− go d@(Rec names') = map (\(name, _) -> ((mn, name), dependencies d)) names'
71−
72−-- |
73−-- Find all referenced values within a binding group.
74−--
75−dependencies :: Bind a -> [Key]
76−dependencies =
77− let (f, _, _, _) = everythingOnValues (++) (const []) values binders (const [])
78− in nub . f
79− where
80− values :: Expr a -> [Key]
81− values (Var _ (Qualified (Just mn) ident)) = [(mn, ident)]
82− values _ = []
83− binders :: Binder a -> [Key]
84− binders (ConstructorBinder _ _ (Qualified (Just mn) ident) _) = [(mn, Ident $ runProperName ident)]
85− binders _ = []
86−
87−-- |
88−-- Check whether a binding group is used.
89−--
90−isUsed :: ModuleName -> Graph -> (Key -> Maybe Vertex) -> [Vertex] -> Bind a -> Bool
91−isUsed mn graph vertexFor entryPointVertices (NonRec name _) =
92− isUsed' mn graph vertexFor entryPointVertices name
93−isUsed mn graph vertexFor entryPointVertices (Rec ds) =
94− any (isUsed' mn graph vertexFor entryPointVertices . fst) ds
95−
96−-- |
97−-- Check whether a named declaration is used.
98−--
99−isUsed' :: ModuleName -> Graph -> (Key -> Maybe Vertex) -> [Vertex] -> Ident -> Bool
100−isUsed' mn graph vertexFor entryPointVertices name =
101− let Just v' = vertexFor (mn, name)
102− in any (\v -> path graph v v') entryPointVertices
src/Language/PureScript/Docs.hs+1
@@ -9,5 +9,6 @@ module Language.PureScript.Docs (
9import Language.PureScript.Docs.Types as Docs
9import Language.PureScript.Docs.Types as Docs
10import Language.PureScript.Docs.RenderedCode.Types as Docs
10import Language.PureScript.Docs.RenderedCode.Types as Docs
11import Language.PureScript.Docs.RenderedCode.Render as Docs
11import Language.PureScript.Docs.RenderedCode.Render as Docs
12+import Language.PureScript.Docs.Convert as Docs
12import Language.PureScript.Docs.Render as Docs
13import Language.PureScript.Docs.Render as Docs
13import Language.PureScript.Docs.ParseAndDesugar as Docs
14import Language.PureScript.Docs.ParseAndDesugar as Docs
src/Language/PureScript/Docs/AsMarkdown.hs+45−22
@@ -12,6 +12,7 @@ import qualified Language.PureScript as P
12
12
13import Language.PureScript.Docs.Types
13import Language.PureScript.Docs.Types
14import Language.PureScript.Docs.RenderedCode
14import Language.PureScript.Docs.RenderedCode
15+import qualified Language.PureScript.Docs.Convert as Convert
15import qualified Language.PureScript.Docs.Render as Render
16import qualified Language.PureScript.Docs.Render as Render
16
17
17-- |
18-- |
@@ -20,37 +21,43 @@ import qualified Language.PureScript.Docs.Render as Render
20--
21--
21renderModulesAsMarkdown :: [P.Module] -> String
22renderModulesAsMarkdown :: [P.Module] -> String
22renderModulesAsMarkdown =
23renderModulesAsMarkdown =
23− runDocs . modulesAsMarkdown . map Render.renderModule
24+ runDocs . modulesAsMarkdown . map Convert.convertModule
24
25
25−modulesAsMarkdown :: [RenderedModule] -> Docs
26+modulesAsMarkdown :: [Module] -> Docs
26modulesAsMarkdown = mapM_ moduleAsMarkdown
27modulesAsMarkdown = mapM_ moduleAsMarkdown
27
28
28−moduleAsMarkdown :: RenderedModule -> Docs
29+moduleAsMarkdown :: Module -> Docs
29−moduleAsMarkdown RenderedModule{..} = do
30+moduleAsMarkdown Module{..} = do
30− headerLevel 2 $ "Module " ++ rmName
31+ headerLevel 2 $ "Module " ++ modName
31 spacer
32 spacer
32− for_ rmComments tell'
33+ for_ modComments tell'
33− mapM_ declAsMarkdown rmDeclarations
34+ mapM_ declAsMarkdown modDeclarations
34 spacer
35 spacer
35
36
36−declAsMarkdown :: RenderedDeclaration -> Docs
37+declAsMarkdown :: Declaration -> Docs
37−declAsMarkdown RenderedDeclaration{..} = do
38+declAsMarkdown decl@Declaration{..} = do
38− headerLevel 4 (ticks rdTitle)
39+ headerLevel 4 (ticks declTitle)
39 spacer
40 spacer
40
41
41− let (instances, children) = partition ((==) ChildInstance . rcdType) rdChildren
42+ let (instances, children) = partition (isChildInstance . cdeclInfo) declChildren
42 fencedBlock $ do
43 fencedBlock $ do
43− tell' (codeToString rdCode)
44+ tell' (codeToString $ Render.renderDeclaration decl)
44 zipWithM_ (\f c -> tell' (childToString f c)) (First : repeat NotFirst) children
45 zipWithM_ (\f c -> tell' (childToString f c)) (First : repeat NotFirst) children
45 spacer
46 spacer
46
47
47− for_ rdComments tell'
48+ for_ declFixity (\fixity -> fixityAsMarkdown fixity >> spacer)
49+
50+ for_ declComments tell'
48
51
49 unless (null instances) $ do
52 unless (null instances) $ do
50 headerLevel 5 "Instances"
53 headerLevel 5 "Instances"
51 fencedBlock $ mapM_ (tell' . childToString NotFirst) instances
54 fencedBlock $ mapM_ (tell' . childToString NotFirst) instances
52 spacer
55 spacer
53
56
57+ where
58+ isChildInstance (ChildInstance _ _) = True
59+ isChildInstance _ = False
60+
54codeToString :: RenderedCode -> String
61codeToString :: RenderedCode -> String
55codeToString = outputWith elemAsMarkdown
62codeToString = outputWith elemAsMarkdown
56 where
63 where
@@ -61,16 +68,32 @@ codeToString = outputWith elemAsMarkdown
61 elemAsMarkdown (Keyword x) = x
68 elemAsMarkdown (Keyword x) = x
62 elemAsMarkdown Space = " "
69 elemAsMarkdown Space = " "
63
70
71+fixityAsMarkdown :: P.Fixity -> Docs
72+fixityAsMarkdown (P.Fixity associativity precedence) =
73+ tell' $ concat [ "_"
74+ , associativityStr
75+ , " / precedence "
76+ , show precedence
77+ , "_"
78+ ]
79+ where
80+ associativityStr = case associativity of
81+ P.Infixl -> "left-associative"
82+ P.Infixr -> "right-associative"
83+ P.Infix -> "non-associative"
84+
64−childToString :: First -> RenderedChildDeclaration -> String
85+childToString :: First -> ChildDeclaration -> String
65−childToString f RenderedChildDeclaration{..} =
86+childToString f decl@ChildDeclaration{..} =
66− case rcdType of
87+ case cdeclInfo of
67− ChildDataConstructor ->
88+ ChildDataConstructor _ ->
68 let c = if f == First then "=" else "|"
89 let c = if f == First then "=" else "|"
69− in " " ++ c ++ " " ++ codeToString rcdCode
90+ in " " ++ c ++ " " ++ str
70− ChildTypeClassMember ->
91+ ChildTypeClassMember _ ->
71− " " ++ codeToString rcdCode
92+ " " ++ str
72− ChildInstance ->
93+ ChildInstance _ _ ->
73− codeToString rcdCode
94+ str
95+ where
96+ str = codeToString $ Render.renderChildDeclaration decl
74
97
75data First
98data First
76 = First
99 = First
src/Language/PureScript/Docs/Convert.hsnew file+228
@@ -0,0 +1,228 @@
1+{-# LANGUAGE TupleSections #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE RecordWildCards #-}
4+{-# LANGUAGE ViewPatterns #-}
5+
6+-- | Functions for converting PureScript ASTs into values of the data types
7+-- from Language.PureScript.Docs.
8+
9+module Language.PureScript.Docs.Convert
10+ ( convertModule
11+ , collectBookmarks
12+ ) where
13+
14+import Control.Monad
15+import Control.Category ((>>>))
16+import Data.Either
17+import Data.Maybe (mapMaybe, isNothing)
18+import Data.List (nub, isPrefixOf, isSuffixOf)
19+
20+import qualified Language.PureScript as P
21+
22+import Language.PureScript.Docs.Types
23+
24+-- |
25+-- Convert a single Module.
26+--
27+convertModule :: P.Module -> Module
28+convertModule m@(P.Module coms moduleName _ _) =
29+ Module (show moduleName) comments (declarations m)
30+ where
31+ comments = convertComments coms
32+ declarations =
33+ P.exportedDeclarations
34+ >>> mapMaybe (\d -> getDeclarationTitle d >>= convertDeclaration d)
35+ >>> augmentDeclarations
36+ >>> map addDefaultFixity
37+
38+-- | The data type for an intermediate stage which we go through during
39+-- converting.
40+--
41+-- In the first pass, we take all top level declarations in the module, and
42+-- collect other information which will later be used to augment the top level
43+-- declarations. These two situation correspond to the Right and Left
44+-- constructors, respectively.
45+--
46+-- In the second pass, we go over all of the Left values and augment the
47+-- relevant declarations, leaving only the augmented Right values.
48+--
49+-- Note that in the Left case, we provide a [String] as well as augment
50+-- information. The [String] value should be a list of titles of declarations
51+-- that the augmentation should apply to. For example, for a type instance
52+-- declaration, that would be any types or type classes mentioned in the
53+-- instance. For a fixity declaration, it would be just the relevant operator's
54+-- name.
55+type IntermediateDeclaration
56+ = Either ([String], DeclarationAugment) Declaration
57+
58+-- | Some data which will be used to augment a Declaration in the
59+-- output.
60+--
61+-- The AugmentChild constructor allows us to move all children under their
62+-- respective parents. It is only necessary for type instance declarations,
63+-- since they appear at the top level in the AST, and since they might need to
64+-- appear as children in two places (for example, if a data type defined in a
65+-- module is an instance of a type class also defined in that module).
66+--
67+-- The AugmentFixity constructor allows us to augment operator definitions
68+-- with their associativity and precedence.
69+data DeclarationAugment
70+ = AugmentChild ChildDeclaration
71+ | AugmentFixity P.Fixity
72+
73+-- | Augment top-level declarations; the second pass. See the comments under
74+-- the type synonym IntermediateDeclaration for more information.
75+augmentDeclarations :: [IntermediateDeclaration] -> [Declaration]
76+augmentDeclarations (partitionEithers -> (augments, toplevels)) =
77+ foldl go toplevels augments
78+ where
79+ go ds (parentTitles, a) =
80+ map (\d ->
81+ if declTitle d `elem` parentTitles
82+ then augmentWith a d
83+ else d) ds
84+
85+ augmentWith a d =
86+ case a of
87+ AugmentChild child ->
88+ d { declChildren = declChildren d ++ [child] }
89+ AugmentFixity fixity ->
90+ d { declFixity = Just fixity }
91+
92+-- | Add the default operator fixity for operators which do not have associated
93+-- fixity declarations.
94+--
95+-- TODO: This may no longer be necessary after issue 806 is resolved, hopefully
96+-- in 0.8.
97+addDefaultFixity :: Declaration -> Declaration
98+addDefaultFixity decl@Declaration{..}
99+ | isOp declTitle && isNothing declFixity =
100+ decl { declFixity = Just defaultFixity }
101+ | otherwise =
102+ decl
103+ where
104+ isOp :: String -> Bool
105+ isOp str = "(" `isPrefixOf` str && ")" `isSuffixOf` str
106+ defaultFixity = P.Fixity P.Infixl (-1)
107+
108+getDeclarationTitle :: P.Declaration -> Maybe String
109+getDeclarationTitle (P.TypeDeclaration name _) = Just (show name)
110+getDeclarationTitle (P.ExternDeclaration name _) = Just (show name)
111+getDeclarationTitle (P.DataDeclaration _ name _ _) = Just (show name)
112+getDeclarationTitle (P.ExternDataDeclaration name _) = Just (show name)
113+getDeclarationTitle (P.TypeSynonymDeclaration name _ _) = Just (show name)
114+getDeclarationTitle (P.TypeClassDeclaration name _ _ _) = Just (show name)
115+getDeclarationTitle (P.TypeInstanceDeclaration name _ _ _ _) = Just (show name)
116+getDeclarationTitle (P.FixityDeclaration _ name) = Just ("(" ++ name ++ ")")
117+getDeclarationTitle (P.PositionedDeclaration _ _ d) = getDeclarationTitle d
118+getDeclarationTitle _ = Nothing
119+
120+-- | Create a basic Declaration value.
121+mkDeclaration :: String -> DeclarationInfo -> Declaration
122+mkDeclaration title info =
123+ Declaration { declTitle = title
124+ , declComments = Nothing
125+ , declSourceSpan = Nothing
126+ , declChildren = []
127+ , declFixity = Nothing
128+ , declInfo = info
129+ }
130+
131+basicDeclaration :: String -> DeclarationInfo -> Maybe IntermediateDeclaration
132+basicDeclaration title info = Just $ Right $ mkDeclaration title info
133+
134+convertDeclaration :: P.Declaration -> String -> Maybe IntermediateDeclaration
135+convertDeclaration (P.TypeDeclaration _ ty) title =
136+ basicDeclaration title (ValueDeclaration ty)
137+convertDeclaration (P.ExternDeclaration _ ty) title =
138+ basicDeclaration title (ValueDeclaration ty)
139+convertDeclaration (P.DataDeclaration dtype _ args ctors) title =
140+ Just (Right (mkDeclaration title info) { declChildren = children })
141+ where
142+ info = DataDeclaration dtype args
143+ children = map convertCtor ctors
144+ convertCtor (ctor', tys) =
145+ ChildDeclaration (show ctor') Nothing Nothing (ChildDataConstructor tys)
146+convertDeclaration (P.ExternDataDeclaration _ kind') title =
147+ basicDeclaration title (ExternDataDeclaration kind')
148+convertDeclaration (P.TypeSynonymDeclaration _ args ty) title =
149+ basicDeclaration title (TypeSynonymDeclaration args ty)
150+convertDeclaration (P.TypeClassDeclaration _ args implies ds) title = do
151+ Just (Right (mkDeclaration title info) { declChildren = children })
152+ where
153+ info = TypeClassDeclaration args implies
154+ children = map convertClassMember ds
155+ convertClassMember (P.PositionedDeclaration _ _ d) =
156+ convertClassMember d
157+ convertClassMember (P.TypeDeclaration ident' ty) =
158+ ChildDeclaration (show ident') Nothing Nothing (ChildTypeClassMember ty)
159+ convertClassMember _ =
160+ error "Invalid argument to convertClassMember."
161+convertDeclaration (P.TypeInstanceDeclaration _ constraints className tys _) title = do
162+ Just (Left (classNameString : typeNameStrings, AugmentChild childDecl))
163+ where
164+ classNameString = unQual className
165+ typeNameStrings = nub (concatMap (P.everythingOnTypes (++) extractProperNames) tys)
166+ unQual x = let (P.Qualified _ y) = x in show y
167+
168+ extractProperNames (P.TypeConstructor n) = [unQual n]
169+ extractProperNames (P.SaturatedTypeSynonym n _) = [unQual n]
170+ extractProperNames _ = []
171+
172+ childDecl = ChildDeclaration title Nothing Nothing (ChildInstance constraints classApp)
173+ classApp = foldl P.TypeApp (P.TypeConstructor className) tys
174+convertDeclaration (P.FixityDeclaration fixity _) title =
175+ Just (Left ([title], AugmentFixity fixity))
176+convertDeclaration (P.PositionedDeclaration srcSpan com d') title =
177+ fmap (addComments . addSourceSpan) (convertDeclaration d' title)
178+ where
179+ addComments (Right d) =
180+ Right (d { declComments = convertComments com })
181+ addComments (Left augment) =
182+ Left (withAugmentChild (\d -> d { cdeclComments = convertComments com })
183+ augment)
184+
185+ addSourceSpan (Right d) =
186+ Right (d { declSourceSpan = Just srcSpan })
187+ addSourceSpan (Left augment) =
188+ Left (withAugmentChild (\d -> d { cdeclSourceSpan = Just srcSpan })
189+ augment)
190+
191+ withAugmentChild f (t, a) =
192+ case a of
193+ AugmentChild d -> (t, AugmentChild (f d))
194+ _ -> (t, a)
195+convertDeclaration _ _ = Nothing
196+
197+convertComments :: [P.Comment] -> Maybe String
198+convertComments cs = do
199+ let raw = concatMap toLines cs
200+ guard (all hasPipe raw && not (null raw))
201+ return (go raw)
202+ where
203+ go = unlines . map stripPipes
204+
205+ toLines (P.LineComment s) = [s]
206+ toLines (P.BlockComment s) = lines s
207+
208+ hasPipe s = case dropWhile (== ' ') s of { ('|':_) -> True; _ -> False }
209+
210+ stripPipes = dropPipe . dropWhile (== ' ')
211+
212+ dropPipe ('|':' ':s) = s
213+ dropPipe ('|':s) = s
214+ dropPipe s = s
215+
216+-- | Go through a PureScript module and extract a list of Bookmarks; references
217+-- to data types or values, to be used as a kind of index. These are used for
218+-- generating links in the HTML documentation, for example.
219+collectBookmarks :: InPackage P.Module -> [Bookmark]
220+collectBookmarks (Local m) = map Local (collectBookmarks' m)
221+collectBookmarks (FromDep pkg m) = map (FromDep pkg) (collectBookmarks' m)
222+
223+collectBookmarks' :: P.Module -> [(P.ModuleName, String)]
224+collectBookmarks' m =
225+ map (P.getModuleName m, )
226+ (mapMaybe getDeclarationTitle
227+ (P.exportedDeclarations m))
228+
src/Language/PureScript/Docs/ParseAndDesugar.hs+33−12
@@ -19,7 +19,7 @@ import Web.Bower.PackageMeta (PackageName)
19import qualified Language.PureScript as P
19import qualified Language.PureScript as P
20import qualified Language.PureScript.Constants as C
20import qualified Language.PureScript.Constants as C
21import Language.PureScript.Docs.Types
21import Language.PureScript.Docs.Types
22−import Language.PureScript.Docs.Render
22+import Language.PureScript.Docs.Convert (collectBookmarks)
23
23
24data ParseDesugarError
24data ParseDesugarError
25 = ParseError P.MultipleErrors
25 = ParseError P.MultipleErrors
@@ -53,20 +53,41 @@ parseAndDesugar inputFiles depsFiles callback = do
53 depsFiles' <- mapM (\(pkgName, f) -> parseAs (FromDep pkgName) f) depsFiles
53 depsFiles' <- mapM (\(pkgName, f) -> parseAs (FromDep pkgName) f) depsFiles
54
54
55 runExceptT $ do
55 runExceptT $ do
56− let eParsed = P.parseModulesFromFiles fileInfoToString (inputFiles' ++ depsFiles')
56+ ms <- parseFiles (inputFiles' ++ depsFiles')
57+ ms' <- sortModules (map snd ms)
58+ (bs, ms'') <- desugarWithBookmarks ms ms'
59+ liftIO $ callback bs ms''
60+
61+parseFiles ::
62+ [(FileInfo, FilePath)]
63+ -> ExceptT ParseDesugarError IO [(FileInfo, P.Module)]
64+parseFiles =
57− ms <- throwLeft ParseError eParsed
65+ throwLeft ParseError . P.parseModulesFromFiles fileInfoToString
66+
67+sortModules ::
68+ [P.Module]
69+ -> ExceptT ParseDesugarError IO [P.Module]
70+sortModules =
71+ fmap fst . throwLeft SortModulesError . sortModules' . map importPrim
72+ where
73+ sortModules' :: [P.Module] -> Either P.MultipleErrors ([P.Module], P.ModuleGraph)
74+ sortModules' = P.sortModules
58
75
59− let depsModules = getDepsModuleNames (map (\(fp, m) -> (,m) <$> fp) ms)
76+desugarWithBookmarks ::
60− let eSorted = P.sortModules . map (importPrim . snd) $ ms
77+ [(FileInfo, P.Module)]
61− (ms', _) <- throwLeft SortModulesError eSorted
78+ -> [P.Module]
79+ -> ExceptT ParseDesugarError IO ([Bookmark], [P.Module])
80+desugarWithBookmarks msInfo msSorted = do
81+ msDesugared <- throwLeft DesugarError (desugar msSorted)
62
82
63− modules <- throwLeft DesugarError (desugar ms')
83+ let msDeps = getDepsModuleNames (map (\(fp, m) -> (,m) <$> fp) msInfo)
64− let modules' = map (addPackage depsModules) modules
84+ msPackages = map (addPackage msDeps) msDesugared
65− bookmarks = concatMap collectBookmarks modules'
85+ bookmarks = concatMap collectBookmarks msPackages
66− liftIO (callback bookmarks (takeLocals modules'))
67
86
68− where
87+ return (bookmarks, takeLocals msPackages)
88+
89+throwLeft :: (MonadError e m) => (l -> e) -> Either l r -> m r
69− throwLeft f = either (throwError . f) return
90+throwLeft f = either (throwError . f) return
70
91
71-- | Specifies whether a PureScript source file is considered as:
92-- | Specifies whether a PureScript source file is considered as:
72--
93--
src/Language/PureScript/Docs/Render.hs+100−212
@@ -1,239 +1,127 @@
1−{-# LANGUAGE TupleSections #-}
2−{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE RecordWildCards #-}
1{-# LANGUAGE RecordWildCards #-}
4−{-# LANGUAGE ViewPatterns #-}
5
2
6−-- | Functions for rendering documentation generated from PureScript code.
3+-- | Functions for creating `RenderedCode` values from data types in
4+-- Language.PureScript.Docs.Types.
5+--
6+-- These functions are the ones that are used in markdown/html documentation
7+-- generation, but the intention is that you are able to supply your own
8+-- instead if necessary. For example, the Hoogle input file generator
9+-- substitutes some of these
7
10
8−module Language.PureScript.Docs.Render (
11+module Language.PureScript.Docs.Render where
9− renderModule,
10− collectBookmarks
11−) where
12
12
13−import Control.Monad
14−import Data.Either
15import Data.Monoid ((<>))
13import Data.Monoid ((<>))
16−import Data.Maybe (mapMaybe)
17−import Data.List (nub)
18−
19import qualified Language.PureScript as P
14import qualified Language.PureScript as P
20
15
21−import Language.PureScript.Docs.RenderedCode
22import Language.PureScript.Docs.Types
16import Language.PureScript.Docs.Types
17+import Language.PureScript.Docs.RenderedCode
23import Language.PureScript.Docs.Utils.MonoidExtras
18import Language.PureScript.Docs.Utils.MonoidExtras
24
19
25−-- |
20+renderDeclaration :: Declaration -> RenderedCode
26−-- Render a single Module.
21+renderDeclaration = renderDeclarationWithOptions defaultRenderTypeOptions
27−--
28−renderModule :: P.Module -> RenderedModule
29−renderModule m@(P.Module coms moduleName _ _) =
30− RenderedModule (show moduleName) comments declarations
31− where
32− comments = renderComments coms
33− declarations = groupChildren declarationsWithChildren
34− declarationsWithChildren = mapMaybe go (P.exportedDeclarations m)
35− go decl = getDeclarationTitle decl
36− >>= renderDeclaration decl
37
22
38−-- | An intermediate stage which we go through during rendering.
23+renderDeclarationWithOptions :: RenderTypeOptions -> Declaration -> RenderedCode
39−--
24+renderDeclarationWithOptions opts Declaration{..} =
40−-- In the first pass, we take all top level declarations in the module, and
25+ mintersperse sp $ case declInfo of
41−-- render those which should appear at the top level in the output, as well as
26+ ValueDeclaration ty ->
42−-- those which should appear as children of other declarations in the output.
27+ [ ident declTitle
43−--
44−-- In the second pass, we move all children under their respective parents,
45−-- or discard them if none are found.
46−--
47−-- This two-pass system is only necessary for type instance declarations, since
48−-- they appear at the top level in the AST, and since they might need to appear
49−-- as children in two places (for example, if a data type defined in a module
50−-- is an instance of a type class also defined in that module).
51−--
52−-- This data type is used as an intermediate type between the two stages. The
53−-- Left case is a child declaration, together with a list of parent declaration
54−-- titles which this may appear as a child of.
55−--
56−-- The Right case is a top level declaration which should pass straight through
57−-- the second stage; the only way it might change is if child declarations are
58−-- added to it.
59−type IntermediateDeclaration
60− = Either ([String], RenderedChildDeclaration) RenderedDeclaration
61−
62−-- | Move child declarations into their respective parents; the second pass.
63−-- See the comments under the type synonym IntermediateDeclaration for more
64−-- information.
65−groupChildren :: [IntermediateDeclaration] -> [RenderedDeclaration]
66−groupChildren (partitionEithers -> (children, toplevels)) =
67− foldl go toplevels children
68− where
69− go ds (parentTitles, child) =
70− map (\d ->
71− if rdTitle d `elem` parentTitles
72− then d { rdChildren = rdChildren d ++ [child] }
73− else d) ds
74−
75−getDeclarationTitle :: P.Declaration -> Maybe String
76−getDeclarationTitle (P.TypeDeclaration name _) = Just (show name)
77−getDeclarationTitle (P.ExternDeclaration name _) = Just (show name)
78−getDeclarationTitle (P.DataDeclaration _ name _ _) = Just (show name)
79−getDeclarationTitle (P.ExternDataDeclaration name _) = Just (show name)
80−getDeclarationTitle (P.TypeSynonymDeclaration name _ _) = Just (show name)
81−getDeclarationTitle (P.TypeClassDeclaration name _ _ _) = Just (show name)
82−getDeclarationTitle (P.TypeInstanceDeclaration name _ _ _ _) = Just (show name)
83−getDeclarationTitle (P.PositionedDeclaration _ _ d) = getDeclarationTitle d
84−getDeclarationTitle _ = Nothing
85−
86−basicDeclaration :: String -> RenderedCode -> Maybe IntermediateDeclaration
87−basicDeclaration title code = Just (Right (RenderedDeclaration title Nothing code Nothing []))
88−
89−renderDeclaration :: P.Declaration -> String -> Maybe IntermediateDeclaration
90−renderDeclaration (P.TypeDeclaration ident' ty) title =
91− basicDeclaration title code
92− where
93− code = ident (show ident')
94− <> sp <> syntax "::" <> sp
28+ , syntax "::"
95− <> renderType ty
29+ , renderType' ty
96−renderDeclaration (P.ExternDeclaration ident' ty) title =
30+ ]
97− basicDeclaration title code
98− where
99− code = ident (show ident')
100− <> sp <> syntax "::" <> sp
101− <> renderType ty
102−renderDeclaration (P.DataDeclaration dtype name args ctors) title =
31+ DataDeclaration dtype args ->
103− Just (Right (RenderedDeclaration title Nothing code Nothing children))
104− where
105− typeApp = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing name)) (map toTypeVar args)
106− code = keyword (show dtype) <> sp <> renderType typeApp
32+ [ keyword (show dtype)
107− children = map renderCtor ctors
33+ , renderType' (typeApp declTitle args)
108− -- TODO: Comments for data constructors?
34+ ]
109− renderCtor (ctor', tys) =
110− let typeApp' = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing ctor')) tys
111− childCode = renderType typeApp'
112− in RenderedChildDeclaration (show ctor') Nothing childCode Nothing ChildDataConstructor
113−renderDeclaration (P.ExternDataDeclaration name kind') title =
35+ ExternDataDeclaration kind' ->
114− basicDeclaration title code
115− where
116− code = keywordData <> sp
36+ [ keywordData
117− <> renderType (P.TypeConstructor (P.Qualified Nothing name))
37+ , renderType' (P.TypeConstructor (notQualified declTitle))
118− <> sp <> syntax "::" <> sp
38+ , syntax "::"
119− <> renderKind kind'
39+ , renderKind kind'
40+ ]
120−renderDeclaration (P.TypeSynonymDeclaration name args ty) title =
41+ TypeSynonymDeclaration args ty ->
121− basicDeclaration title code
122− where
123− typeApp = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing name)) (map toTypeVar args)
124− code = mintersperse sp
125− [ keywordType
42+ [ keywordType
126− , renderType typeApp
43+ , renderType' (typeApp declTitle args)
127− , syntax "="
44+ , syntax "="
128− , renderType ty
45+ , renderType' ty
129− ]
46+ ]
130−renderDeclaration (P.TypeClassDeclaration name args implies ds) title = do
47+ TypeClassDeclaration args implies ->
131− Just (Right (RenderedDeclaration title Nothing code Nothing children))
132− where
133− code = mintersperse sp $
134− [keywordClass]
48+ [ keywordClass ]
135− ++ maybe [] (:[]) superclasses
49+ ++ maybe [] (:[]) superclasses
136− ++ [renderType classApp]
50+ ++ [renderType' (typeApp declTitle args)]
51+ ++ if any (isTypeClassMember . cdeclInfo) declChildren
137− ++ if (not (null ds)) then [keywordWhere] else []
52+ then [keywordWhere]
138−
53+ else []
54+
55+ where
139− superclasses
56+ superclasses
140− | null implies = Nothing
57+ | null implies = Nothing
141− | otherwise = Just $
58+ | otherwise = Just $
142− syntax "("
59+ syntax "("
143− <> mintersperse (syntax "," <> sp) (map renderImplies implies)
60+ <> mintersperse (syntax "," <> sp) (map renderConstraint implies)
144− <> syntax ") <="
61+ <> syntax ")" <> sp <> syntax "<="
145−
62+
146− renderImplies (pn, tys) =
63+ isTypeClassMember (ChildTypeClassMember _) = True
147− let supApp = foldl P.TypeApp (P.TypeConstructor pn) tys
64+ isTypeClassMember _ = False
148− in renderType supApp
149−
150− classApp = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing name)) (map toTypeVar args)
151−
152− children = map renderClassMember ds
153−
154− -- TODO: Comments for type class members
155− renderClassMember (P.PositionedDeclaration _ _ d) = renderClassMember d
156− renderClassMember (P.TypeDeclaration ident' ty) =
157− let childCode =
158− mintersperse sp
159− [ ident (show ident')
160− , syntax "::"
161− , renderType ty
162− ]
163− in RenderedChildDeclaration (show ident') Nothing childCode Nothing ChildTypeClassMember
164− renderClassMember _ = error "Invalid argument to renderClassMember."
165−renderDeclaration (P.TypeInstanceDeclaration name constraints className tys _) title = do
166− Just (Left (classNameString : typeNameStrings, childDecl))
167 where
65 where
168− classNameString = unQual className
66+ renderType' = renderTypeWithOptions opts
169− typeNameStrings = nub (concatMap (P.everythingOnTypes (++) extractProperNames) tys)
170− unQual x = let (P.Qualified _ y) = x in show y
171−
172− extractProperNames (P.TypeConstructor n) = [unQual n]
173− extractProperNames (P.SaturatedTypeSynonym n _) = [unQual n]
174− extractProperNames _ = []
175
67
176− childDecl = RenderedChildDeclaration title Nothing code Nothing ChildInstance
68+renderChildDeclaration :: ChildDeclaration -> RenderedCode
69+renderChildDeclaration = renderChildDeclarationWithOptions defaultRenderTypeOptions
177
70
178− code =
71+renderChildDeclarationWithOptions :: RenderTypeOptions -> ChildDeclaration -> RenderedCode
72+renderChildDeclarationWithOptions opts ChildDeclaration{..} =
179− mintersperse sp $
73+ mintersperse sp $ case cdeclInfo of
74+ ChildInstance constraints ty ->
180 [ keywordInstance
75 [ keywordInstance
181− , ident (show name)
76+ , ident cdeclTitle
182 , syntax "::"
77 , syntax "::"
183− ] ++ maybe [] (:[]) constraints'
78+ ] ++ maybe [] (:[]) (renderConstraints constraints)
184− ++ [ renderType classApp ]
79+ ++ [ renderType' ty ]
80+ ChildDataConstructor args ->
81+ [ renderType' typeApp' ]
82+ where
83+ typeApp' = foldl P.TypeApp ctor' args
84+ ctor' = P.TypeConstructor (notQualified cdeclTitle)
85+
86+ ChildTypeClassMember ty ->
87+ [ ident cdeclTitle
88+ , syntax "::"
89+ , renderType' ty
90+ ]
91+ where
92+ renderType' = renderTypeWithOptions opts
185
93
186− constraints'
94+renderConstraint :: (P.Qualified P.ProperName, [P.Type]) -> RenderedCode
187− | null constraints = Nothing
95+renderConstraint = renderConstraintWithOptions defaultRenderTypeOptions
188− | otherwise = Just (syntax "(" <> renderedConstraints <> syntax ") =>")
189
96
190− renderedConstraints = mintersperse (syntax "," <> sp) (map renderConstraint constraints)
97+renderConstraintWithOptions :: RenderTypeOptions -> (P.Qualified P.ProperName, [P.Type]) -> RenderedCode
98+renderConstraintWithOptions opts (pn, tys) =
99+ renderTypeWithOptions opts $ foldl P.TypeApp (P.TypeConstructor pn) tys
191
100
192− renderConstraint (pn, tys') =
101+renderConstraints :: [P.Constraint] -> Maybe RenderedCode
193− let supApp = foldl P.TypeApp (P.TypeConstructor pn) tys'
102+renderConstraints = renderConstraintsWithOptions defaultRenderTypeOptions
194− in renderType supApp
195
103
196− classApp = foldl P.TypeApp (P.TypeConstructor className) tys
104+renderConstraintsWithOptions :: RenderTypeOptions -> [P.Constraint] -> Maybe RenderedCode
197−renderDeclaration (P.PositionedDeclaration srcSpan com d') title =
105+renderConstraintsWithOptions opts constraints
198− fmap (addComments . addSourceSpan) (renderDeclaration d' title)
106+ | null constraints = Nothing
199− where
107+ | otherwise = Just $
200− addComments (Left (t, d)) = Left (t, d { rcdComments = renderComments com })
108+ syntax "("
201− addComments (Right d) = Right (d { rdComments = renderComments com })
109+ <> renderedConstraints
202−
110+ <> syntax ")" <> sp <> syntax "=>"
203− addSourceSpan (Left (t, d)) = Left (t, d { rcdSourceSpan = Just srcSpan })
204− addSourceSpan (Right d) = Right (d { rdSourceSpan = Just srcSpan })
205−renderDeclaration _ _ = Nothing
206−
207−renderComments :: [P.Comment] -> Maybe String
208−renderComments cs = do
209− let raw = concatMap toLines cs
210− guard (all hasPipe raw && not (null raw))
211− return (go raw)
212 where
111 where
213− go = unlines . map stripPipes
112+ renderedConstraints =
214−
113+ mintersperse (syntax "," <> sp)
215− toLines (P.LineComment s) = [s]
114+ (map (renderConstraintWithOptions opts) constraints)
216− toLines (P.BlockComment s) = lines s
217−
218− hasPipe s = case dropWhile (== ' ') s of { ('|':_) -> True; _ -> False }
219
115
220− stripPipes = dropPipe . dropWhile (== ' ')
116+notQualified :: String -> P.Qualified P.ProperName
117+notQualified = P.Qualified Nothing . P.ProperName
221
118
222− dropPipe ('|':' ':s) = s
119+typeApp :: String -> [(String, Maybe P.Kind)] -> P.Type
223− dropPipe ('|':s) = s
120+typeApp title typeArgs =
224− dropPipe s = s
121+ foldl P.TypeApp
122+ (P.TypeConstructor (notQualified title))
123+ (map toTypeVar typeArgs)
225
124
226toTypeVar :: (String, Maybe P.Kind) -> P.Type
125toTypeVar :: (String, Maybe P.Kind) -> P.Type
227toTypeVar (s, Nothing) = P.TypeVar s
126toTypeVar (s, Nothing) = P.TypeVar s
228toTypeVar (s, Just k) = P.KindedType (P.TypeVar s) k
127toTypeVar (s, Just k) = P.KindedType (P.TypeVar s) k
229−
230−collectBookmarks :: InPackage P.Module -> [Bookmark]
231−collectBookmarks (Local m) = map Local (collectBookmarks' m)
232−collectBookmarks (FromDep pkg m) = map (FromDep pkg) (collectBookmarks' m)
233−
234−collectBookmarks' :: P.Module -> [(P.ModuleName, String)]
235−collectBookmarks' m =
236− map (P.getModuleName m, )
237− (mapMaybe getDeclarationTitle
238− (P.exportedDeclarations m))
239−
src/Language/PureScript/Docs/RenderedCode/Render.hs+26−12
@@ -5,7 +5,10 @@ module Language.PureScript.Docs.RenderedCode.Render (
5 renderType,
5 renderType,
6 renderTypeAtom,
6 renderTypeAtom,
7 renderRow,
7 renderRow,
8− renderKind
8+ renderKind,
9+ RenderTypeOptions(..),
10+ defaultRenderTypeOptions,
11+ renderTypeWithOptions
9) where
12) where
10
13
11import Data.Monoid ((<>), mconcat, mempty)
14import Data.Monoid ((<>), mconcat, mempty)
@@ -119,9 +122,9 @@ forall_ = mkPattern match
119 match (PrettyPrintForAll idents ty) = Just (idents, ty)
122 match (PrettyPrintForAll idents ty) = Just (idents, ty)
120 match _ = Nothing
123 match _ = Nothing
121
124
122−insertPlaceholders :: Type -> Type
125+insertPlaceholders :: RenderTypeOptions -> Type -> Type
123−insertPlaceholders =
126+insertPlaceholders opts =
124− everywhereOnTypesTopDown convertForAlls . everywhereOnTypes convert
127+ everywhereOnTypesTopDown convertForAlls . everywhereOnTypes (convert opts)
125
128
126dePrim :: Type -> Type
129dePrim :: Type -> Type
127dePrim ty@(TypeConstructor (Qualified _ name))
130dePrim ty@(TypeConstructor (Qualified _ name))
@@ -129,10 +132,10 @@ dePrim ty@(TypeConstructor (Qualified _ name))
129 TypeConstructor $ Qualified Nothing name
132 TypeConstructor $ Qualified Nothing name
130dePrim other = other
133dePrim other = other
131
134
132−convert :: Type -> Type
135+convert :: RenderTypeOptions -> Type -> Type
133−convert (TypeApp (TypeApp f arg) ret) | f == tyFunction = PrettyPrintFunction arg ret
136+convert _ (TypeApp (TypeApp f arg) ret) | f == tyFunction = PrettyPrintFunction arg ret
134−convert (TypeApp o r) | o == tyObject = PrettyPrintObject r
137+convert opts (TypeApp o r) | o == tyObject && prettyPrintObjects opts = PrettyPrintObject r
135−convert other = other
138+convert _ other = other
136
139
137convertForAlls :: Type -> Type
140convertForAlls :: Type -> Type
138convertForAlls (ForAll i ty _) = go [i] ty
141convertForAlls (ForAll i ty _) = go [i] ty
@@ -141,8 +144,8 @@ convertForAlls (ForAll i ty _) = go [i] ty
141 go idents other = PrettyPrintForAll idents other
144 go idents other = PrettyPrintForAll idents other
142convertForAlls other = other
145convertForAlls other = other
143
146
144−preprocessType :: Type -> Type
147+preprocessType :: RenderTypeOptions -> Type -> Type
145−preprocessType = dePrim . insertPlaceholders
148+preprocessType opts = dePrim . insertPlaceholders opts
146
149
147-- |
150-- |
148-- Render code representing a Kind
151-- Render code representing a Kind
@@ -154,12 +157,23 @@ renderKind = kind . prettyPrintKind
154-- Render code representing a Type, as it should appear inside parentheses
157-- Render code representing a Type, as it should appear inside parentheses
155--
158--
156renderTypeAtom :: Type -> RenderedCode
159renderTypeAtom :: Type -> RenderedCode
160+renderTypeAtom =
157−renderTypeAtom = fromMaybe (error "Incomplete pattern") . pattern matchTypeAtom () . preprocessType
161+ fromMaybe (error "Incomplete pattern") . pattern matchTypeAtom () . preprocessType defaultRenderTypeOptions
158
162
159
163
160-- |
164-- |
161-- Render code representing a Type
165-- Render code representing a Type
162--
166--
163renderType :: Type -> RenderedCode
167renderType :: Type -> RenderedCode
164−renderType = fromMaybe (error "Incomplete pattern") . pattern matchType () . preprocessType
168+renderType = renderTypeWithOptions defaultRenderTypeOptions
165
169
170+data RenderTypeOptions = RenderTypeOptions
171+ { prettyPrintObjects :: Bool
172+ }
173+
174+defaultRenderTypeOptions :: RenderTypeOptions
175+defaultRenderTypeOptions = RenderTypeOptions { prettyPrintObjects = True }
176+
177+renderTypeWithOptions :: RenderTypeOptions -> Type -> RenderedCode
178+renderTypeWithOptions opts =
179+ fromMaybe (error "Incomplete pattern") . pattern matchType () . preprocessType opts
src/Language/PureScript/Docs/Types.hs+274−98
@@ -10,9 +10,9 @@ module Language.PureScript.Docs.Types
10 where
10 where
11
11
12import Control.Arrow (first, (***))
12import Control.Arrow (first, (***))
13−import Control.Applicative ((<$>), (<*>))
13+import Control.Applicative ((<$>), (<*>), pure)
14+import Control.Monad (when)
14import Data.Functor ((<$))
15import Data.Functor ((<$))
15−import Data.Char
16import Data.Maybe (mapMaybe)
16import Data.Maybe (mapMaybe)
17import Data.Version
17import Data.Version
18import Data.Aeson ((.=))
18import Data.Aeson ((.=))
@@ -23,7 +23,7 @@ import Data.Text (Text)
23import Data.ByteString.Lazy (ByteString)
23import Data.ByteString.Lazy (ByteString)
24import qualified Data.Text as T
24import qualified Data.Text as T
25
25
26−import Web.Bower.PackageMeta hiding (Version)
26+import Web.Bower.PackageMeta hiding (Version, displayError)
27
27
28import qualified Language.PureScript as P
28import qualified Language.PureScript as P
29
29
@@ -39,11 +39,14 @@ data Package a = Package
39 { pkgMeta :: PackageMeta
39 { pkgMeta :: PackageMeta
40 , pkgVersion :: Version
40 , pkgVersion :: Version
41 , pkgVersionTag :: String
41 , pkgVersionTag :: String
42− , pkgModules :: [RenderedModule]
42+ , pkgModules :: [Module]
43 , pkgBookmarks :: [Bookmark]
43 , pkgBookmarks :: [Bookmark]
44 , pkgResolvedDependencies :: [(PackageName, Version)]
44 , pkgResolvedDependencies :: [(PackageName, Version)]
45 , pkgGithub :: (GithubUser, GithubRepo)
45 , pkgGithub :: (GithubUser, GithubRepo)
46 , pkgUploader :: a
46 , pkgUploader :: a
47+ , pkgCompilerVersion :: Version
48+ -- ^ The version of the PureScript compiler which was used to generate
49+ -- this data. We store this in order to reject packages which are too old.
47 }
50 }
48 deriving (Show, Eq, Ord)
51 deriving (Show, Eq, Ord)
49
52
@@ -63,50 +66,105 @@ verifyPackage verifiedUser Package{..} =
63 pkgResolvedDependencies
66 pkgResolvedDependencies
64 pkgGithub
67 pkgGithub
65 verifiedUser
68 verifiedUser
69+ pkgCompilerVersion
66
70
67packageName :: Package a -> PackageName
71packageName :: Package a -> PackageName
68packageName = bowerName . pkgMeta
72packageName = bowerName . pkgMeta
69
73
70−data RenderedModule = RenderedModule
74+data Module = Module
71− { rmName :: String
75+ { modName :: String
72− , rmComments :: Maybe String
76+ , modComments :: Maybe String
73− , rmDeclarations :: [RenderedDeclaration]
77+ , modDeclarations :: [Declaration]
74 }
78 }
75 deriving (Show, Eq, Ord)
79 deriving (Show, Eq, Ord)
76
80
77−data RenderedDeclaration = RenderedDeclaration
81+data Declaration = Declaration
78− { rdTitle :: String
82+ { declTitle :: String
79− , rdComments :: Maybe String
83+ , declComments :: Maybe String
80− , rdCode :: RenderedCode
81− , rdSourceSpan :: Maybe P.SourceSpan
84+ , declSourceSpan :: Maybe P.SourceSpan
82− , rdChildren :: [RenderedChildDeclaration]
85+ , declChildren :: [ChildDeclaration]
86+ , declFixity :: Maybe P.Fixity
87+ , declInfo :: DeclarationInfo
83 }
88 }
84 deriving (Show, Eq, Ord)
89 deriving (Show, Eq, Ord)
85
90
86−data RenderedChildDeclaration = RenderedChildDeclaration
91+-- |
87− { rcdTitle :: String
92+-- A value of this type contains information that is specific to a particular
88− , rcdComments :: Maybe String
93+-- kind of declaration (as opposed to information which exists in all kinds of
89− , rcdCode :: RenderedCode
94+-- declarations, which goes into the 'Declaration' type directly).
90− , rcdSourceSpan :: Maybe P.SourceSpan
95+--
91− , rcdType :: RenderedChildDeclarationType
96+-- Many of the constructors are very similar to their equivalents in the real
92− }
97+-- PureScript AST, except that they have their name elided, since this is
98+-- already available via the rdTitle field of 'Declaration'.
99+--
100+data DeclarationInfo
101+ -- |
102+ -- A value declaration, with its type.
103+ --
104+ = ValueDeclaration P.Type
105+
106+ -- |
107+ -- A data/newtype declaration, with the kind of declaration (data or
108+ -- newtype) and its type arguments. Constructors are represented as child
109+ -- declarations.
110+ --
111+ | DataDeclaration P.DataDeclType [(String, Maybe P.Kind)]
112+
113+ -- |
114+ -- A data type foreign import, with its kind.
115+ --
116+ | ExternDataDeclaration P.Kind
117+
118+ -- |
119+ -- A type synonym, with its type arguments and its type.
120+ --
121+ | TypeSynonymDeclaration [(String, Maybe P.Kind)] P.Type
122+
123+ -- |
124+ -- A type class, with its type arguments and its superclasses. Instances and
125+ -- members are represented as child declarations.
126+ --
127+ | TypeClassDeclaration [(String, Maybe P.Kind)] [P.Constraint]
93 deriving (Show, Eq, Ord)
128 deriving (Show, Eq, Ord)
94
129
95−data RenderedChildDeclarationType
130+declInfoToString :: DeclarationInfo -> String
96− = ChildInstance
131+declInfoToString (ValueDeclaration _) = "value"
97− | ChildDataConstructor
132+declInfoToString (DataDeclaration _ _) = "data"
98− | ChildTypeClassMember
133+declInfoToString (ExternDataDeclaration _) = "externData"
134+declInfoToString (TypeSynonymDeclaration _ _) = "typeSynonym"
135+declInfoToString (TypeClassDeclaration _ _) = "typeClass"
136+
137+data ChildDeclaration = ChildDeclaration
138+ { cdeclTitle :: String
139+ , cdeclComments :: Maybe String
140+ , cdeclSourceSpan :: Maybe P.SourceSpan
141+ , cdeclInfo :: ChildDeclarationInfo
142+ }
99− deriving (Show, Eq, Ord, Bounded, Enum)
143+ deriving (Show, Eq, Ord)
100
144
101−childDeclTypeToString :: RenderedChildDeclarationType -> String
145+data ChildDeclarationInfo
102−childDeclTypeToString = withHead toLower . drop 5 . show
146+ -- |
103− where
147+ -- A type instance declaration, with its dependencies and its type.
104− withHead f (x:xs) = f x : xs
148+ --
105− withHead _ [] = []
149+ = ChildInstance [P.Constraint] P.Type
150+
151+ -- |
152+ -- A data constructor, with its type arguments.
153+ --
154+ | ChildDataConstructor [P.Type]
155+
156+ -- |
157+ -- A type class member, with its type. Note that the type does not include
158+ -- the type class constraint; this may be added manually if desired. For
159+ -- example, `pure` from `Applicative` would be `forall a. a -> f a`.
160+ --
161+ | ChildTypeClassMember P.Type
162+ deriving (Show, Eq, Ord)
106
163
107−childDeclarationTypes :: [(String, RenderedChildDeclarationType)]
164+childDeclInfoToString :: ChildDeclarationInfo -> String
108−childDeclarationTypes =
165+childDeclInfoToString (ChildInstance _ _) = "instance"
109− map (\t -> (childDeclTypeToString t, t)) [minBound .. maxBound]
166+childDeclInfoToString (ChildDataConstructor _) = "dataConstructor"
167+childDeclInfoToString (ChildTypeClassMember _) = "typeClassMember"
110
168
111newtype GithubUser
169newtype GithubUser
112 = GithubUser { runGithubUser :: String }
170 = GithubUser { runGithubUser :: String }
@@ -117,10 +175,16 @@ newtype GithubRepo
117 deriving (Show, Eq, Ord)
175 deriving (Show, Eq, Ord)
118
176
119data PackageError
177data PackageError
178+ = CompilerTooOld Version Version
179+ -- ^ Minimum allowable version for generating data with the current
180+ -- parser, and actual version used.
120− = ErrorInPackageMeta BowerError
181+ | ErrorInPackageMeta BowerError
121 | InvalidVersion
182 | InvalidVersion
122− | InvalidDeclarationType
183+ | InvalidDeclarationType String
123− | InvalidRenderedCode String
184+ | InvalidChildDeclarationType String
185+ | InvalidFixity
186+ | InvalidKind String
187+ | InvalidDataDeclType String
124 deriving (Show, Eq, Ord)
188 deriving (Show, Eq, Ord)
125
189
126type Bookmark = InPackage (P.ModuleName, String)
190type Bookmark = InPackage (P.ModuleName, String)
@@ -148,25 +212,33 @@ ignorePackage (FromDep _ x) = x
148----------------------
212----------------------
149-- Parsing
213-- Parsing
150
214
151−parseUploadedPackage :: ByteString -> Either (ParseError PackageError) UploadedPackage
215+parseUploadedPackage :: Version -> ByteString -> Either (ParseError PackageError) UploadedPackage
152−parseUploadedPackage = parse asUploadedPackage
216+parseUploadedPackage minVersion = parse $ asUploadedPackage minVersion
217+
218+parseVerifiedPackage :: Version -> ByteString -> Either (ParseError PackageError) VerifiedPackage
219+parseVerifiedPackage minVersion = parse $ asVerifiedPackage minVersion
153
220
154−parseVerifiedPackage :: ByteString -> Either (ParseError PackageError) VerifiedPackage
221+asPackage :: Version -> (forall e. Parse e a) -> Parse PackageError (Package a)
155−parseVerifiedPackage = parse asVerifiedPackage
222+asPackage minimumVersion uploader = do
223+ -- If the compilerVersion key is missing, we can be sure that it was produced
224+ -- with 0.7.0.0, since that is the only released version that included the
225+ -- psc-publish tool before this key was added.
226+ compilerVersion <- keyOrDefault "compilerVersion" (Version [0,7,0,0] []) asVersion
227+ when (compilerVersion < minimumVersion)
228+ (throwCustomError $ CompilerTooOld minimumVersion compilerVersion)
156
229
157−asPackage :: (forall e. Parse e a) -> Parse PackageError (Package a)
158−asPackage uploader =
159 Package <$> key "packageMeta" asPackageMeta .! ErrorInPackageMeta
230 Package <$> key "packageMeta" asPackageMeta .! ErrorInPackageMeta
160 <*> key "version" asVersion
231 <*> key "version" asVersion
161 <*> key "versionTag" asString
232 <*> key "versionTag" asString
162− <*> key "modules" (eachInArray asRenderedModule)
233+ <*> key "modules" (eachInArray asModule)
163 <*> key "bookmarks" asBookmarks .! ErrorInPackageMeta
234 <*> key "bookmarks" asBookmarks .! ErrorInPackageMeta
164 <*> key "resolvedDependencies" asResolvedDependencies
235 <*> key "resolvedDependencies" asResolvedDependencies
165 <*> key "github" asGithub
236 <*> key "github" asGithub
166 <*> key "uploader" uploader
237 <*> key "uploader" uploader
238+ <*> pure compilerVersion
167
239
168−asUploadedPackage :: Parse PackageError UploadedPackage
240+asUploadedPackage :: Version -> Parse PackageError UploadedPackage
169−asUploadedPackage = asPackage asNotYetKnown
241+asUploadedPackage minVersion = asPackage minVersion asNotYetKnown
170
242
171asNotYetKnown :: Parse e NotYetKnown
243asNotYetKnown :: Parse e NotYetKnown
172asNotYetKnown = NotYetKnown <$ asNull
244asNotYetKnown = NotYetKnown <$ asNull
@@ -174,8 +246,35 @@ asNotYetKnown = NotYetKnown <$ asNull
174instance A.FromJSON NotYetKnown where
246instance A.FromJSON NotYetKnown where
175 parseJSON = toAesonParser' asNotYetKnown
247 parseJSON = toAesonParser' asNotYetKnown
176
248
177−asVerifiedPackage :: Parse PackageError VerifiedPackage
249+asVerifiedPackage :: Version -> Parse PackageError VerifiedPackage
178−asVerifiedPackage = asPackage asGithubUser
250+asVerifiedPackage minVersion = asPackage minVersion asGithubUser
251+
252+displayPackageError :: PackageError -> Text
253+displayPackageError e = case e of
254+ CompilerTooOld minV usedV ->
255+ "Expecting data produced by at least version " <> T.pack (showVersion minV)
256+ <> " of the compiler, but it appears that " <> T.pack (showVersion usedV)
257+ <> " was used."
258+ ErrorInPackageMeta err ->
259+ "Error in package metadata: " <> showBowerError err
260+ InvalidVersion ->
261+ "Invalid version"
262+ InvalidDeclarationType str ->
263+ "Invalid declaration type: \"" <> T.pack str <> "\""
264+ InvalidChildDeclarationType str ->
265+ "Invalid child declaration type: \"" <> T.pack str <> "\""
266+ InvalidFixity ->
267+ "Invalid fixity"
268+ InvalidKind str ->
269+ "Invalid kind: \"" <> T.pack str <> "\""
270+ InvalidDataDeclType str ->
271+ "Invalid data declaration type: \"" <> T.pack str <> "\""
272+ where
273+ (<>) = T.append
274+
275+instance A.FromJSON a => A.FromJSON (Package a) where
276+ parseJSON = toAesonParser displayPackageError
277+ (asPackage (Version [0,0,0,0] []) fromAesonParser)
179
278
180asGithubUser :: Parse e GithubUser
279asGithubUser :: Parse e GithubUser
181asGithubUser = GithubUser <$> asString
280asGithubUser = GithubUser <$> asString
@@ -183,11 +282,6 @@ asGithubUser = GithubUser <$> asString
183instance A.FromJSON GithubUser where
282instance A.FromJSON GithubUser where
184 parseJSON = toAesonParser' asGithubUser
283 parseJSON = toAesonParser' asGithubUser
185
284
186−instance A.FromJSON a => A.FromJSON (Package a) where
187− -- TODO: actual error display
188− parseJSON = toAesonParser (T.pack . show)
189− (asPackage fromAesonParser)
190−
191asVersion :: Parse PackageError Version
285asVersion :: Parse PackageError Version
192asVersion = withString (maybe (Left InvalidVersion) Right . parseVersion')
286asVersion = withString (maybe (Left InvalidVersion) Right . parseVersion')
193
287
@@ -197,39 +291,105 @@ parseVersion' str =
197 [(vers, "")] -> Just vers
291 [(vers, "")] -> Just vers
198 _ -> Nothing
292 _ -> Nothing
199
293
200−asRenderedModule :: Parse PackageError RenderedModule
294+asModule :: Parse PackageError Module
201−asRenderedModule =
295+asModule =
202− RenderedModule <$> key "name" asString
296+ Module <$> key "name" asString
203− <*> key "comments" (perhaps asString)
297+ <*> key "comments" (perhaps asString)
204− <*> key "declarations" (eachInArray asDeclaration)
298+ <*> key "declarations" (eachInArray asDeclaration)
205
299
206−asDeclaration :: Parse PackageError RenderedDeclaration
300+asDeclaration :: Parse PackageError Declaration
207asDeclaration =
301asDeclaration =
208− RenderedDeclaration <$> key "title" asString
302+ Declaration <$> key "title" asString
209− <*> key "comments" (perhaps asString)
303+ <*> key "comments" (perhaps asString)
210− <*> key "code" asRenderedCode .! InvalidRenderedCode
304+ <*> key "sourceSpan" (perhaps asSourceSpan)
211− <*> key "sourceSpan" (perhaps asSourceSpan)
305+ <*> key "children" (eachInArray asChildDeclaration)
212− <*> key "children" (eachInArray asRenderedChildDeclaration)
306+ <*> key "fixity" (perhaps asFixity)
213−
307+ <*> key "info" asDeclarationInfo
214−asRenderedChildDeclaration :: Parse PackageError RenderedChildDeclaration
308+
215−asRenderedChildDeclaration =
309+asFixity :: Parse PackageError P.Fixity
216− RenderedChildDeclaration <$> key "title" asString
310+asFixity = P.Fixity <$> key "associativity" asAssociativity
217− <*> key "comments" (perhaps asString)
311+ <*> key "precedence" asIntegral
218− <*> key "code" asRenderedCode .! InvalidRenderedCode
312+
219− <*> key "sourceSpan" (perhaps asSourceSpan)
313+parseAssociativity :: String -> Maybe P.Associativity
220− <*> key "type" asRenderedChildDeclarationType .!! InvalidDeclarationType
314+parseAssociativity str = case str of
315+ "infix" -> Just P.Infix
316+ "infixl" -> Just P.Infixl
317+ "infixr" -> Just P.Infixr
318+ _ -> Nothing
319+
320+asAssociativity :: Parse PackageError P.Associativity
321+asAssociativity = withString (maybe (Left InvalidFixity) Right . parseAssociativity)
322+
323+asDeclarationInfo :: Parse PackageError DeclarationInfo
324+asDeclarationInfo = do
325+ ty <- key "declType" asString
326+ case ty of
327+ "value" ->
328+ ValueDeclaration <$> key "type" asType
329+ "data" ->
330+ DataDeclaration <$> key "dataDeclType" asDataDeclType
331+ <*> key "typeArguments" asTypeArguments
332+ "externData" ->
333+ ExternDataDeclaration <$> key "kind" asKind
334+ "typeSynonym" ->
335+ TypeSynonymDeclaration <$> key "arguments" asTypeArguments
336+ <*> key "type" asType
337+ "typeClass" ->
338+ TypeClassDeclaration <$> key "arguments" asTypeArguments
339+ <*> key "superclasses" (eachInArray asConstraint)
340+ other ->
341+ throwCustomError (InvalidDeclarationType other)
342+
343+asTypeArguments :: Parse PackageError [(String, Maybe P.Kind)]
344+asTypeArguments = eachInArray asTypeArgument
221 where
345 where
222− p .!! err = p .! const err
346+ asTypeArgument = (,) <$> nth 0 asString <*> nth 1 (perhaps asKind)
347+
348+asKind :: Parse e P.Kind
349+asKind = fromAesonParser
350+
351+asType :: Parse e P.Type
352+asType = fromAesonParser
353+
354+asDataDeclType :: Parse PackageError P.DataDeclType
355+asDataDeclType =
356+ withString $ \s -> case s of
357+ "data" -> Right P.Data
358+ "newtype" -> Right P.Newtype
359+ other -> Left (InvalidDataDeclType other)
223
360
224−asRenderedChildDeclarationType :: Parse PackageError RenderedChildDeclarationType
361+asChildDeclaration :: Parse PackageError ChildDeclaration
225−asRenderedChildDeclarationType =
362+asChildDeclaration =
226− withString (maybe (Left InvalidDeclarationType) Right .
363+ ChildDeclaration <$> key "title" asString
227− flip lookup childDeclarationTypes)
364+ <*> key "comments" (perhaps asString)
365+ <*> key "sourceSpan" (perhaps asSourceSpan)
366+ <*> key "info" asChildDeclarationInfo
367+
368+asChildDeclarationInfo :: Parse PackageError ChildDeclarationInfo
369+asChildDeclarationInfo = do
370+ ty <- key "declType" asString
371+ case ty of
372+ "instance" ->
373+ ChildInstance <$> key "dependencies" (eachInArray asConstraint)
374+ <*> key "type" asType
375+ "dataConstructor" ->
376+ ChildDataConstructor <$> key "arguments" (eachInArray asType)
377+ "typeClassMember" ->
378+ ChildTypeClassMember <$> key "type" asType
379+ other ->
380+ throwCustomError $ InvalidChildDeclarationType other
228
381
229asSourcePos :: Parse e P.SourcePos
382asSourcePos :: Parse e P.SourcePos
230asSourcePos = P.SourcePos <$> nth 0 asIntegral
383asSourcePos = P.SourcePos <$> nth 0 asIntegral
231 <*> nth 1 asIntegral
384 <*> nth 1 asIntegral
232
385
386+asConstraint :: Parse PackageError P.Constraint
387+asConstraint = (,) <$> nth 0 asQualifiedProperName
388+ <*> nth 1 (eachInArray asType)
389+
390+asQualifiedProperName :: Parse e (P.Qualified P.ProperName)
391+asQualifiedProperName = fromAesonParser
392+
233asBookmarks :: Parse BowerError [Bookmark]
393asBookmarks :: Parse BowerError [Bookmark]
234asBookmarks = eachInArray asBookmark
394asBookmarks = eachInArray asBookmark
235
395
@@ -274,38 +434,54 @@ instance A.ToJSON a => A.ToJSON (Package a) where
274 pkgResolvedDependencies
434 pkgResolvedDependencies
275 , "github" .= pkgGithub
435 , "github" .= pkgGithub
276 , "uploader" .= pkgUploader
436 , "uploader" .= pkgUploader
437+ , "compilerVersion" .= showVersion P.version
277 ]
438 ]
278
439
279instance A.ToJSON NotYetKnown where
440instance A.ToJSON NotYetKnown where
280 toJSON _ = A.Null
441 toJSON _ = A.Null
281
442
282−instance A.ToJSON RenderedModule where
443+instance A.ToJSON Module where
283− toJSON RenderedModule{..} =
444+ toJSON Module{..} =
284− A.object [ "name" .= rmName
445+ A.object [ "name" .= modName
285− , "comments" .= rmComments
446+ , "comments" .= modComments
286− , "declarations" .= rmDeclarations
447+ , "declarations" .= modDeclarations
287 ]
448 ]
288
449
289−instance A.ToJSON RenderedDeclaration where
450+instance A.ToJSON Declaration where
290− toJSON RenderedDeclaration{..} =
451+ toJSON Declaration{..} =
291− A.object [ "title" .= rdTitle
452+ A.object [ "title" .= declTitle
292− , "comments" .= rdComments
453+ , "comments" .= declComments
293− , "code" .= rdCode
454+ , "sourceSpan" .= declSourceSpan
294− , "sourceSpan" .= rdSourceSpan
455+ , "children" .= declChildren
295− , "children" .= rdChildren
456+ , "fixity" .= declFixity
457+ , "info" .= declInfo
296 ]
458 ]
297
459
298−instance A.ToJSON RenderedChildDeclaration where
460+instance A.ToJSON ChildDeclaration where
299− toJSON RenderedChildDeclaration{..} =
461+ toJSON ChildDeclaration{..} =
300− A.object [ "title" .= rcdTitle
462+ A.object [ "title" .= cdeclTitle
301− , "comments" .= rcdComments
463+ , "comments" .= cdeclComments
302− , "code" .= rcdCode
464+ , "sourceSpan" .= cdeclSourceSpan
303− , "sourceSpan" .= rcdSourceSpan
465+ , "info" .= cdeclInfo
304− , "type" .= rcdType
305 ]
466 ]
306
467
307−instance A.ToJSON RenderedChildDeclarationType where
468+instance A.ToJSON DeclarationInfo where
308− toJSON = A.toJSON . childDeclTypeToString
469+ toJSON info = A.object $ "declType" .= declInfoToString info : props
470+ where
471+ props = case info of
472+ ValueDeclaration ty -> ["type" .= ty]
473+ DataDeclaration ty args -> ["dataDeclType" .= ty, "typeArguments" .= args]
474+ ExternDataDeclaration kind -> ["kind" .= kind]
475+ TypeSynonymDeclaration args ty -> ["arguments" .= args, "type" .= ty]
476+ TypeClassDeclaration args super -> ["arguments" .= args, "superclasses" .= super]
477+
478+instance A.ToJSON ChildDeclarationInfo where
479+ toJSON info = A.object $ "declType" .= childDeclInfoToString info : props
480+ where
481+ props = case info of
482+ ChildInstance deps ty -> ["dependencies" .= deps, "type" .= ty]
483+ ChildDataConstructor args -> ["arguments" .= args]
484+ ChildTypeClassMember ty -> ["type" .= ty]
309
485
310instance A.ToJSON GithubUser where
486instance A.ToJSON GithubUser where
311 toJSON = A.toJSON . runGithubUser
487 toJSON = A.toJSON . runGithubUser
src/Language/PureScript/Environment.hs+25−4
@@ -13,12 +13,15 @@
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
14
14
15{-# LANGUAGE DeriveDataTypeable #-}
15{-# LANGUAGE DeriveDataTypeable #-}
16+{-# LANGUAGE OverloadedStrings #-}
16
17
17module Language.PureScript.Environment where
18module Language.PureScript.Environment where
18
19
19import Data.Data
20import Data.Data
20import Data.Maybe (fromMaybe)
21import Data.Maybe (fromMaybe)
21import qualified Data.Map as M
22import qualified Data.Map as M
23+import qualified Data.Text as T
24+import qualified Data.Aeson as A
22
25
23import Language.PureScript.Kinds
26import Language.PureScript.Kinds
24import Language.PureScript.Names
27import Language.PureScript.Names
@@ -49,7 +52,7 @@ data Environment = Environment {
49 -- |
52 -- |
50 -- Available type class dictionaries
53 -- Available type class dictionaries
51 --
54 --
52− , typeClassDictionaries :: M.Map (Qualified Ident, Maybe ModuleName) TypeClassDictionaryInScope
55+ , typeClassDictionaries :: M.Map (Maybe ModuleName) (M.Map (Qualified ProperName) (M.Map (Qualified Ident) TypeClassDictionaryInScope))
53 -- |
56 -- |
54 -- Type classes
57 -- Type classes
55 --
58 --
@@ -137,6 +140,16 @@ instance Show DataDeclType where
137 show Data = "data"
140 show Data = "data"
138 show Newtype = "newtype"
141 show Newtype = "newtype"
139
142
143+instance A.ToJSON DataDeclType where
144+ toJSON = A.toJSON . show
145+
146+instance A.FromJSON DataDeclType where
147+ parseJSON = A.withText "DataDeclType" $ \str ->
148+ case str of
149+ "data" -> return Data
150+ "newtype" -> return Newtype
151+ other -> fail $ "invalid type: '" ++ T.unpack other ++ "'"
152+
140-- |
153-- |
141-- Construct a ProperName in the Prim module
154-- Construct a ProperName in the Prim module
142--
155--
@@ -201,9 +214,17 @@ tyObject = primTy "Object"
201-- Check whether a type is an object
214-- Check whether a type is an object
202--
215--
203isObject :: Type -> Bool
216isObject :: Type -> Bool
204−isObject = (==) tyObject . extract
217+isObject = isTypeOrApplied tyObject
205− where extract (TypeApp t _) = t
218+
206− extract t = t
219+-- |
220+-- Check whether a type is a function
221+--
222+isFunction :: Type -> Bool
223+isFunction = isTypeOrApplied tyFunction
224+
225+isTypeOrApplied :: Type -> Type -> Bool
226+isTypeOrApplied t1 (TypeApp t2 _) = t1 == t2
227+isTypeOrApplied t1 t2 = t1 == t2
207
228
208-- |
229-- |
209-- Smart constructor for function types
230-- Smart constructor for function types
src/Language/PureScript/Errors.hs+70−37
@@ -19,7 +19,7 @@
19module Language.PureScript.Errors where
19module Language.PureScript.Errors where
20
20
21import Data.Either (lefts, rights)
21import Data.Either (lefts, rights)
22−import Data.List (intercalate)
22+import Data.List (intercalate, transpose)
23import Data.Function (on)
23import Data.Function (on)
24import Data.Monoid
24import Data.Monoid
25import Data.Foldable (fold, foldMap)
25import Data.Foldable (fold, foldMap)
@@ -35,7 +35,7 @@ import Control.Monad.Trans.State.Lazy
35import Control.Arrow(first)
35import Control.Arrow(first)
36
36
37import Language.PureScript.AST
37import Language.PureScript.AST
38−import Language.PureScript.Environment (isObject)
38+import Language.PureScript.Environment (isObject, isFunction)
39import Language.PureScript.Pretty
39import Language.PureScript.Pretty
40import Language.PureScript.Types
40import Language.PureScript.Types
41import Language.PureScript.Names
41import Language.PureScript.Names
@@ -107,6 +107,7 @@ data SimpleErrorMessage
107 | ArgListLengthsDiffer Ident
107 | ArgListLengthsDiffer Ident
108 | OverlappingArgNames (Maybe Ident)
108 | OverlappingArgNames (Maybe Ident)
109 | MissingClassMember Ident
109 | MissingClassMember Ident
110+ | ExtraneousClassMember Ident
110 | ExpectedType Kind
111 | ExpectedType Kind
111 | IncorrectConstructorArity (Qualified ProperName)
112 | IncorrectConstructorArity (Qualified ProperName)
112 | SubsumptionCheckFailed
113 | SubsumptionCheckFailed
@@ -119,6 +120,8 @@ data SimpleErrorMessage
119 | TransitiveExportError DeclarationRef [DeclarationRef]
120 | TransitiveExportError DeclarationRef [DeclarationRef]
120 | ShadowedName Ident
121 | ShadowedName Ident
121 | WildcardInferredType Type
122 | WildcardInferredType Type
123+ | NotExhaustivePattern [[Binder]] Bool
124+ | OverlappingPattern [[Binder]] Bool
122 | ClassOperator ProperName Ident
125 | ClassOperator ProperName Ident
123 deriving (Show)
126 deriving (Show)
124
127
@@ -215,6 +218,7 @@ errorCode em = case unwrapErrorMessage em of
215 (ArgListLengthsDiffer _) -> "ArgListLengthsDiffer"
218 (ArgListLengthsDiffer _) -> "ArgListLengthsDiffer"
216 (OverlappingArgNames _) -> "OverlappingArgNames"
219 (OverlappingArgNames _) -> "OverlappingArgNames"
217 (MissingClassMember _) -> "MissingClassMember"
220 (MissingClassMember _) -> "MissingClassMember"
221+ (ExtraneousClassMember _) -> "ExtraneousClassMember"
218 (ExpectedType _) -> "ExpectedType"
222 (ExpectedType _) -> "ExpectedType"
219 (IncorrectConstructorArity _) -> "IncorrectConstructorArity"
223 (IncorrectConstructorArity _) -> "IncorrectConstructorArity"
220 SubsumptionCheckFailed -> "SubsumptionCheckFailed"
224 SubsumptionCheckFailed -> "SubsumptionCheckFailed"
@@ -227,6 +231,8 @@ errorCode em = case unwrapErrorMessage em of
227 (TransitiveExportError _ _) -> "TransitiveExportError"
231 (TransitiveExportError _ _) -> "TransitiveExportError"
228 (ShadowedName _) -> "ShadowedName"
232 (ShadowedName _) -> "ShadowedName"
229 (WildcardInferredType _) -> "WildcardInferredType"
233 (WildcardInferredType _) -> "WildcardInferredType"
234+ (NotExhaustivePattern _ _) -> "NotExhaustivePattern"
235+ (OverlappingPattern _ _) -> "OverlappingPattern"
230 (ClassOperator _ _) -> "ClassOperator"
236 (ClassOperator _ _) -> "ClassOperator"
231
237
232-- |
238-- |
@@ -236,10 +242,10 @@ newtype MultipleErrors = MultipleErrors
236 { runMultipleErrors :: [ErrorMessage] } deriving (Show, Monoid)
242 { runMultipleErrors :: [ErrorMessage] } deriving (Show, Monoid)
237
243
238instance UnificationError Type MultipleErrors where
244instance UnificationError Type MultipleErrors where
239− occursCheckFailed = occursCheckFailed
245+ occursCheckFailed t = MultipleErrors [occursCheckFailed t]
240
246
241instance UnificationError Kind MultipleErrors where
247instance UnificationError Kind MultipleErrors where
242− occursCheckFailed = occursCheckFailed
248+ occursCheckFailed k = MultipleErrors [occursCheckFailed k]
243
249
244-- | Check whether a collection of errors is empty or not.
250-- | Check whether a collection of errors is empty or not.
245nonEmpty :: MultipleErrors -> Bool
251nonEmpty :: MultipleErrors -> Bool
@@ -270,6 +276,9 @@ data LabelType = TypeLabel | SkolemLabel String deriving (Show, Eq, Ord)
270-- | A map from rigid type variable name/unknown variable pairs to new variables.
276-- | A map from rigid type variable name/unknown variable pairs to new variables.
271type UnknownMap = M.Map (LabelType, Unknown) Unknown
277type UnknownMap = M.Map (LabelType, Unknown) Unknown
272
278
279+-- | How critical the issue is
280+data Level = Error | Warning deriving Show
281+
273-- |
282-- |
274-- Extract nested error messages from wrapper errors
283-- Extract nested error messages from wrapper errors
275--
284--
@@ -342,8 +351,8 @@ onTypesInErrorMessageM f = g
342-- |
351-- |
343-- Pretty print a single error, simplifying if necessary
352-- Pretty print a single error, simplifying if necessary
344--
353--
345−prettyPrintSingleError :: Bool -> ErrorMessage -> State UnknownMap Box.Box
354+prettyPrintSingleError :: Bool -> Level -> ErrorMessage -> State UnknownMap Box.Box
346−prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
355+prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
347 where
356 where
348 -- |
357 -- |
349 -- Pretty print an ErrorMessage
358 -- Pretty print an ErrorMessage
@@ -371,7 +380,7 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
371 , indent . line $ path
380 , indent . line $ path
372 ]
381 ]
373 goSimple (ErrorParsingExterns err) =
382 goSimple (ErrorParsingExterns err) =
374− paras [ line "Error parsing externs files: "
383+ paras [ lineWithLevel "parsing externs files: "
375 , indent . line . show $ err
384 , indent . line . show $ err
376 ]
385 ]
377 goSimple (ErrorParsingFFIModule path) =
386 goSimple (ErrorParsingFFIModule path) =
@@ -436,9 +445,9 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
436 goSimple (UnknownDataConstructor dc tc) =
445 goSimple (UnknownDataConstructor dc tc) =
437 line $ "Unknown data constructor " ++ show dc ++ foldMap ((" for type constructor " ++) . show) tc
446 line $ "Unknown data constructor " ++ show dc ++ foldMap ((" for type constructor " ++) . show) tc
438 goSimple (ConflictingImport nm mn) =
447 goSimple (ConflictingImport nm mn) =
439− line $ "Cannot declare `" ++ nm ++ "` since another declaration of that name was imported from `" ++ show mn ++ "`"
448+ line $ "Cannot declare " ++ show nm ++ " since another declaration of that name was imported from " ++ show mn
440 goSimple (ConflictingImports nm m1 m2) =
449 goSimple (ConflictingImports nm m1 m2) =
441− line $ "Conflicting imports for " ++ nm ++ " from modules " ++ show m1 ++ " and " ++ show m2
450+ line $ "Conflicting imports for " ++ show nm ++ " from modules " ++ show m1 ++ " and " ++ show m2
442 goSimple (ConflictingTypeDecls nm) =
451 goSimple (ConflictingTypeDecls nm) =
443 line $ "Conflicting type declarations for " ++ show nm
452 line $ "Conflicting type declarations for " ++ show nm
444 goSimple (ConflictingCtorDecls nm) =
453 goSimple (ConflictingCtorDecls nm) =
@@ -513,6 +522,8 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
513 line $ "Overlapping names in function/binder" ++ foldMap ((" in declaration" ++) . show) ident
522 line $ "Overlapping names in function/binder" ++ foldMap ((" in declaration" ++) . show) ident
514 goSimple (MissingClassMember ident) =
523 goSimple (MissingClassMember ident) =
515 line $ "Member " ++ show ident ++ " has not been implemented"
524 line $ "Member " ++ show ident ++ " has not been implemented"
525+ goSimple (ExtraneousClassMember ident) =
526+ line $ "Member " ++ show ident ++ " is not a member of the class being instantiated"
516 goSimple (ExpectedType kind) =
527 goSimple (ExpectedType kind) =
517 line $ "Expected type of kind *, was " ++ prettyPrintKind kind
528 line $ "Expected type of kind *, was " ++ prettyPrintKind kind
518 goSimple (IncorrectConstructorArity nm) =
529 goSimple (IncorrectConstructorArity nm) =
@@ -552,56 +563,66 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
552 ]
563 ]
553 goSimple (WildcardInferredType ty) =
564 goSimple (WildcardInferredType ty) =
554 line $ "The wildcard type definition has the inferred type " ++ prettyPrintType ty
565 line $ "The wildcard type definition has the inferred type " ++ prettyPrintType ty
566+ goSimple (NotExhaustivePattern bs b) =
567+ indent $ paras $ [ line "Pattern could not be determined to cover all cases."
568+ , line $ "The definition has the following uncovered cases:\n"
569+ , Box.hsep 1 Box.left (map (paras . map (line . prettyPrintBinderAtom)) (transpose bs))
570+ ] ++ if not b then [line "..."] else []
571+ goSimple (OverlappingPattern bs b) =
572+ indent $ paras $ [ line "Redundant cases have been detected."
573+ , line $ "The definition has the following redundant cases:\n"
574+ , Box.hsep 1 Box.left (map (paras . map (line . prettyPrintBinderAtom)) (transpose bs))
575+ ] ++ if not b then [line "..."] else []
555 go (NotYetDefined names err) =
576 go (NotYetDefined names err) =
556 paras [ line $ "The following are not yet defined here: " ++ intercalate ", " (map show names) ++ ":"
577 paras [ line $ "The following are not yet defined here: " ++ intercalate ", " (map show names) ++ ":"
557 , indent $ go err
578 , indent $ go err
558 ]
579 ]
559 go (ErrorUnifyingTypes t1 t2 err) =
580 go (ErrorUnifyingTypes t1 t2 err) =
560− paras [ line "Error unifying type "
581+ paras [ lineWithLevel "unifying type "
561 , indent $ line $ prettyPrintType t1
582 , indent $ line $ prettyPrintType t1
562 , line "with type"
583 , line "with type"
563 , indent $ line $ prettyPrintType t2
584 , indent $ line $ prettyPrintType t2
564 , go err
585 , go err
565 ]
586 ]
566 go (ErrorInExpression expr err) =
587 go (ErrorInExpression expr err) =
567− paras [ line "Error in expression:"
588+ paras [ lineWithLevel "in expression:"
568 , indent $ line $ prettyPrintValue expr
589 , indent $ line $ prettyPrintValue expr
569 , go err
590 , go err
570 ]
591 ]
571 go (ErrorInModule mn err) =
592 go (ErrorInModule mn err) =
572− paras [ line $ "Error in module " ++ show mn ++ ":"
593+ paras [ lineWithLevel $ "in module " ++ show mn ++ ":"
573 , go err
594 , go err
574 ]
595 ]
575 go (ErrorInSubsumption t1 t2 err) =
596 go (ErrorInSubsumption t1 t2 err) =
576− paras [ line "Error checking that type "
597+ paras [ lineWithLevel "checking that type "
577 , indent $ line $ prettyPrintType t1
598 , indent $ line $ prettyPrintType t1
578 , line "subsumes type"
599 , line "subsumes type"
579 , indent $ line $ prettyPrintType t2
600 , indent $ line $ prettyPrintType t2
580 , go err
601 , go err
581 ]
602 ]
582 go (ErrorInInstance name ts err) =
603 go (ErrorInInstance name ts err) =
583− paras [ line $ "Error in type class instance " ++ show name ++ " " ++ unwords (map prettyPrintTypeAtom ts) ++ ":"
604+ paras [ lineWithLevel $ "in type class instance " ++ show name ++ " " ++ unwords (map prettyPrintTypeAtom ts) ++ ":"
584 , go err
605 , go err
585 ]
606 ]
586 go (ErrorCheckingKind ty err) =
607 go (ErrorCheckingKind ty err) =
587− paras [ line "Error checking kind of type "
608+ paras [ lineWithLevel "checking kind of type "
588 , indent $ line $ prettyPrintType ty
609 , indent $ line $ prettyPrintType ty
589 , go err
610 , go err
590 ]
611 ]
591 go (ErrorInferringType expr err) =
612 go (ErrorInferringType expr err) =
592− paras [ line "Error inferring type of value "
613+ paras [ lineWithLevel "inferring type of value "
593 , indent $ line $ prettyPrintValue expr
614 , indent $ line $ prettyPrintValue expr
594 , go err
615 , go err
595 ]
616 ]
596 go (ErrorCheckingType expr ty err) =
617 go (ErrorCheckingType expr ty err) =
597− paras [ line "Error checking that value "
618+ paras [ lineWithLevel "checking that value "
598 , indent $ line $ prettyPrintValue expr
619 , indent $ line $ prettyPrintValue expr
599 , line "has type"
620 , line "has type"
600 , indent $ line $ prettyPrintType ty
621 , indent $ line $ prettyPrintType ty
601 , go err
622 , go err
602 ]
623 ]
603 go (ErrorInApplication f t a err) =
624 go (ErrorInApplication f t a err) =
604− paras [ line "Error applying function"
625+ paras [ lineWithLevel "applying function"
605 , indent $ line $ prettyPrintValue f
626 , indent $ line $ prettyPrintValue f
606 , line "of type"
627 , line "of type"
607 , indent $ line $ prettyPrintType t
628 , indent $ line $ prettyPrintType t
@@ -610,35 +631,35 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
610 , go err
631 , go err
611 ]
632 ]
612 go (ErrorInDataConstructor nm err) =
633 go (ErrorInDataConstructor nm err) =
613− paras [ line $ "Error in data constructor " ++ show nm ++ ":"
634+ paras [ lineWithLevel $ "in data constructor " ++ show nm ++ ":"
614 , go err
635 , go err
615 ]
636 ]
616 go (ErrorInTypeConstructor nm err) =
637 go (ErrorInTypeConstructor nm err) =
617− paras [ line $ "Error in type constructor " ++ show nm ++ ":"
638+ paras [ lineWithLevel $ "in type constructor " ++ show nm ++ ":"
618 , go err
639 , go err
619 ]
640 ]
620 go (ErrorInBindingGroup nms err) =
641 go (ErrorInBindingGroup nms err) =
621− paras [ line $ "Error in binding group " ++ intercalate ", " (map show nms) ++ ":"
642+ paras [ lineWithLevel $ "in binding group " ++ intercalate ", " (map show nms) ++ ":"
622 , go err
643 , go err
623 ]
644 ]
624 go (ErrorInDataBindingGroup err) =
645 go (ErrorInDataBindingGroup err) =
625− paras [ line $ "Error in data binding group:"
646+ paras [ lineWithLevel $ "in data binding group:"
626 , go err
647 , go err
627 ]
648 ]
628 go (ErrorInTypeSynonym name err) =
649 go (ErrorInTypeSynonym name err) =
629− paras [ line $ "Error in type synonym " ++ show name ++ ":"
650+ paras [ lineWithLevel $ "in type synonym " ++ show name ++ ":"
630 , go err
651 , go err
631 ]
652 ]
632 go (ErrorInValueDeclaration n err) =
653 go (ErrorInValueDeclaration n err) =
633− paras [ line $ "Error in value declaration " ++ show n ++ ":"
654+ paras [ lineWithLevel $ "in value declaration " ++ show n ++ ":"
634 , go err
655 , go err
635 ]
656 ]
636 go (ErrorInForeignImport nm err) =
657 go (ErrorInForeignImport nm err) =
637− paras [ line $ "Error in foreign import " ++ show nm ++ ":"
658+ paras [ lineWithLevel $ "in foreign import " ++ show nm ++ ":"
638 , go err
659 , go err
639 ]
660 ]
640 go (PositionedError srcSpan err) =
661 go (PositionedError srcSpan err) =
641− paras [ line $ "Error at " ++ displaySourceSpan srcSpan ++ ":"
662+ paras [ lineWithLevel $ "at " ++ displaySourceSpan srcSpan ++ ":"
642 , indent $ go err
663 , indent $ go err
643 ]
664 ]
644 go (SimpleErrorWrapper sem) = goSimple sem
665 go (SimpleErrorWrapper sem) = goSimple sem
@@ -646,14 +667,17 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
646 line :: String -> Box.Box
667 line :: String -> Box.Box
647 line = Box.text
668 line = Box.text
648
669
670+ lineWithLevel :: String -> Box.Box
671+ lineWithLevel text = line $ show level ++ " " ++ text
672+
649 suggestions :: ErrorMessage -> [Box.Box]
673 suggestions :: ErrorMessage -> [Box.Box]
650 suggestions = suggestions' . unwrapErrorMessage
674 suggestions = suggestions' . unwrapErrorMessage
651 where
675 where
652− suggestions' (ConflictingImport nm im) = [ line $ "Possible fix: hide `" ++ nm ++ "` when importing `" ++ show im ++ "`:"
676+ suggestions' (ConflictingImport nm im) = [ line $ "Possible fix: hide " ++ show nm ++ " when importing " ++ show im ++ ":"
653 , indent . line $ "import " ++ show im ++ " hiding (" ++ nm ++ ")"
677 , indent . line $ "import " ++ show im ++ " hiding (" ++ nm ++ ")"
654 ]
678 ]
655 suggestions' (TypesDoNotUnify t1 t2)
679 suggestions' (TypesDoNotUnify t1 t2)
656− | any isObject [t1, t2] = [line "Note that function composition in PureScript is defined using `(<<<)`"]
680+ | isObject t1 && isFunction t2 = [line "Note that function composition in PureScript is defined using (<<<)"]
657 | otherwise = []
681 | otherwise = []
658 suggestions' _ = []
682 suggestions' _ = []
659
683
@@ -684,6 +708,7 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
684 prettyPrintExport (ValueRef ident) = show ident
708 prettyPrintExport (ValueRef ident) = show ident
685 prettyPrintExport (TypeClassRef pn) = show pn
709 prettyPrintExport (TypeClassRef pn) = show pn
686 prettyPrintExport (TypeInstanceRef ident) = show ident
710 prettyPrintExport (TypeInstanceRef ident) = show ident
711+ prettyPrintExport (ModuleRef name) = "module " ++ show name
687 prettyPrintExport (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref
712 prettyPrintExport (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref
688
713
689 -- |
714 -- |
@@ -722,24 +747,32 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
722-- Pretty print multiple errors
747-- Pretty print multiple errors
723--
748--
724prettyPrintMultipleErrors :: Bool -> MultipleErrors -> String
749prettyPrintMultipleErrors :: Bool -> MultipleErrors -> String
725−prettyPrintMultipleErrors full = flip evalState M.empty . prettyPrintMultipleErrorsWith "Error:" "Multiple errors:" full
750+prettyPrintMultipleErrors full = renderBox . prettyPrintMultipleErrorsBox full
726
751
727-- |
752-- |
728-- Pretty print multiple warnings
753-- Pretty print multiple warnings
729--
754--
730prettyPrintMultipleWarnings :: Bool -> MultipleErrors -> String
755prettyPrintMultipleWarnings :: Bool -> MultipleErrors -> String
731−prettyPrintMultipleWarnings full = flip evalState M.empty . prettyPrintMultipleErrorsWith "Warning:" "Multiple warnings:" full
756+prettyPrintMultipleWarnings full = renderBox . prettyPrintMultipleWarningsBox full
757+
758+-- | Pretty print warnings as a Box
759+prettyPrintMultipleWarningsBox :: Bool -> MultipleErrors -> Box.Box
760+prettyPrintMultipleWarningsBox full = flip evalState M.empty . prettyPrintMultipleErrorsWith Warning "Warning found:" "Multiple warnings found:" full
761+
762+-- | Pretty print errors as a Box
763+prettyPrintMultipleErrorsBox :: Bool -> MultipleErrors -> Box.Box
764+prettyPrintMultipleErrorsBox full = flip evalState M.empty . prettyPrintMultipleErrorsWith Error "Error found:" "Multiple errors found:" full
732
765
733−prettyPrintMultipleErrorsWith :: String -> String -> Bool -> MultipleErrors -> State UnknownMap String
766+prettyPrintMultipleErrorsWith :: Level -> String -> String -> Bool -> MultipleErrors -> State UnknownMap Box.Box
734−prettyPrintMultipleErrorsWith intro _ full (MultipleErrors [e]) = do
767+prettyPrintMultipleErrorsWith level intro _ full (MultipleErrors [e]) = do
735− result <- prettyPrintSingleError full e
768+ result <- prettyPrintSingleError full level e
736− return $ renderBox $
769+ return $
737 Box.vcat Box.left [ Box.text intro
770 Box.vcat Box.left [ Box.text intro
738 , result
771 , result
739 ]
772 ]
740−prettyPrintMultipleErrorsWith _ intro full (MultipleErrors es) = do
773+prettyPrintMultipleErrorsWith level _ intro full (MultipleErrors es) = do
741− result <- forM es $ (liftM $ Box.moveRight 2) . prettyPrintSingleError full
774+ result <- forM es $ (liftM $ Box.moveRight 2) . prettyPrintSingleError full level
742− return $ renderBox $
775+ return $
743 Box.vcat Box.left [ Box.text intro
776 Box.vcat Box.left [ Box.text intro
744 , Box.vsep 1 Box.left result
777 , Box.vsep 1 Box.left result
745 ]
778 ]
src/Language/PureScript/Kinds.hs+5−1
@@ -13,10 +13,12 @@
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
14
14
15{-# LANGUAGE DeriveDataTypeable #-}
15{-# LANGUAGE DeriveDataTypeable #-}
16+{-# LANGUAGE TemplateHaskell #-}
16
17
17module Language.PureScript.Kinds where
18module Language.PureScript.Kinds where
18
19
19import Data.Data
20import Data.Data
21+import qualified Data.Aeson.TH as A
20
22
21import Control.Applicative
23import Control.Applicative
22import Control.Monad.Unify (Unknown)
24import Control.Monad.Unify (Unknown)
@@ -44,7 +46,9 @@ data Kind
44 -- |
46 -- |
45 -- Function kinds
47 -- Function kinds
46 --
48 --
47− | FunKind Kind Kind deriving (Show, Eq, Data, Typeable)
49+ | FunKind Kind Kind deriving (Show, Eq, Ord, Data, Typeable)
50+
51+$(A.deriveJSON A.defaultOptions ''Kind)
48
52
49everywhereOnKinds :: (Kind -> Kind) -> Kind -> Kind
53everywhereOnKinds :: (Kind -> Kind) -> Kind -> Kind
50everywhereOnKinds f = go
54everywhereOnKinds f = go
src/Language/PureScript/Linter.hs+8−2
@@ -16,7 +16,7 @@
16{-# LANGUAGE FlexibleContexts #-}
16{-# LANGUAGE FlexibleContexts #-}
17{-# LANGUAGE ScopedTypeVariables #-}
17{-# LANGUAGE ScopedTypeVariables #-}
18
18
19−module Language.PureScript.Linter (lint) where
19+module Language.PureScript.Linter (lint, module L) where
20
20
21import Data.List (mapAccumL, nub)
21import Data.List (mapAccumL, nub)
22import Data.Maybe (mapMaybe)
22import Data.Maybe (mapMaybe)
@@ -30,6 +30,7 @@ import Control.Monad.Writer.Class
30import Language.PureScript.AST
30import Language.PureScript.AST
31import Language.PureScript.Names
31import Language.PureScript.Names
32import Language.PureScript.Errors
32import Language.PureScript.Errors
33+import Language.PureScript.Linter.Exhaustive as L
33
34
34-- | Lint the PureScript AST.
35-- | Lint the PureScript AST.
35-- |
36-- |
@@ -52,7 +53,12 @@ lint (Module _ mn ds _) = censor (onErrorMessages (ErrorInModule mn)) $ mapM_ li
52 lintDeclaration :: Declaration -> m ()
53 lintDeclaration :: Declaration -> m ()
53 lintDeclaration d =
54 lintDeclaration d =
54 let (f, _, _, _, _) = everythingWithContextOnValues moduleNames mempty mappend stepD stepE stepB def def
55 let (f, _, _, _, _) = everythingWithContextOnValues moduleNames mempty mappend stepD stepE stepB def def
55− in tell (f d)
56+
57+ f' :: Declaration -> MultipleErrors
58+ f' (PositionedDeclaration pos _ dec) = onErrorMessages (PositionedError pos) (f' dec)
59+ f' dec = f dec
60+
61+ in tell (f' d)
56 where
62 where
57 def s _ = (s, mempty)
63 def s _ = (s, mempty)
58
64
src/Language/PureScript/Linter/Exhaustive.hsnew file+285
@@ -0,0 +1,285 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Exhaustive
4+-- Copyright : (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+-- | Module for exhaustivity checking over pattern matching definitions
13+-- | The algorithm analyses the clauses of a definition one by one from top
14+-- | to bottom, where in each step it has the cases already missing (uncovered),
15+-- | and it generates the new set of missing cases.
16+--
17+-----------------------------------------------------------------------------
18+
19+{-# LANGUAGE FlexibleContexts #-}
20+{-# LANGUAGE ScopedTypeVariables #-}
21+
22+module Language.PureScript.Linter.Exhaustive
23+ ( checkExhaustive
24+ , checkExhaustiveModule
25+ ) where
26+
27+import qualified Data.Map as M
28+import Data.Maybe (fromMaybe)
29+import Data.List (foldl', sortBy, nub)
30+import Data.Function (on)
31+
32+import Control.Monad (unless)
33+import Control.Applicative
34+import Control.Arrow (first, second)
35+import Control.Monad.Writer.Class
36+
37+import Language.PureScript.AST.Binders
38+import Language.PureScript.AST.Declarations
39+import Language.PureScript.Environment
40+import Language.PureScript.Names as P
41+import Language.PureScript.Kinds
42+import Language.PureScript.Types as P
43+import Language.PureScript.Errors
44+
45+import Language.PureScript.AST.Traversals (everywhereOnValuesTopDownM)
46+
47+-- |
48+-- Qualifies a propername from a given qualified propername and a default module name
49+--
50+qualifyName :: a -> ModuleName -> Qualified a -> Qualified a
51+qualifyName n defmn qn = Qualified (Just mn) n
52+ where
53+ (mn, _) = qualify defmn qn
54+
55+-- |
56+-- Given an environment and a datatype or newtype name,
57+-- this function returns the associated data constructors if it is the case of a datatype
58+-- where: - ProperName is the name of the constructor (for example, "Nothing" in Maybe)
59+-- - [Type] is the list of arguments, if it has (for example, "Just" has [TypeVar "a"])
60+--
61+getConstructors :: Environment -> ModuleName -> (Qualified ProperName) -> [(ProperName, [Type])]
62+getConstructors env defmn n = extractConstructors lnte
63+ where
64+ qpn :: Qualified ProperName
65+ qpn = getConsDataName n
66+
67+ getConsDataName :: (Qualified ProperName) -> (Qualified ProperName)
68+ getConsDataName con = qualifyName nm defmn con
69+ where
70+ nm = case getConsInfo con of
71+ Nothing -> error $ "ProperName " ++ show con ++ " not in the scope of the current environment in getConsDataName."
72+ Just (_, pm, _, _) -> pm
73+
74+ getConsInfo :: (Qualified ProperName) -> Maybe (DataDeclType, ProperName, Type, [Ident])
75+ getConsInfo con = M.lookup con dce
76+ where
77+ dce :: M.Map (Qualified ProperName) (DataDeclType, ProperName, Type, [Ident])
78+ dce = dataConstructors env
79+
80+ lnte :: Maybe (Kind, TypeKind)
81+ lnte = M.lookup qpn (types env)
82+
83+ extractConstructors :: Maybe (Kind, TypeKind) -> [(ProperName, [Type])]
84+ extractConstructors (Just (_, DataType _ pt)) = pt
85+ extractConstructors _ = error "Data name not in the scope of the current environment in extractConstructors"
86+
87+-- |
88+-- Replicates a wildcard binder
89+--
90+initialize :: Int -> [Binder]
91+initialize l = replicate l NullBinder
92+
93+-- |
94+-- Applies a function over two lists of tuples that may lack elements
95+--
96+genericMerge :: Ord a =>
97+ (a -> Maybe b -> Maybe c -> d) ->
98+ [(a, b)] ->
99+ [(a, c)] ->
100+ [d]
101+genericMerge _ [] [] = []
102+genericMerge f bs [] = map (\(s, b) -> f s (Just b) Nothing) bs
103+genericMerge f [] bs = map (\(s, b) -> f s Nothing (Just b)) bs
104+genericMerge f bsl@((s, b):bs) bsr@((s', b'):bs')
105+ | s < s' = (f s (Just b) Nothing) : genericMerge f bs bsr
106+ | s > s' = (f s' Nothing (Just b')) : genericMerge f bsl bs'
107+ | otherwise = (f s (Just b) (Just b')) : genericMerge f bs bs'
108+
109+-- |
110+-- Find the uncovered set between two binders:
111+-- the first binder is the case we are trying to cover, the second one is the matching binder
112+--
113+missingCasesSingle :: Environment -> ModuleName -> Binder -> Binder -> ([Binder], Maybe Bool)
114+missingCasesSingle _ _ _ NullBinder = ([], Just True)
115+missingCasesSingle _ _ _ (VarBinder _) = ([], Just True)
116+missingCasesSingle env mn (VarBinder _) b = missingCasesSingle env mn NullBinder b
117+missingCasesSingle env mn br (NamedBinder _ bl) = missingCasesSingle env mn br bl
118+missingCasesSingle env mn NullBinder cb@(ConstructorBinder con _) =
119+ (concatMap (\cp -> fst $ missingCasesSingle env mn cp cb) allPatterns, Just True)
120+ where
121+ allPatterns = map (\(p, t) -> ConstructorBinder (qualifyName p mn con) (initialize $ length t))
122+ $ getConstructors env mn con
123+missingCasesSingle env mn cb@(ConstructorBinder con bs) (ConstructorBinder con' bs')
124+ | con == con' = let (bs'', pr) = missingCasesMultiple env mn bs bs' in (map (ConstructorBinder con) bs'', pr)
125+ | otherwise = ([cb], Just False)
126+missingCasesSingle env mn NullBinder (ObjectBinder bs) =
127+ (map (ObjectBinder . zip (map fst bs)) allMisses, pr)
128+ where
129+ (allMisses, pr) = missingCasesMultiple env mn (initialize $ length bs) (map snd bs)
130+missingCasesSingle env mn (ObjectBinder bs) (ObjectBinder bs') =
131+ (map (ObjectBinder . zip sortedNames) allMisses, pr)
132+ where
133+ (allMisses, pr) = uncurry (missingCasesMultiple env mn) (unzip binders)
134+
135+ sortNames = sortBy (compare `on` fst)
136+
137+ (sbs, sbs') = (sortNames bs, sortNames bs')
138+
139+ compB :: a -> Maybe a -> Maybe a -> (a, a)
140+ compB e b b' = (fm b, fm b')
141+ where
142+ fm = fromMaybe e
143+
144+ compBS :: Eq a => b -> a -> Maybe b -> Maybe b -> (a, (b, b))
145+ compBS e s b b' = (s, compB e b b')
146+
147+ (sortedNames, binders) = unzip $ genericMerge (compBS NullBinder) sbs sbs'
148+missingCasesSingle _ _ NullBinder (BooleanBinder b) = ([BooleanBinder $ not b], Just True)
149+missingCasesSingle _ _ (BooleanBinder bl) (BooleanBinder br)
150+ | bl == br = ([], Just True)
151+ | otherwise = ([BooleanBinder bl], Just False)
152+missingCasesSingle env mn b (PositionedBinder _ _ cb) = missingCasesSingle env mn b cb
153+missingCasesSingle _ _ b _ = ([b], Nothing)
154+
155+-- |
156+-- Returns the uncovered set of binders
157+-- the first argument is the list of uncovered binders at step i
158+-- the second argument is the (i+1)th clause of a pattern matching definition
159+--
160+-- The idea of the algorithm is as follows:
161+-- it processes each binder of the two lists (say, `x` and `y`) one by one
162+-- at each step two cases arises:
163+-- - there are no missing cases between `x` and `y`: this is very straightforward, it continues with the remaining cases
164+-- but keeps the uncovered binder in its position.
165+-- - there are missing cases, let us call it the set `U`: on the one hand, we mix each new uncovered case in `U`
166+-- with the current tail of uncovered set. On the other hand, it continues with the remaining cases: here we
167+-- can use `x` (but it will generate overlapping cases), or `y`, which will generate non-overlapping cases.
168+--
169+-- As an example, consider:
170+--
171+-- data N = Z | S N
172+-- f Z Z = Z --> {[S _, _], [Z, S _]} which are the right non-overlapping cases (GHC uses this).
173+--
174+-- if we use `x` instead of `y` (in this case, `y` stands for `Z` and `x` for `_`) we obtain:
175+-- f Z Z = Z --> {[S _, _], [_, S _]} you can see that both cases overlaps each other.
176+--
177+-- Up to now, we've decided to use `x` just because we expect to generate uncovered cases which might be
178+-- redundant or not, but uncovered at least. If we use `y` instead, we'll need to have a redundancy checker
179+-- (which ought to be available soon), or increase the complexity of the algorithm.
180+--
181+missingCasesMultiple :: Environment -> ModuleName -> [Binder] -> [Binder] -> ([[Binder]], Maybe Bool)
182+missingCasesMultiple env mn = go
183+ where
184+ go [] [] = ([], pure True)
185+ go (x:xs) (y:ys) = (map (: xs) miss1 ++ map (x :) miss2, liftA2 (&&) pr1 pr2)
186+ where
187+ (miss1, pr1) = missingCasesSingle env mn x y
188+ (miss2, pr2) = go xs ys
189+ go _ _ = error "Argument lengths did not match in missingCasesMultiple."
190+
191+-- |
192+-- Guard handling
193+--
194+-- We say a guard is exhaustive iff it has an `otherwise` (or `true`) expression.
195+-- Example:
196+-- f x | x < 0 = 0
197+-- | otherwise = 1
198+-- is exhaustive, whereas `f x | x < 0` is not
199+--
200+-- The function below say whether or not a guard has an `otherwise` expression
201+-- It is considered that `otherwise` is defined in Prelude
202+--
203+isExhaustiveGuard :: Either [(Guard, Expr)] Expr -> Bool
204+isExhaustiveGuard (Left gs) = not . null $ filter (\(g, _) -> isOtherwise g) gs
205+ where
206+ isOtherwise :: Expr -> Bool
207+ isOtherwise (TypedValue _ (BooleanLiteral True) _) = True
208+ isOtherwise (TypedValue _ (Var (Qualified (Just (ModuleName [ProperName "Prelude"])) (Ident "otherwise"))) _) = True
209+ isOtherwise _ = False
210+isExhaustiveGuard (Right _) = True
211+
212+-- |
213+-- Returns the uncovered set of case alternatives
214+--
215+missingCases :: Environment -> ModuleName -> [Binder] -> CaseAlternative -> ([[Binder]], Maybe Bool)
216+missingCases env mn uncovered ca = missingCasesMultiple env mn uncovered (caseAlternativeBinders ca)
217+
218+missingAlternative :: Environment -> ModuleName -> CaseAlternative -> [Binder] -> ([[Binder]], Maybe Bool)
219+missingAlternative env mn ca uncovered
220+ | isExhaustiveGuard (caseAlternativeResult ca) = mcases
221+ | otherwise = ([uncovered], snd mcases)
222+ where
223+ mcases = missingCases env mn uncovered ca
224+
225+-- |
226+-- Main exhaustivity checking function
227+-- Starting with the set `uncovered = { _ }` (nothing covered, one `_` for each function argument),
228+-- it partitions that set with the new uncovered cases, until it consumes the whole set of clauses.
229+-- Then, returns the uncovered set of case alternatives.
230+--
231+checkExhaustive :: forall m. (MonadWriter MultipleErrors m) => Environment -> ModuleName -> [CaseAlternative] -> m ()
232+checkExhaustive env mn cas = makeResult . first nub $ foldl' step ([initial], (pure True, [])) cas
233+ where
234+ step :: ([[Binder]], (Maybe Bool, [[Binder]])) -> CaseAlternative -> ([[Binder]], (Maybe Bool, [[Binder]]))
235+ step (uncovered, (nec, redundant)) ca =
236+ let (missed, pr) = unzip (map (missingAlternative env mn ca) uncovered)
237+ cond = or <$> sequenceA pr
238+ in (concat missed, (liftA2 (&&) cond nec,
239+ if fromMaybe True cond then redundant else caseAlternativeBinders ca : redundant))
240+ where
241+ sequenceA = foldr (liftA2 (:)) (pure [])
242+
243+ initial :: [Binder]
244+ initial = initialize numArgs
245+ where
246+ numArgs = length . caseAlternativeBinders . head $ cas
247+
248+ makeResult :: ([[Binder]], (Maybe Bool, [[Binder]])) -> m ()
249+ makeResult (bss, (_, bss')) =
250+ do unless (null bss) tellExhaustive
251+ unless (null bss') tellRedundant
252+ where
253+ tellExhaustive = tell . errorMessage . uncurry NotExhaustivePattern . second null . splitAt 5 $ bss
254+ tellRedundant = tell . errorMessage . uncurry OverlappingPattern . second null . splitAt 5 $ bss'
255+
256+-- |
257+-- Exhaustivity checking over a list of declarations
258+--
259+checkExhaustiveDecls :: forall m. (Applicative m, MonadWriter MultipleErrors m) => Environment -> ModuleName -> [Declaration] -> m ()
260+checkExhaustiveDecls env mn ds =
261+ let (f, _, _) = everywhereOnValuesTopDownM return checkExpr return
262+
263+ f' :: Declaration -> m Declaration
264+ f' d@(BindingGroupDeclaration bs) = mapM_ (f' . convert) bs >> return d
265+ where
266+ convert :: (Ident, NameKind, Expr) -> Declaration
267+ convert (name, nk, e) = ValueDeclaration name nk [] (Right e)
268+ f' d@(ValueDeclaration name _ _ _) = censor (onErrorMessages (ErrorInValueDeclaration name)) $ f d
269+ f' (PositionedDeclaration pos com dec) = PositionedDeclaration pos com <$> censor (onErrorMessages (PositionedError pos)) (f' dec)
270+ -- Don't generate two warnings for desugared dictionaries.
271+ f' d@TypeInstanceDeclaration{} = return d
272+ f' d = f d
273+
274+ in mapM_ f' ds
275+ where
276+ checkExpr :: Expr -> m Expr
277+ checkExpr c@(Case _ cas) = checkExhaustive env mn cas >> return c
278+ checkExpr other = return other
279+
280+-- |
281+-- Exhaustivity checking over a single module
282+--
283+checkExhaustiveModule :: forall m. (Applicative m, MonadWriter MultipleErrors m) => Environment -> Module -> m ()
284+checkExhaustiveModule env (Module _ mn ds _) = censor (onErrorMessages (ErrorInModule mn)) $ checkExhaustiveDecls env mn ds
285+
src/Language/PureScript/Make.hsnew file+318
@@ -0,0 +1,318 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Make
4+-- Copyright : (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+{-# LANGUAGE DataKinds #-}
16+{-# LANGUAGE FlexibleContexts #-}
17+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
18+{-# LANGUAGE TupleSections #-}
19+{-# LANGUAGE RankNTypes #-}
20+{-# LANGUAGE RecordWildCards #-}
21+{-# LANGUAGE ScopedTypeVariables #-}
22+
23+module Language.PureScript.Make
24+ (
25+ -- * Make API
26+ RebuildPolicy(..)
27+ , ProgressMessage(..), renderProgressMessage
28+ , MakeActions(..)
29+ , Externs()
30+ , make
31+
32+ -- * Implementation of Make API using files on disk
33+ , Make(..)
34+ , runMake
35+ , buildMakeActions
36+ ) where
37+
38+import Control.Applicative
39+import Control.Arrow ((&&&))
40+import Control.Monad
41+import Control.Monad.Error.Class (MonadError(..))
42+import Control.Monad.Trans.Except
43+import Control.Monad.Reader
44+import Control.Monad.Writer
45+import Control.Monad.Supply
46+
47+import Data.Function (on)
48+import Data.List (sortBy, groupBy)
49+import Data.Maybe (fromMaybe)
50+import Data.Time.Clock
51+import Data.Foldable (for_)
52+import Data.Traversable (traverse)
53+import Data.Version (showVersion)
54+import qualified Data.Map as M
55+import qualified Data.Set as S
56+
57+import System.Directory
58+ (doesFileExist, getModificationTime, createDirectoryIfMissing)
59+import System.FilePath ((</>), takeDirectory)
60+import System.IO.Error (tryIOError)
61+
62+
63+import Language.PureScript.AST
64+import Language.PureScript.CodeGen.Externs (moduleToPs)
65+import Language.PureScript.Environment
66+import Language.PureScript.Errors
67+import Language.PureScript.Linter
68+import Language.PureScript.ModuleDependencies
69+import Language.PureScript.Names
70+import Language.PureScript.Options
71+import Language.PureScript.Parser
72+import Language.PureScript.Pretty
73+import Language.PureScript.Renamer
74+import Language.PureScript.Sugar
75+import Language.PureScript.TypeChecker
76+import qualified Language.PureScript.Constants as C
77+
78+import qualified Language.PureScript.CodeGen.JS as J
79+import qualified Language.PureScript.CoreFn as CF
80+import qualified Paths_purescript as Paths
81+
82+-- | Progress messages from the make process
83+data ProgressMessage
84+ = CompilingModule ModuleName
85+ deriving (Show, Eq, Ord)
86+
87+-- | Render a progress message
88+renderProgressMessage :: ProgressMessage -> String
89+renderProgressMessage (CompilingModule mn) = "Compiling " ++ runModuleName mn
90+
91+-- | Actions that require implementations when running in "make" mode.
92+--
93+-- This type exists to make two things abstract:
94+--
95+-- * The particular backend being used (Javascript, C++11, etc.)
96+--
97+-- * The details of how files are read/written etc.
98+--
99+data MakeActions m = MakeActions {
100+ -- |
101+ -- Get the timestamp for the input file(s) for a module. If there are multiple
102+ -- files (.purs and foreign files, for example) the timestamp should be for
103+ -- the most recently modified file.
104+ --
105+ getInputTimestamp :: ModuleName -> m (Either RebuildPolicy (Maybe UTCTime))
106+ -- |
107+ -- Get the timestamp for the output files for a module. This should be the
108+ -- timestamp for the oldest modified file, or Nothing if any of the required
109+ -- output files are missing.
110+ --
111+ , getOutputTimestamp :: ModuleName -> m (Maybe UTCTime)
112+ -- |
113+ -- Read the externs file for a module as a string and also return the actual
114+ -- path for the file.
115+ , readExterns :: ModuleName -> m (FilePath, String)
116+ -- |
117+ -- Run the code generator for the module and write any required output files.
118+ --
119+ , codegen :: CF.Module CF.Ann -> Environment -> Externs -> SupplyT m ()
120+ -- |
121+ -- Respond to a progress update.
122+ --
123+ , progress :: ProgressMessage -> m ()
124+ }
125+
126+-- |
127+-- Generated code for an externs file.
128+--
129+type Externs = String
130+
131+-- |
132+-- Determines when to rebuild a module
133+--
134+data RebuildPolicy
135+ -- | Never rebuild this module
136+ = RebuildNever
137+ -- | Always rebuild this module
138+ | RebuildAlways deriving (Show, Eq, Ord)
139+
140+-- |
141+-- Compiles in "make" mode, compiling each module separately to a js files and an externs file
142+--
143+-- If timestamps have not changed, the externs file can be used to provide the module's types without
144+-- having to typecheck the module again.
145+--
146+make :: forall m. (Functor m, Applicative m, Monad m, MonadReader Options m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
147+ => MakeActions m
148+ -> [Module]
149+ -> m Environment
150+make MakeActions{..} ms = do
151+ (sorted, graph) <- sortModules $ map importPrim ms
152+ toRebuild <- foldM (\s (Module _ moduleName' _ _) -> do
153+ inputTimestamp <- getInputTimestamp moduleName'
154+ outputTimestamp <- getOutputTimestamp moduleName'
155+ return $ case (inputTimestamp, outputTimestamp) of
156+ (Right (Just t1), Just t2) | t1 < t2 -> s
157+ (Left RebuildNever, Just _) -> s
158+ _ -> S.insert moduleName' s) S.empty sorted
159+
160+ marked <- rebuildIfNecessary (reverseDependencies graph) toRebuild sorted
161+ for_ marked $ \(willRebuild, m) -> when willRebuild (lint m)
162+ (desugared, nextVar) <- runSupplyT 0 $ zip (map fst marked) <$> desugar (map snd marked)
163+ evalSupplyT nextVar $ go initEnvironment desugared
164+ where
165+
166+ go :: Environment -> [(Bool, Module)] -> SupplyT m Environment
167+ go env [] = return env
168+ go env ((False, m) : ms') = do
169+ (_, env') <- lift . runCheck' env $ typeCheckModule Nothing m
170+ go env' ms'
171+ go env ((True, m@(Module coms moduleName' _ exps)) : ms') = do
172+ lift . progress $ CompilingModule moduleName'
173+ (checked@(Module _ _ elaborated _), env') <- lift . runCheck' env $ typeCheckModule Nothing m
174+ checkExhaustiveModule env' checked
175+ regrouped <- createBindingGroups moduleName' . collapseBindingGroups $ elaborated
176+ let mod' = Module coms moduleName' regrouped exps
177+ corefn = CF.moduleToCoreFn env' mod'
178+ [renamed] = renameInModules [corefn]
179+ exts = moduleToPs mod' env'
180+ codegen renamed env' exts
181+ go env' ms'
182+
183+ rebuildIfNecessary :: M.Map ModuleName [ModuleName] -> S.Set ModuleName -> [Module] -> m [(Bool, Module)]
184+ rebuildIfNecessary _ _ [] = return []
185+ rebuildIfNecessary graph toRebuild (m@(Module _ moduleName' _ _) : ms') | moduleName' `S.member` toRebuild = do
186+ let deps = fromMaybe [] $ moduleName' `M.lookup` graph
187+ toRebuild' = toRebuild `S.union` S.fromList deps
188+ (:) (True, m) <$> rebuildIfNecessary graph toRebuild' ms'
189+ rebuildIfNecessary graph toRebuild (Module _ moduleName' _ _ : ms') = do
190+ (path, externs) <- readExterns moduleName'
191+ externsModules <- fmap (map snd) . alterErrors $ parseModulesFromFiles id [(path, externs)]
192+ case externsModules of
193+ [m'@(Module _ moduleName'' _ _)] | moduleName'' == moduleName' -> (:) (False, m') <$> rebuildIfNecessary graph toRebuild ms'
194+ _ -> throwError . errorMessage . InvalidExternsFile $ path
195+ where
196+ alterErrors = flip catchError $ \(MultipleErrors errs) ->
197+ throwError . MultipleErrors $ flip map errs $ \e -> case e of
198+ SimpleErrorWrapper (ErrorParsingModule err) -> SimpleErrorWrapper (ErrorParsingExterns err)
199+ _ -> e
200+
201+reverseDependencies :: ModuleGraph -> M.Map ModuleName [ModuleName]
202+reverseDependencies g = combine [ (dep, mn) | (mn, deps) <- g, dep <- deps ]
203+ where
204+ combine :: (Ord a) => [(a, b)] -> M.Map a [b]
205+ combine = M.fromList . map ((fst . head) &&& map snd) . groupBy ((==) `on` fst) . sortBy (compare `on` fst)
206+
207+-- |
208+-- Add an import declaration for a module if it does not already explicitly import it.
209+--
210+addDefaultImport :: ModuleName -> Module -> Module
211+addDefaultImport toImport m@(Module coms mn decls exps) =
212+ if isExistingImport `any` decls || mn == toImport then m
213+ else Module coms mn (ImportDeclaration toImport Implicit Nothing : decls) exps
214+ where
215+ isExistingImport (ImportDeclaration mn' _ _) | mn' == toImport = True
216+ isExistingImport (PositionedDeclaration _ _ d) = isExistingImport d
217+ isExistingImport _ = False
218+
219+importPrim :: Module -> Module
220+importPrim = addDefaultImport (ModuleName [ProperName C.prim])
221+
222+-- |
223+-- A monad for running make actions
224+--
225+newtype Make a = Make { unMake :: ReaderT Options (WriterT MultipleErrors (ExceptT MultipleErrors IO)) a }
226+ deriving (Functor, Applicative, Monad, MonadIO, MonadError MultipleErrors, MonadWriter MultipleErrors, MonadReader Options)
227+
228+-- |
229+-- Execute a 'Make' monad, returning either errors, or the result of the compile plus any warnings.
230+--
231+runMake :: Options -> Make a -> IO (Either MultipleErrors (a, MultipleErrors))
232+runMake opts = runExceptT . runWriterT . flip runReaderT opts . unMake
233+
234+makeIO :: (IOError -> ErrorMessage) -> IO a -> Make a
235+makeIO f io = do
236+ e <- liftIO $ tryIOError io
237+ either (throwError . singleError . f) return e
238+
239+-- Traverse (Either e) instance (base 4.7)
240+traverseEither :: Applicative f => (a -> f b) -> Either e a -> f (Either e b)
241+traverseEither _ (Left x) = pure (Left x)
242+traverseEither f (Right y) = Right <$> f y
243+
244+-- |
245+-- A set of make actions that read and write modules from the given directory.
246+--
247+buildMakeActions :: FilePath -- ^ the output directory
248+ -> M.Map ModuleName (Either RebuildPolicy String) -- ^ a map between module names and paths to the file containing the PureScript module
249+ -> M.Map ModuleName (FilePath, ForeignJS) -- ^ a map between module name and the file containing the foreign javascript for the module
250+ -> Bool -- ^ Generate a prefix comment?
251+ -> MakeActions Make
252+buildMakeActions outputDir filePathMap foreigns usePrefix =
253+ MakeActions getInputTimestamp getOutputTimestamp readExterns codegen progress
254+ where
255+
256+ getInputTimestamp :: ModuleName -> Make (Either RebuildPolicy (Maybe UTCTime))
257+ getInputTimestamp mn = do
258+ let path = fromMaybe (error "Module has no filename in 'make'") $ M.lookup mn filePathMap
259+ e1 <- traverseEither getTimestamp path
260+ fPath <- maybe (return Nothing) (getTimestamp . fst) $ M.lookup mn foreigns
261+ return $ fmap (max fPath) e1
262+
263+ getOutputTimestamp :: ModuleName -> Make (Maybe UTCTime)
264+ getOutputTimestamp mn = do
265+ let filePath = runModuleName mn
266+ jsFile = outputDir </> filePath </> "index.js"
267+ externsFile = outputDir </> filePath </> "externs.purs"
268+ min <$> getTimestamp jsFile <*> getTimestamp externsFile
269+
270+ readExterns :: ModuleName -> Make (FilePath, String)
271+ readExterns mn = do
272+ let path = outputDir </> runModuleName mn </> "externs.purs"
273+ (path, ) <$> readTextFile path
274+
275+ codegen :: CF.Module CF.Ann -> Environment -> Externs -> SupplyT Make ()
276+ codegen m _ exts = do
277+ let mn = CF.moduleName m
278+ foreignInclude <- case mn `M.lookup` foreigns of
279+ Just (path, _)
280+ | not $ requiresForeign m -> do
281+ tell $ errorMessage $ UnnecessaryFFIModule mn path
282+ return Nothing
283+ | otherwise -> return $ Just $ J.JSApp (J.JSVar "require") [J.JSStringLiteral "./foreign"]
284+ Nothing | requiresForeign m -> throwError . errorMessage $ MissingFFIModule mn
285+ | otherwise -> return Nothing
286+ pjs <- prettyPrintJS <$> J.moduleToJs m foreignInclude
287+ let filePath = runModuleName mn
288+ jsFile = outputDir </> filePath </> "index.js"
289+ externsFile = outputDir </> filePath </> "externs.purs"
290+ foreignFile = outputDir </> filePath </> "foreign.js"
291+ prefix = ["Generated by psc version " ++ showVersion Paths.version | usePrefix]
292+ js = unlines $ map ("// " ++) prefix ++ [pjs]
293+ lift $ do
294+ writeTextFile jsFile js
295+ maybe (return ()) (writeTextFile foreignFile . snd) $ mn `M.lookup` foreigns
296+ writeTextFile externsFile exts
297+
298+ requiresForeign :: CF.Module a -> Bool
299+ requiresForeign = not . null . CF.moduleForeign
300+
301+ getTimestamp :: FilePath -> Make (Maybe UTCTime)
302+ getTimestamp path = makeIO (const (SimpleErrorWrapper $ CannotGetFileInfo path)) $ do
303+ exists <- doesFileExist path
304+ traverse (const $ getModificationTime path) $ guard exists
305+
306+ readTextFile :: FilePath -> Make String
307+ readTextFile path = makeIO (const (SimpleErrorWrapper $ CannotReadFile path)) $ readFile path
308+
309+ writeTextFile :: FilePath -> String -> Make ()
310+ writeTextFile path text = makeIO (const (SimpleErrorWrapper $ CannotWriteFile path)) $ do
311+ mkdirp path
312+ writeFile path text
313+ where
314+ mkdirp :: FilePath -> IO ()
315+ mkdirp = createDirectoryIfMissing True . takeDirectory
316+
317+ progress :: ProgressMessage -> Make ()
318+ progress = liftIO . putStrLn . renderProgressMessage
src/Language/PureScript/Names.hs+18−1
@@ -13,12 +13,15 @@
13--
13--
14-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
15
15
16−{-# LANGUAGE DeriveDataTypeable, DeriveFunctor #-}
16+{-# LANGUAGE DeriveDataTypeable, DeriveFunctor, GADTs #-}
17
17
18module Language.PureScript.Names where
18module Language.PureScript.Names where
19
19
20import Data.List
20import Data.List
21import Data.Data
21import Data.Data
22+import Data.List.Split (splitOn)
23+import qualified Data.Aeson as A
24+import qualified Data.Text as T
22
25
23-- |
26-- |
24-- Names for value identifiers
27-- Names for value identifiers
@@ -77,6 +80,20 @@ instance (Show a) => Show (Qualified a) where
77 show (Qualified Nothing a) = show a
80 show (Qualified Nothing a) = show a
78 show (Qualified (Just name) a) = show name ++ "." ++ show a
81 show (Qualified (Just name) a) = show name ++ "." ++ show a
79
82
83+instance (a ~ ProperName) => A.ToJSON (Qualified a) where
84+ toJSON = A.toJSON . show
85+
86+instance (a ~ ProperName) => A.FromJSON (Qualified a) where
87+ parseJSON =
88+ A.withText "Qualified ProperName" $ \str ->
89+ return $ case reverse (splitOn "." (T.unpack str)) of
90+ [name] -> Qualified Nothing (ProperName name)
91+ (name:rest) -> Qualified (Just (reconstructModuleName rest)) (ProperName name)
92+ _ -> Qualified Nothing (ProperName "")
93+ where
94+ reconstructModuleName = moduleNameFromString . intercalate "." . reverse
95+
96+
80-- |
97-- |
81-- Provide a default module name, if a name is unqualified
98-- Provide a default module name, if a name is unqualified
82--
99--
src/Language/PureScript/Options.hs+5−44
@@ -13,76 +13,37 @@
13--
13--
14-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
15
15
16−{-# LANGUAGE GADTs, DataKinds, StandaloneDeriving #-}
17−
18module Language.PureScript.Options where
16module Language.PureScript.Options where
19
17
20−-- |
21−-- Indicates the mode of the compiler. Lifted using DataKinds to refine the Options type.
22−--
23−data Mode = Compile | Make
24−
25−-- |
26−-- Per-mode options
27−--
28−data ModeOptions mode where
29− CompileOptions :: String -> [String] -> [String] -> ModeOptions Compile
30− MakeOptions :: ModeOptions Make
31−
32−browserNamespace :: ModeOptions Compile -> String
33−browserNamespace (CompileOptions ns _ _) = ns
34−
35−entryPointModules :: ModeOptions Compile -> [String]
36−entryPointModules (CompileOptions _ ms _) = ms
37−
38−codeGenModules :: ModeOptions Compile -> [String]
39−codeGenModules (CompileOptions _ _ ms) = ms
40−
41−deriving instance Show (ModeOptions mode)
42−
43-- |
18-- |
44-- The data type of compiler options
19-- The data type of compiler options
45--
20--
46−data Options mode = Options {
21+data Options = Options {
47 -- |
22 -- |
48 -- Disable tail-call elimination
23 -- Disable tail-call elimination
49− --
50 optionsNoTco :: Bool
24 optionsNoTco :: Bool
51 -- |
25 -- |
52 -- Disable inlining of calls to return and bind for the Eff monad
26 -- Disable inlining of calls to return and bind for the Eff monad
53− --
54 , optionsNoMagicDo :: Bool
27 , optionsNoMagicDo :: Bool
55 -- |
28 -- |
56 -- When specified, checks the type of `main` in the module, and generate a call to run main
29 -- When specified, checks the type of `main` in the module, and generate a call to run main
57 -- after the module definitions.
30 -- after the module definitions.
58− --
59 , optionsMain :: Maybe String
31 , optionsMain :: Maybe String
60 -- |
32 -- |
61 -- Skip all optimizations
33 -- Skip all optimizations
62− --
63 , optionsNoOptimizations :: Bool
34 , optionsNoOptimizations :: Bool
64 -- |
35 -- |
65 -- Verbose error message
36 -- Verbose error message
66− --
67 , optionsVerboseErrors :: Bool
37 , optionsVerboseErrors :: Bool
68 -- |
38 -- |
69 -- Remove the comments from the generated js
39 -- Remove the comments from the generated js
70 , optionsNoComments :: Bool
40 , optionsNoComments :: Bool
71 -- |
41 -- |
72− -- Specify the namespace that PureScript modules will be exported to when running in the
42+ -- The path to prepend to require statements
73− -- browser.
43+ , optionsRequirePath :: Maybe FilePath
74− --
75− , optionsAdditional :: ModeOptions mode
76 } deriving Show
44 } deriving Show
77
45
78−-- |
79−-- Default compiler options
80−--
81−defaultCompileOptions :: Options Compile
82−defaultCompileOptions = Options False False Nothing False False False (CompileOptions "PS" [] [])
83−
84-- |
46-- |
85-- Default make options
47-- Default make options
86−--
48+defaultOptions :: Options
87−defaultMakeOptions :: Options Make
49+defaultOptions = Options False False Nothing False False False Nothing
88−defaultMakeOptions = Options False False Nothing False False False MakeOptions
src/Language/PureScript/Parser/Declarations.hs+9−1
@@ -186,11 +186,19 @@ parseImportDeclaration' = do
186
186
187
187
188parseDeclarationRef :: TokenParser DeclarationRef
188parseDeclarationRef :: TokenParser DeclarationRef
189−parseDeclarationRef = withSourceSpan PositionedDeclarationRef $
189+parseDeclarationRef =
190+ parseModuleRef <|> (
191+ withSourceSpan PositionedDeclarationRef $
190 ValueRef <$> parseIdent
192 ValueRef <$> parseIdent
191 <|> do name <- properName
193 <|> do name <- properName
192 dctors <- P.optionMaybe $ parens (symbol' ".." *> pure Nothing <|> Just <$> commaSep properName)
194 dctors <- P.optionMaybe $ parens (symbol' ".." *> pure Nothing <|> Just <$> commaSep properName)
193 return $ maybe (TypeClassRef name) (TypeRef name) dctors
195 return $ maybe (TypeClassRef name) (TypeRef name) dctors
196+ )
197+ where
198+ parseModuleRef :: TokenParser DeclarationRef
199+ parseModuleRef = do
200+ name <- indented *> reserved "module" *> moduleName
201+ return $ ModuleRef name
194
202
195parseTypeClassDeclaration :: TokenParser Declaration
203parseTypeClassDeclaration :: TokenParser Declaration
196parseTypeClassDeclaration = do
204parseTypeClassDeclaration = do
src/Language/PureScript/Pretty/JS.hs+1
@@ -163,6 +163,7 @@ string s = '"' : concatMap encodeChar s ++ "\""
163 encodeChar '\\' = "\\\\"
163 encodeChar '\\' = "\\\\"
164 encodeChar c | fromEnum c > 0xFFF = "\\u" ++ showHex (fromEnum c) ""
164 encodeChar c | fromEnum c > 0xFFF = "\\u" ++ showHex (fromEnum c) ""
165 encodeChar c | fromEnum c > 0xFF = "\\u0" ++ showHex (fromEnum c) ""
165 encodeChar c | fromEnum c > 0xFF = "\\u0" ++ showHex (fromEnum c) ""
166+ encodeChar c | fromEnum c > 0x7E || fromEnum c < 0x20 = "\\x" ++ showHex (fromEnum c) ""
166 encodeChar c = [c]
167 encodeChar c = [c]
167
168
168conditional :: Pattern PrinterState JS ((JS, JS), JS)
169conditional :: Pattern PrinterState JS ((JS, JS), JS)
src/Language/PureScript/Pretty/Values.hs+40−64
@@ -15,7 +15,8 @@
15
15
16module Language.PureScript.Pretty.Values (
16module Language.PureScript.Pretty.Values (
17 prettyPrintValue,
17 prettyPrintValue,
18− prettyPrintBinder
18+ prettyPrintBinder,
19+ prettyPrintBinderAtom
19) where
20) where
20
21
21import Data.Maybe (fromMaybe)
22import Data.Maybe (fromMaybe)
@@ -40,11 +41,7 @@ literals = mkPattern' match
40 match (CharLiteral c) = return $ show c
41 match (CharLiteral c) = return $ show c
41 match (BooleanLiteral True) = return "true"
42 match (BooleanLiteral True) = return "true"
42 match (BooleanLiteral False) = return "false"
43 match (BooleanLiteral False) = return "false"
43− match (ArrayLiteral xs) = concat <$> sequence
44+ match (ArrayLiteral xs) = return $ "[" ++ intercalate ", " (map prettyPrintValue xs) ++ "]"
44− [ return "[ "
45− , withIndent $ prettyPrintMany prettyPrintValue' xs
46− , return " ]"
47− ]
48 match (ObjectLiteral ps) = prettyPrintObject' $ second Just `map` ps
45 match (ObjectLiteral ps) = prettyPrintObject' $ second Just `map` ps
49 match (ObjectConstructor ps) = prettyPrintObject' ps
46 match (ObjectConstructor ps) = prettyPrintObject' ps
50 match (ObjectGetter prop) = return $ "(." ++ prop ++ ")"
47 match (ObjectGetter prop) = return $ "(." ++ prop ++ ")"
@@ -71,7 +68,7 @@ literals = mkPattern' match
71 ]
68 ]
72 match (Var ident) = return $ show ident
69 match (Var ident) = return $ show ident
73 match (Do els) = concat <$> sequence
70 match (Do els) = concat <$> sequence
74− [ return "do "
71+ [ return "do\n"
75 , withIndent $ prettyPrintMany prettyPrintDoNotationElement els
72 , withIndent $ prettyPrintMany prettyPrintDoNotationElement els
76 , currentIndent
73 , currentIndent
77 ]
74 ]
@@ -95,11 +92,14 @@ prettyPrintDeclaration _ = error "Invalid argument to prettyPrintDeclaration"
95prettyPrintCaseAlternative :: CaseAlternative -> StateT PrinterState Maybe String
92prettyPrintCaseAlternative :: CaseAlternative -> StateT PrinterState Maybe String
96prettyPrintCaseAlternative (CaseAlternative binders result) =
93prettyPrintCaseAlternative (CaseAlternative binders result) =
97 concat <$> sequence
94 concat <$> sequence
98− [ intercalate ", " <$> forM binders prettyPrintBinder'
95+ [ return (unwords (map prettyPrintBinderAtom binders))
99 , prettyPrintResult result
96 , prettyPrintResult result
100 ]
97 ]
101 where
98 where
102− prettyPrintResult (Left gs) = concat <$> mapM prettyPrintGuardedValue gs
99+ prettyPrintResult (Left gs) = concat <$> sequence
100+ [ return "\n"
101+ , withIndent $ prettyPrintMany prettyPrintGuardedValue gs
102+ ]
103 prettyPrintResult (Right v) = (" -> " ++) <$> prettyPrintValue' v
103 prettyPrintResult (Right v) = (" -> " ++) <$> prettyPrintValue' v
104
104
105 prettyPrintGuardedValue (grd, val) =
105 prettyPrintGuardedValue (grd, val) =
@@ -108,7 +108,6 @@ prettyPrintCaseAlternative (CaseAlternative binders result) =
108 , prettyPrintValue' grd
108 , prettyPrintValue' grd
109 , return " -> "
109 , return " -> "
110 , prettyPrintValue' val
110 , prettyPrintValue' val
111− , return "\n"
112 ]
111 ]
113
112
114prettyPrintDoNotationElement :: DoNotationElement -> StateT PrinterState Maybe String
113prettyPrintDoNotationElement :: DoNotationElement -> StateT PrinterState Maybe String
@@ -116,7 +115,7 @@ prettyPrintDoNotationElement (DoNotationValue val) =
116 prettyPrintValue' val
115 prettyPrintValue' val
117prettyPrintDoNotationElement (DoNotationBind binder val) =
116prettyPrintDoNotationElement (DoNotationBind binder val) =
118 concat <$> sequence
117 concat <$> sequence
119− [ prettyPrintBinder' binder
118+ [ return (prettyPrintBinder binder)
120 , return " <- "
119 , return " <- "
121 , prettyPrintValue' val
120 , prettyPrintValue' val
122 ]
121 ]
@@ -129,13 +128,10 @@ prettyPrintDoNotationElement (PositionedDoNotationElement _ _ el) = prettyPrintD
129
128
130prettyPrintObject' :: [(String, Maybe Expr)] -> StateT PrinterState Maybe String
129prettyPrintObject' :: [(String, Maybe Expr)] -> StateT PrinterState Maybe String
131prettyPrintObject' [] = return "{}"
130prettyPrintObject' [] = return "{}"
132−prettyPrintObject' ps = concat <$> sequence
131+prettyPrintObject' ps = return $ "{ " ++ intercalate ", " (map prettyPrintObjectProperty ps) ++ "}"
133− [ return "{\n"
132+ where
134− , withIndent $ prettyPrintMany prettyPrintObjectProperty ps
133+ prettyPrintObjectProperty :: (String, Maybe Expr) -> String
135− , return "\n"
134+ prettyPrintObjectProperty (key, value) = prettyPrintObjectKey key ++ ": " ++ maybe "_" prettyPrintValue value
136− , currentIndent
137− , return "}"
138− ]
139
135
140ifThenElse :: Pattern PrinterState Expr ((Expr, Expr), Expr)
136ifThenElse :: Pattern PrinterState Expr ((Expr, Expr), Expr)
141ifThenElse = mkPattern match
137ifThenElse = mkPattern match
@@ -188,55 +184,35 @@ prettyPrintValue' = runKleisli $ runPattern matchValue
188 , [ Wrap ifThenElse $ \(th, el) cond -> "if " ++ cond ++ " then " ++ prettyPrintValue th ++ " else " ++ prettyPrintValue el ]
184 , [ Wrap ifThenElse $ \(th, el) cond -> "if " ++ cond ++ " then " ++ prettyPrintValue th ++ " else " ++ prettyPrintValue el ]
189 ]
185 ]
190
186
191−prettyPrintBinderAtom :: Pattern PrinterState Binder String
187+prettyPrintBinderAtom :: Binder -> String
192−prettyPrintBinderAtom = mkPattern' match
188+prettyPrintBinderAtom NullBinder = "_"
189+prettyPrintBinderAtom (StringBinder str) = show str
190+prettyPrintBinderAtom (CharBinder c) = show c
191+prettyPrintBinderAtom (NumberBinder num) = either show show num
192+prettyPrintBinderAtom (BooleanBinder True) = "true"
193+prettyPrintBinderAtom (BooleanBinder False) = "false"
194+prettyPrintBinderAtom (VarBinder ident) = show ident
195+prettyPrintBinderAtom (ConstructorBinder ctor []) = show ctor
196+prettyPrintBinderAtom (ObjectBinder bs) =
197+ "{ "
198+ ++ intercalate ", " (map prettyPrintObjectPropertyBinder bs)
199+ ++ " }"
193 where
200 where
194− match :: Binder -> StateT PrinterState Maybe String
201+ prettyPrintObjectPropertyBinder :: (String, Binder) -> String
195− match NullBinder = return "_"
202+ prettyPrintObjectPropertyBinder (key, binder) = prettyPrintObjectKey key ++ ": " ++ prettyPrintBinder binder
196− match (StringBinder str) = return $ show str
203+prettyPrintBinderAtom (ArrayBinder bs) =
197− match (CharBinder c) = return $ show c
204+ "[ "
198− match (NumberBinder num) = return $ either show show num
205+ ++ intercalate ", " (map prettyPrintBinder bs)
199− match (BooleanBinder True) = return "true"
206+ ++ " ]"
200− match (BooleanBinder False) = return "false"
207+prettyPrintBinderAtom (NamedBinder ident binder) = show ident ++ "@" ++ prettyPrintBinder binder
201− match (VarBinder ident) = return $ show ident
208+prettyPrintBinderAtom (PositionedBinder _ _ binder) = prettyPrintBinderAtom binder
202− match (ConstructorBinder ctor args) = concat <$> sequence
209+prettyPrintBinderAtom b = parens (prettyPrintBinder b)
203− [ return $ show ctor ++ " "
204− , unwords <$> forM args match
205− ]
206− match (ObjectBinder bs) = concat <$> sequence
207− [ return "{\n"
208− , withIndent $ prettyPrintMany prettyPrintObjectPropertyBinder bs
209− , currentIndent
210− , return "}"
211− ]
212− match (ArrayBinder bs) = concat <$> sequence
213− [ return "["
214− , unwords <$> mapM prettyPrintBinder' bs
215− , return "]"
216− ]
217− match (NamedBinder ident binder) = ((show ident ++ "@") ++) <$> prettyPrintBinder' binder
218− match (PositionedBinder _ _ binder) = prettyPrintBinder' binder
219
210
220-- |
211-- |
221-- Generate a pretty-printed string representing a Binder
212-- Generate a pretty-printed string representing a Binder
222--
213--
223prettyPrintBinder :: Binder -> String
214prettyPrintBinder :: Binder -> String
224−prettyPrintBinder = fromMaybe (error "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyPrintBinder'
215+prettyPrintBinder (ConstructorBinder ctor []) = show ctor
225−
216+prettyPrintBinder (ConstructorBinder ctor args) = show ctor ++ " " ++ unwords (map prettyPrintBinderAtom args)
226−prettyPrintBinder' :: Binder -> StateT PrinterState Maybe String
217+prettyPrintBinder (PositionedBinder _ _ binder) = prettyPrintBinder binder
227−prettyPrintBinder' = runKleisli $ runPattern matchBinder
218+prettyPrintBinder b = prettyPrintBinderAtom b
228− where
229− matchBinder :: Pattern PrinterState Binder String
230− matchBinder = prettyPrintBinderAtom <+> fmap parens matchBinder
231−
232−prettyPrintObjectPropertyBinder :: (String, Binder) -> StateT PrinterState Maybe String
233−prettyPrintObjectPropertyBinder (key, binder) = concat <$> sequence
234− [ return $ prettyPrintObjectKey key ++ ": "
235− , prettyPrintBinder' binder
236− ]
237−
238−prettyPrintObjectProperty :: (String, Maybe Expr) -> StateT PrinterState Maybe String
239−prettyPrintObjectProperty (key, value) = concat <$> sequence
240− [ return $ prettyPrintObjectKey key ++ ": "
241− , maybe (pure "_") prettyPrintValue' value
242− ]
src/Language/PureScript/Publish.hsnew file+361
@@ -0,0 +1,361 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE RecordWildCards #-}
3+{-# LANGUAGE TupleSections #-}
4+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5+
6+module Language.PureScript.Publish
7+ ( preparePackage
8+ , preparePackage'
9+ , PrepareM()
10+ , runPrepareM
11+ , PublishOptions(..)
12+ , defaultPublishOptions
13+ , getGitWorkingTreeStatus
14+ , requireCleanWorkingTree
15+ , getVersionFromGitTag
16+ , getBowerInfo
17+ , getModulesAndBookmarks
18+ , getResolvedDependencies
19+ ) where
20+
21+import Prelude hiding (userError)
22+
23+import Data.Maybe
24+import Data.Char (isSpace)
25+import Data.String (fromString)
26+import Data.List (stripPrefix, isSuffixOf, (\\), nubBy)
27+import Data.List.Split (splitOn)
28+import Data.List.NonEmpty (NonEmpty(..))
29+import Data.Version
30+import Data.Function (on)
31+import Safe (headMay)
32+import Data.Aeson.BetterErrors
33+import qualified Data.Text as T
34+
35+import Control.Applicative
36+import Control.Category ((>>>))
37+import Control.Arrow ((***))
38+import Control.Exception (catch, try)
39+import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
40+import Control.Monad.Trans.Except
41+import Control.Monad.Error.Class (MonadError(..))
42+import Control.Monad.Writer
43+
44+import System.Directory (doesFileExist, findExecutable)
45+import System.Process (readProcess)
46+import System.Exit (exitFailure)
47+import System.FilePath (pathSeparator)
48+import qualified System.FilePath.Glob as Glob
49+import qualified System.Info
50+
51+import Web.Bower.PackageMeta (PackageMeta(..), BowerError(..), PackageName,
52+ runPackageName, parsePackageName, Repository(..))
53+import qualified Web.Bower.PackageMeta as Bower
54+
55+import qualified Language.PureScript as P (version)
56+import qualified Language.PureScript.Docs as D
57+import Language.PureScript.Publish.Utils
58+import Language.PureScript.Publish.ErrorsWarnings
59+
60+data PublishOptions = PublishOptions
61+ { -- | How to obtain the version tag and version that the data being
62+ -- generated will refer to.
63+ publishGetVersion :: PrepareM (String, Version)
64+ }
65+
66+defaultPublishOptions :: PublishOptions
67+defaultPublishOptions = PublishOptions
68+ { publishGetVersion = getVersionFromGitTag
69+ }
70+
71+-- | Attempt to retrieve package metadata from the current directory.
72+-- Calls exitFailure if no package metadata could be retrieved.
73+preparePackage :: PublishOptions -> IO D.UploadedPackage
74+preparePackage opts =
75+ runPrepareM (preparePackage' opts)
76+ >>= either (\e -> printError e >> exitFailure)
77+ handleWarnings
78+ where
79+ handleWarnings (result, warns) = do
80+ printWarnings warns
81+ return result
82+
83+newtype PrepareM a =
84+ PrepareM { unPrepareM :: WriterT [PackageWarning] (ExceptT PackageError IO) a }
85+ deriving (Functor, Applicative, Monad,
86+ MonadWriter [PackageWarning],
87+ MonadError PackageError)
88+
89+-- This MonadIO instance ensures that IO errors don't crash the program.
90+instance MonadIO PrepareM where
91+ liftIO act =
92+ lift' (try act) >>= either (otherError . IOExceptionThrown) return
93+ where
94+ lift' :: IO a -> PrepareM a
95+ lift' = PrepareM . lift . lift
96+
97+runPrepareM :: PrepareM a -> IO (Either PackageError (a, [PackageWarning]))
98+runPrepareM = runExceptT . runWriterT . unPrepareM
99+
100+warn :: PackageWarning -> PrepareM ()
101+warn w = tell [w]
102+
103+userError :: UserError -> PrepareM a
104+userError = throwError . UserError
105+
106+internalError :: InternalError -> PrepareM a
107+internalError = throwError . InternalError
108+
109+otherError :: OtherError -> PrepareM a
110+otherError = throwError . OtherError
111+
112+catchLeft :: Applicative f => Either a b -> (a -> f b) -> f b
113+catchLeft a f = either f pure a
114+
115+preparePackage' :: PublishOptions -> PrepareM D.UploadedPackage
116+preparePackage' opts = do
117+ exists <- liftIO (doesFileExist "bower.json")
118+ unless exists (userError BowerJSONNotFound)
119+
120+ requireCleanWorkingTree
121+
122+ pkgMeta <- liftIO (Bower.decodeFile "bower.json")
123+ >>= flip catchLeft (userError . CouldntParseBowerJSON)
124+ (pkgVersionTag, pkgVersion) <- publishGetVersion opts
125+ pkgGithub <- getBowerInfo pkgMeta
126+ (pkgBookmarks, pkgModules) <- getModulesAndBookmarks
127+
128+ let declaredDeps = map fst (bowerDependencies pkgMeta ++
129+ bowerDevDependencies pkgMeta)
130+ pkgResolvedDependencies <- getResolvedDependencies declaredDeps
131+
132+ let pkgUploader = D.NotYetKnown
133+ let pkgCompilerVersion = P.version
134+
135+ return D.Package{..}
136+
137+getModulesAndBookmarks :: PrepareM ([D.Bookmark], [D.Module])
138+getModulesAndBookmarks = do
139+ (inputFiles, depsFiles) <- liftIO getInputAndDepsFiles
140+ liftIO (D.parseAndDesugar inputFiles depsFiles renderModules)
141+ >>= either (userError . ParseAndDesugarError) return
142+ where
143+ renderModules bookmarks modules =
144+ return (bookmarks, map D.convertModule modules)
145+
146+data TreeStatus = Clean | Dirty deriving (Show, Eq, Ord, Enum)
147+
148+getGitWorkingTreeStatus :: PrepareM TreeStatus
149+getGitWorkingTreeStatus = do
150+ out <- readProcess' "git" ["status", "--porcelain"] ""
151+ return $
152+ if null . filter (not . null) . lines $ out
153+ then Clean
154+ else Dirty
155+
156+requireCleanWorkingTree :: PrepareM ()
157+requireCleanWorkingTree = do
158+ status <- getGitWorkingTreeStatus
159+ unless (status == Clean) $
160+ userError DirtyWorkingTree
161+
162+getVersionFromGitTag :: PrepareM (String, Version)
163+getVersionFromGitTag = do
164+ out <- readProcess' "git" ["tag", "--list", "--points-at", "HEAD"] ""
165+ let vs = map trimWhitespace (lines out)
166+ case mapMaybe parseMay vs of
167+ [] -> userError TagMustBeCheckedOut
168+ [x] -> return x
169+ xs -> userError (AmbiguousVersions (map snd xs))
170+ where
171+ trimWhitespace =
172+ dropWhile isSpace >>> reverse >>> dropWhile isSpace >>> reverse
173+ parseMay str =
174+ (str,) <$> D.parseVersion' (dropPrefix "v" str)
175+ dropPrefix prefix str =
176+ fromMaybe str (stripPrefix prefix str)
177+
178+getBowerInfo :: PackageMeta -> PrepareM (D.GithubUser, D.GithubRepo)
179+getBowerInfo = either (userError . BadRepositoryField) return . tryExtract
180+ where
181+ tryExtract pkgMeta =
182+ case bowerRepository pkgMeta of
183+ Nothing -> Left RepositoryFieldMissing
184+ Just Repository{..} -> do
185+ unless (repositoryType == "git")
186+ (Left (BadRepositoryType repositoryType))
187+ maybe (Left NotOnGithub) Right (extractGithub repositoryUrl)
188+
189+extractGithub :: String -> Maybe (D.GithubUser, D.GithubRepo)
190+extractGithub =
191+ stripPrefix "git://github.com/"
192+ >>> fmap (splitOn "/")
193+ >=> takeTwo
194+ >>> fmap (D.GithubUser *** (D.GithubRepo . dropDotGit))
195+
196+ where
197+ takeTwo :: [a] -> Maybe (a, a)
198+ takeTwo [x, y] = Just (x, y)
199+ takeTwo _ = Nothing
200+
201+ dropDotGit :: String -> String
202+ dropDotGit str
203+ | ".git" `isSuffixOf` str = take (length str - 4) str
204+ | otherwise = str
205+
206+readProcess' :: String -> [String] -> String -> PrepareM String
207+readProcess' prog args stdin = do
208+ out <- liftIO (catch (Right <$> readProcess prog args stdin)
209+ (return . Left))
210+ either (otherError . ProcessFailed prog args) return out
211+
212+data DependencyStatus
213+ = Missing
214+ -- ^ Listed in bower.json, but not installed.
215+ | NoResolution
216+ -- ^ In the output of `bower list --json --offline`, there was no
217+ -- _resolution key. This can be caused by adding the dependency using
218+ -- `bower link`, or simply copying it into bower_components instead of
219+ -- installing it normally.
220+ | ResolvedOther String
221+ -- ^ Resolved, but to something other than a version. The String argument
222+ -- is the resolution type. The values it can take that I'm aware of are
223+ -- "commit" and "branch".
224+ | ResolvedVersion String
225+ -- ^ Resolved to a version. The String argument is the resolution tag (eg,
226+ -- "v0.1.0").
227+ deriving (Show, Eq)
228+
229+-- Go through all bower dependencies which contain purescript code, and
230+-- extract their versions.
231+--
232+-- In the case where a bower dependency is taken from a particular version,
233+-- that's easy; take that version. In any other case (eg, a branch, or a commit
234+-- sha) we print a warning that documentation links will not work, and avoid
235+-- linking to documentation for any types from that package.
236+--
237+-- The rationale for this is: people will prefer to use a released version
238+-- where possible. If they are not using a released version, then this is
239+-- probably for a reason. However, docs are only ever available for released
240+-- versions. Therefore there will probably be no version of the docs which is
241+-- appropriate to link to, and we should omit links.
242+getResolvedDependencies :: [PackageName] -> PrepareM [(PackageName, Version)]
243+getResolvedDependencies declaredDeps = do
244+ bower <- findBowerExecutable
245+ depsBS <- fromString <$> readProcess' bower ["list", "--json", "--offline"] ""
246+
247+ -- Check for undeclared dependencies
248+ toplevels <- catchJSON (parse asToplevelDependencies depsBS)
249+ warnUndeclared declaredDeps toplevels
250+
251+ deps <- catchJSON (parse asResolvedDependencies depsBS)
252+ handleDeps deps
253+
254+ where
255+ catchJSON = flip catchLeft (internalError . JSONError FromBowerList)
256+
257+findBowerExecutable :: PrepareM String
258+findBowerExecutable = do
259+ mname <- liftIO . runMaybeT . msum . map (MaybeT . findExecutable) $ names
260+ maybe (userError (BowerExecutableNotFound names)) return mname
261+ where
262+ names = case System.Info.os of
263+ "mingw32" -> ["bower", "bower.cmd"]
264+ _ -> ["bower"]
265+
266+-- | Extracts all dependencies and their versions from
267+-- `bower list --json --offline`
268+asResolvedDependencies :: Parse BowerError [(PackageName, DependencyStatus)]
269+asResolvedDependencies = nubBy ((==) `on` fst) <$> go
270+ where
271+ go =
272+ fmap (fromMaybe []) $
273+ keyMay "dependencies" $
274+ (++) <$> eachInObjectWithKey (parsePackageName . T.unpack)
275+ asDependencyStatus
276+ <*> (concatMap snd <$> eachInObject asResolvedDependencies)
277+
278+-- | Extracts only the top level dependency names from the output of
279+-- `bower list --json --offline`
280+asToplevelDependencies :: Parse BowerError [PackageName]
281+asToplevelDependencies =
282+ fmap (map fst) $
283+ key "dependencies" $
284+ eachInObjectWithKey (parsePackageName . T.unpack) (return ())
285+
286+asDependencyStatus :: Parse e DependencyStatus
287+asDependencyStatus = do
288+ isMissing <- keyOrDefault "missing" False asBool
289+ if isMissing
290+ then
291+ return Missing
292+ else
293+ key "pkgMeta" $
294+ keyOrDefault "_resolution" NoResolution $ do
295+ type_ <- key "type" asString
296+ case type_ of
297+ "version" -> ResolvedVersion <$> key "tag" asString
298+ other -> return (ResolvedOther other)
299+
300+warnUndeclared :: [PackageName] -> [PackageName] -> PrepareM ()
301+warnUndeclared declared actual =
302+ mapM_ (warn . UndeclaredDependency) (actual \\ declared)
303+
304+handleDeps ::
305+ [(PackageName, DependencyStatus)] -> PrepareM [(PackageName, Version)]
306+handleDeps deps = do
307+ let (missing, noVersion, installed) = partitionDeps deps
308+ case missing of
309+ (x:xs) ->
310+ userError (MissingDependencies (x :| xs))
311+ [] -> do
312+ mapM_ (warn . NoResolvedVersion) noVersion
313+ withVersions <- catMaybes <$> mapM tryExtractVersion' installed
314+ filterM (liftIO . isPureScript . bowerDir . fst) withVersions
315+
316+ where
317+ partitionDeps = foldr go ([], [], [])
318+ go (pkgName, d) (ms, os, is) =
319+ case d of
320+ Missing -> (pkgName : ms, os, is)
321+ NoResolution -> (ms, pkgName : os, is)
322+ ResolvedOther _ -> (ms, pkgName : os, is)
323+ ResolvedVersion v -> (ms, os, (pkgName, v) : is)
324+
325+ bowerDir pkgName = "bower_components/" ++ runPackageName pkgName
326+
327+ -- Try to extract a version, and warn if unsuccessful.
328+ tryExtractVersion' pair =
329+ maybe (warn (UnacceptableVersion pair) >> return Nothing)
330+ (return . Just)
331+ (tryExtractVersion pair)
332+
333+tryExtractVersion :: (PackageName, String) -> Maybe (PackageName, Version)
334+tryExtractVersion (pkgName, tag) =
335+ let tag' = fromMaybe tag (stripPrefix "v" tag)
336+ in (pkgName,) <$> D.parseVersion' tag'
337+
338+-- | Returns whether it looks like there is a purescript package checked out
339+-- in the given directory.
340+isPureScript :: FilePath -> IO Bool
341+isPureScript dir = do
342+ files <- Glob.globDir1 purescriptSourceFiles dir
343+ return (not (null files))
344+
345+getInputAndDepsFiles :: IO ([FilePath], [(PackageName, FilePath)])
346+getInputAndDepsFiles = do
347+ inputFiles <- globRelative purescriptSourceFiles
348+ depsFiles' <- globRelative purescriptDepsFiles
349+ return (inputFiles, mapMaybe withPackageName depsFiles')
350+
351+withPackageName :: FilePath -> Maybe (PackageName, FilePath)
352+withPackageName fp = (,fp) <$> getPackageName fp
353+
354+getPackageName :: FilePath -> Maybe PackageName
355+getPackageName fp = do
356+ let xs = splitOn [pathSeparator] fp
357+ ys <- stripPrefix ["bower_components"] xs
358+ y <- headMay ys
359+ case Bower.mkPackageName y of
360+ Right name -> Just name
361+ Left _ -> Nothing
psc-publish/BoxesHelpers.hs → src/Language/PureScript/Publish/BoxesHelpers.hsrenamed+2−2
@@ -1,7 +1,7 @@
1−module BoxesHelpers
1+module Language.PureScript.Publish.BoxesHelpers
2 ( Boxes.Box
2 ( Boxes.Box
3 , Boxes.nullBox
3 , Boxes.nullBox
4− , module BoxesHelpers
4+ , module Language.PureScript.Publish.BoxesHelpers
5 ) where
5 ) where
6
6
7import System.IO (hPutStr, stderr)
7import System.IO (hPutStr, stderr)
psc-publish/ErrorsWarnings.hs → src/Language/PureScript/Publish/ErrorsWarnings.hsrenamed+100−33
@@ -1,11 +1,27 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE RecordWildCards #-}
2
3
3−module ErrorsWarnings where
4+module Language.PureScript.Publish.ErrorsWarnings
5+ ( PackageError(..)
6+ , PackageWarning(..)
7+ , UserError(..)
8+ , InternalError(..)
9+ , OtherError(..)
10+ , RepositoryFieldError(..)
11+ , JSONSource(..)
12+ , printError
13+ , renderError
14+ , printWarnings
15+ , renderWarnings
16+ ) where
4
17
18+import Control.Applicative ((<$>))
5import Data.Aeson.BetterErrors
19import Data.Aeson.BetterErrors
6import Data.Version
20import Data.Version
7import Data.Maybe
21import Data.Maybe
8−import Data.List (intersperse)
22+import Data.Monoid
23+import Data.Foldable (foldMap)
24+import Data.List (intersperse, intercalate)
9import Data.List.NonEmpty (NonEmpty(..))
25import Data.List.NonEmpty (NonEmpty(..))
10import qualified Data.List.NonEmpty as NonEmpty
26import qualified Data.List.NonEmpty as NonEmpty
11
27
@@ -18,7 +34,7 @@ import qualified Web.Bower.PackageMeta as Bower
18import qualified Language.PureScript as P
34import qualified Language.PureScript as P
19import qualified Language.PureScript.Docs as D
35import qualified Language.PureScript.Docs as D
20
36
21−import BoxesHelpers
37+import Language.PureScript.Publish.BoxesHelpers
22
38
23-- | An error which meant that it was not possible to retrieve metadata for a
39-- | An error which meant that it was not possible to retrieve metadata for a
24-- package.
40-- package.
@@ -29,13 +45,15 @@ data PackageError
29 deriving (Show)
45 deriving (Show)
30
46
31data PackageWarning
47data PackageWarning
32− = ResolutionNotVersion PackageName
48+ = NoResolvedVersion PackageName
33 | UndeclaredDependency PackageName
49 | UndeclaredDependency PackageName
50+ | UnacceptableVersion (PackageName, String)
34 deriving (Show)
51 deriving (Show)
35
52
36-- | An error that should be fixed by the user.
53-- | An error that should be fixed by the user.
37data UserError
54data UserError
38 = BowerJSONNotFound
55 = BowerJSONNotFound
56+ | BowerExecutableNotFound [String] -- list of executable names tried
39 | CouldntParseBowerJSON (ParseError BowerError)
57 | CouldntParseBowerJSON (ParseError BowerError)
40 | BowerJSONNameMissing
58 | BowerJSONNameMissing
41 | TagMustBeCheckedOut
59 | TagMustBeCheckedOut
@@ -43,6 +61,7 @@ data UserError
43 | BadRepositoryField RepositoryFieldError
61 | BadRepositoryField RepositoryFieldError
44 | MissingDependencies (NonEmpty PackageName)
62 | MissingDependencies (NonEmpty PackageName)
45 | ParseAndDesugarError D.ParseDesugarError
63 | ParseAndDesugarError D.ParseDesugarError
64+ | DirtyWorkingTree
46 deriving (Show)
65 deriving (Show)
47
66
48data RepositoryFieldError
67data RepositoryFieldError
@@ -103,6 +122,13 @@ displayUserError e = case e of
103 [ "The bower.json file was not found. Please create one, or run "
122 [ "The bower.json file was not found. Please create one, or run "
104 , "`pulp init`."
123 , "`pulp init`."
105 ])
124 ])
125+ BowerExecutableNotFound names ->
126+ para (concat
127+ [ "The Bower executable was not found (tried: ", format names, "). Please"
128+ , " ensure that bower is installed and on your PATH."
129+ ])
130+ where
131+ format = intercalate ", " . map show
106 CouldntParseBowerJSON err ->
132 CouldntParseBowerJSON err ->
107 vcat
133 vcat
108 [ successivelyIndented
134 [ successivelyIndented
@@ -172,13 +198,18 @@ displayUserError e = case e of
172 ParseAndDesugarError (D.SortModulesError err) ->
198 ParseAndDesugarError (D.SortModulesError err) ->
173 vcat
199 vcat
174 [ para "Error in sortModules:"
200 [ para "Error in sortModules:"
175− , indented (para (P.prettyPrintMultipleErrors False err))
201+ , indented (P.prettyPrintMultipleErrorsBox False err)
176 ]
202 ]
177 ParseAndDesugarError (D.DesugarError err) ->
203 ParseAndDesugarError (D.DesugarError err) ->
178 vcat
204 vcat
179 [ para "Error while desugaring:"
205 [ para "Error while desugaring:"
180− , indented (para (P.prettyPrintMultipleErrors False err))
206+ , indented (P.prettyPrintMultipleErrorsBox False err)
181 ]
207 ]
208+ DirtyWorkingTree ->
209+ para (concat
210+ [ "Your git working tree is dirty. Please commit, discard, or stash "
211+ , "your changes first."
212+ ])
182
213
183displayRepositoryError :: RepositoryFieldError -> Box
214displayRepositoryError :: RepositoryFieldError -> Box
184displayRepositoryError err = case err of
215displayRepositoryError err = case err of
@@ -247,45 +278,52 @@ displayOtherError e = case e of
247 successivelyIndented
278 successivelyIndented
248 [ "An IO exception occurred:", show exc ]
279 [ "An IO exception occurred:", show exc ]
249
280
250−renderWarnings :: [PackageWarning] -> Box
281+data CollectedWarnings = CollectedWarnings
251−renderWarnings =
282+ { noResolvedVersions :: [PackageName]
252− collectWarnings
283+ , undeclaredDependencies :: [PackageName]
253− [ (getResolutionNotVersion, warnResolutionNotVersions)
284+ , unacceptableVersions :: [(PackageName, String)]
254− , (getUndeclaredDependency, warnUndeclaredDependencies)
285+ }
255− ]
286+ deriving (Show, Eq, Ord)
256− where
257− collectWarnings patterns warns =
258− let boxes = mapMaybe (collectWarnings' warns) patterns
259− result = vcat
260− [ para "Warnings:"
261− , indented (vcat (intersperse spacer boxes))
262− ]
263− in if null boxes then nullBox else result
264
287
265− getResolutionNotVersion (ResolutionNotVersion n) = Just n
288+instance Monoid CollectedWarnings where
266− getResolutionNotVersion _ = Nothing
289+ mempty = CollectedWarnings mempty mempty mempty
290+ mappend (CollectedWarnings as bs cs) (CollectedWarnings as' bs' cs') =
291+ CollectedWarnings (as <> as') (bs <> bs') (cs <> cs')
267
292
268− getUndeclaredDependency (UndeclaredDependency n) = Just n
293+collectWarnings :: [PackageWarning] -> CollectedWarnings
269− getUndeclaredDependency _ = Nothing
294+collectWarnings = foldMap singular
295+ where
296+ singular w = case w of
297+ NoResolvedVersion pn -> CollectedWarnings [pn] [] []
298+ UndeclaredDependency pn -> CollectedWarnings [] [pn] []
299+ UnacceptableVersion t -> CollectedWarnings [] [] [t]
270
300
271−collectWarnings' :: [PackageWarning] -> ((PackageWarning -> Maybe a), (NonEmpty a -> Box)) -> Maybe Box
301+renderWarnings :: [PackageWarning] -> Box
272−collectWarnings' warns (pattern, render) =
302+renderWarnings warns =
273− case mapMaybe pattern warns of
303+ let CollectedWarnings{..} = collectWarnings warns
274− [] -> Nothing
304+ go toBox warns' = toBox <$> NonEmpty.nonEmpty warns'
275− (x:xs) -> Just (render (x :| xs))
305+ mboxes = [ go warnNoResolvedVersions noResolvedVersions
306+ , go warnUndeclaredDependencies undeclaredDependencies
307+ , go warnUnacceptableVersions unacceptableVersions
308+ ]
309+ in case catMaybes mboxes of
310+ [] -> nullBox
311+ boxes -> vcat [ para "Warnings:"
312+ , indented (vcat (intersperse spacer boxes))
313+ ]
276
314
277−warnResolutionNotVersions :: NonEmpty PackageName -> Box
315+warnNoResolvedVersions :: NonEmpty PackageName -> Box
278−warnResolutionNotVersions pkgNames =
316+warnNoResolvedVersions pkgNames =
279 let singular = NonEmpty.length pkgNames == 1
317 let singular = NonEmpty.length pkgNames == 1
280 pl a b = if singular then b else a
318 pl a b = if singular then b else a
281
319
282 packages = pl "packages" "package"
320 packages = pl "packages" "package"
283− were = pl "were" "was"
284 anyOfThese = pl "any of these" "this"
321 anyOfThese = pl "any of these" "this"
285 these = pl "these" "this"
322 these = pl "these" "this"
286 in vcat $
323 in vcat $
287 [ para (concat
324 [ para (concat
288− ["The following ", packages, " ", were, " not resolved to a version:"])
325+ ["The following ", packages, " did not appear to have a resolved "
326+ , "version:"])
289 ] ++
327 ] ++
290 bulletedList runPackageName (NonEmpty.toList pkgNames)
328 bulletedList runPackageName (NonEmpty.toList pkgNames)
291 ++
329 ++
@@ -314,5 +352,34 @@ warnUndeclaredDependencies pkgNames =
314 ] ++
352 ] ++
315 bulletedList runPackageName (NonEmpty.toList pkgNames)
353 bulletedList runPackageName (NonEmpty.toList pkgNames)
316
354
355+warnUnacceptableVersions :: NonEmpty (PackageName, String) -> Box
356+warnUnacceptableVersions pkgs =
357+ let singular = NonEmpty.length pkgs == 1
358+ pl a b = if singular then b else a
359+
360+ packages' = pl "packages'" "package's"
361+ packages = pl "packages" "package"
362+ anyOfThese = pl "any of these" "this"
363+ these = pl "these" "this"
364+ versions = pl "versions" "version"
365+ in vcat $
366+ [ para (concat
367+ [ "The following installed Bower ", packages', " ", versions, " could "
368+ , "not be parsed:"
369+ ])
370+ ] ++
371+ bulletedList showTuple (NonEmpty.toList pkgs)
372+ ++
373+ [ spacer
374+ , para (concat
375+ ["Links to types in ", anyOfThese, " ", packages, " will not work. In "
376+ , "order to make links work, edit your bower.json to specify an "
377+ , "acceptable version or version range for ", these, " ", packages, ", "
378+ , "and rerun `bower install`."
379+ ])
380+ ]
381+ where
382+ showTuple (pkgName, tag) = runPackageName pkgName ++ "#" ++ tag
383+
317printWarnings :: [PackageWarning] -> IO ()
384printWarnings :: [PackageWarning] -> IO ()
318printWarnings = printToStderr . renderWarnings
385printWarnings = printToStderr . renderWarnings
src/Language/PureScript/Publish/Utils.hsnew file+38
@@ -0,0 +1,38 @@
1+
2+module Language.PureScript.Publish.Utils where
3+
4+import Data.List
5+import Data.Either (partitionEithers)
6+import System.Directory
7+import System.Exit (exitFailure)
8+import System.IO (hPutStrLn, stderr)
9+import System.FilePath (pathSeparator)
10+import qualified System.FilePath.Glob as Glob
11+
12+-- | Glob relative to the current directory, and produce relative pathnames.
13+globRelative :: Glob.Pattern -> IO [FilePath]
14+globRelative pat = do
15+ currentDir <- getCurrentDirectory
16+ filesAbsolute <- Glob.globDir1 pat currentDir
17+ let prefix = currentDir ++ [pathSeparator]
18+ let (fails, paths) = partitionEithers . map (stripPrefix' prefix) $ filesAbsolute
19+ if null fails
20+ then return paths
21+ else do
22+ let p = hPutStrLn stderr
23+ p "Internal error in Language.PureScript.Publish.Utils.globRelative"
24+ p "Unmatched files:"
25+ mapM_ p fails
26+ exitFailure
27+
28+ where
29+ stripPrefix' prefix dir =
30+ maybe (Left dir) Right $ stripPrefix prefix dir
31+
32+-- | Glob pattern for PureScript source files.
33+purescriptSourceFiles :: Glob.Pattern
34+purescriptSourceFiles = Glob.compile "src/**/*.purs"
35+
36+-- | Glob pattern for PureScript dependency files.
37+purescriptDepsFiles :: Glob.Pattern
38+purescriptDepsFiles = Glob.compile "bower_components/*/src/**/*.purs"
src/Language/PureScript/Sugar/DoNotation.hs+3−3
@@ -10,7 +10,7 @@
10--
10--
11-- |
11-- |
12-- This module implements the desugaring pass which replaces do-notation statements with
12-- This module implements the desugaring pass which replaces do-notation statements with
13−-- appropriate calls to (>>=) from the Prelude.Monad type class.
13+-- appropriate calls to bind from the Prelude.Monad type class.
14--
14--
15-----------------------------------------------------------------------------
15-----------------------------------------------------------------------------
16
16
@@ -32,7 +32,7 @@ import Control.Monad.Error.Class (MonadError(..))
32import Control.Monad.Supply.Class
32import Control.Monad.Supply.Class
33
33
34-- |
34-- |
35−-- Replace all @DoNotationBind@ and @DoNotationValue@ constructors with applications of the Prelude.(>>=) function,
35+-- Replace all @DoNotationBind@ and @DoNotationValue@ constructors with applications of the Prelude.bind function,
36-- and all @DoNotationLet@ constructors with let expressions.
36-- and all @DoNotationLet@ constructors with let expressions.
37--
37--
38desugarDoModule :: forall m. (Applicative m, MonadSupply m, MonadError MultipleErrors m) => Module -> m Module
38desugarDoModule :: forall m. (Applicative m, MonadSupply m, MonadError MultipleErrors m) => Module -> m Module
@@ -45,7 +45,7 @@ desugarDo d =
45 in f d
45 in f d
46 where
46 where
47 bind :: Expr
47 bind :: Expr
48− bind = Var (Qualified Nothing (Op (C.>>=)))
48+ bind = Var (Qualified Nothing (Ident (C.bind)))
49
49
50 replace :: Expr -> m Expr
50 replace :: Expr -> m Expr
51 replace (Do els) = go els
51 replace (Do els) = go els
src/Language/PureScript/Sugar/Names.hs+74−7
@@ -14,13 +14,14 @@
14
14
15{-# LANGUAGE FlexibleContexts #-}
15{-# LANGUAGE FlexibleContexts #-}
16{-# LANGUAGE ScopedTypeVariables #-}
16{-# LANGUAGE ScopedTypeVariables #-}
17+{-# LANGUAGE PatternGuards #-}
17
18
18module Language.PureScript.Sugar.Names (
19module Language.PureScript.Sugar.Names (
19 desugarImports
20 desugarImports
20) where
21) where
21
22
22−import Data.List (nub)
23+import Data.List (find, nub, (\\))
23−import Data.Maybe (fromMaybe, isJust, mapMaybe)
24+import Data.Maybe (catMaybes, fromMaybe, isJust, mapMaybe)
24
25
25import Control.Applicative (Applicative(..), (<$>), (<*>))
26import Control.Applicative (Applicative(..), (<$>), (<*>))
26import Control.Monad
27import Control.Monad
@@ -59,6 +60,10 @@ data Exports = Exports
59 -- The values exported from each module
60 -- The values exported from each module
60 --
61 --
61 , exportedValues :: [Ident]
62 , exportedValues :: [Ident]
63+ -- |
64+ -- The modules exported from each module
65+ --
66+ , exportedModules :: [ModuleName]
62 } deriving (Show)
67 } deriving (Show)
63
68
64-- |
69-- |
@@ -101,7 +106,7 @@ addEmptyModule :: (Applicative m, MonadError MultipleErrors m) => ExportEnvironm
101addEmptyModule env name =
106addEmptyModule env name =
102 if name `M.member` env
107 if name `M.member` env
103 then throwError . errorMessage $ RedefinedModule name
108 then throwError . errorMessage $ RedefinedModule name
104− else return $ M.insert name (Exports [] [] []) env
109+ else return $ M.insert name (Exports [] [] [] []) env
105
110
106-- |
111-- |
107-- Adds a type belonging to a module to the export environment.
112-- Adds a type belonging to a module to the export environment.
@@ -155,13 +160,65 @@ desugarImports :: forall m. (Applicative m, MonadError MultipleErrors m) => [Mod
155desugarImports modules = do
160desugarImports modules = do
156 unfilteredExports <- findExports modules
161 unfilteredExports <- findExports modules
157 exports <- foldM filterModuleExports unfilteredExports modules
162 exports <- foldM filterModuleExports unfilteredExports modules
158− mapM (renameInModule' unfilteredExports exports) modules
163+ let modules' = moduleReexports <$> modules
164+ mapM (renameInModule' unfilteredExports exports) modules'
159 where
165 where
166+ moduleReexports :: Module -> Module
167+ moduleReexports (Module coms mn decls exps) =
168+ let importedMods = catMaybes findImports'
169+ in (Module coms mn (decls ++ (concatMap reexports importedMods)) exps)
170+ where
171+ imports :: [Declaration]
172+ imports = filter isImportDecl decls
173+ findImports' :: [Maybe (Declaration, Module)]
174+ findImports' = go <$> modules
175+ where
176+ go :: Module -> Maybe (Declaration, Module)
177+ go m@(Module _ mn' _ (Just exps'))
178+ | any isModExport exps', Just d <- find ((== mn') . importedModName) imports = Just (d, m)
179+ where
180+ importedModName :: Declaration -> ModuleName
181+ importedModName (ImportDeclaration imn _ _) = imn
182+ importedModName (PositionedDeclaration _ _ d) = importedModName d
183+ importedModName _ = error "Not an import decl"
184+ go _ = Nothing
185+ reexports :: (Declaration, Module) -> [Declaration]
186+ reexports (ImportDeclaration _ (Hiding refs) _, (Module coms' mn' ds' (Just exps'))) =
187+ case nonHiddenRefs of
188+ [] -> []
189+ _ -> reexports (ImportDeclaration mn' Implicit Nothing, Module coms' mn' ds' (Just nonHiddenRefs))
190+ where
191+ nonHiddenRefs :: [DeclarationRef]
192+ nonHiddenRefs = filter isModExport exps' \\ filter isModExport refs
193+ reexports (ImportDeclaration _ ty qual, Module _ _ _ (Just exps')) =
194+ let ty' = case ty of
195+ Explicit _ -> Explicit []
196+ _ -> ty
197+ in (\m -> ImportDeclaration m ty' qual) <$> (catMaybes $ go <$> exps')
198+ where
199+ go :: DeclarationRef -> Maybe ModuleName
200+ go (ModuleRef mn') = Just mn'
201+ go _ = Nothing
202+ reexports (PositionedDeclaration _ _ d, m@(Module _ _ _ (Just _))) = reexports (d, m)
203+ reexports _ = []
204+
205+ isModExport :: DeclarationRef -> Bool
206+ isModExport (ModuleRef _) = True
207+ isModExport _ = False
160
208
161 -- Filters the exports for a module in the global exports environment so that only explicitly
209 -- Filters the exports for a module in the global exports environment so that only explicitly
162 -- exported members remain. If the module does not explicitly export anything, everything is
210 -- exported members remain. If the module does not explicitly export anything, everything is
163 -- exported.
211 -- exported.
164 filterModuleExports :: ExportEnvironment -> Module -> m ExportEnvironment
212 filterModuleExports :: ExportEnvironment -> Module -> m ExportEnvironment
213+ filterModuleExports env (Module _ mn _ (Just exps))
214+ | any isSelfModuleExport exps, Just exps' <- M.lookup mn env =
215+ let moduleNames = filter (/= mn) $ (\(ModuleRef mn') -> mn') <$> filter isModExport exps
216+ in return $ M.insert mn (exps' {exportedModules = moduleNames}) env
217+ where
218+ isSelfModuleExport :: DeclarationRef -> Bool
219+ isSelfModuleExport (ModuleRef mn') | mn' == mn = True
220+ isSelfModuleExport (PositionedDeclarationRef _ _ ref) = isSelfModuleExport ref
221+ isSelfModuleExport _ = False
165 filterModuleExports env (Module _ mn _ (Just exps)) = filterExports mn exps env
222 filterModuleExports env (Module _ mn _ (Just exps)) = filterExports mn exps env
166 filterModuleExports env _ = return env
223 filterModuleExports env _ = return env
167
224
@@ -183,7 +240,8 @@ elaborateExports :: Exports -> Module -> Module
183elaborateExports exps (Module coms mn decls _) = Module coms mn decls (Just $
240elaborateExports exps (Module coms mn decls _) = Module coms mn decls (Just $
184 map (\(ctor, dctors) -> TypeRef ctor (Just dctors)) (exportedTypes exps) ++
241 map (\(ctor, dctors) -> TypeRef ctor (Just dctors)) (exportedTypes exps) ++
185 map TypeClassRef (exportedTypeClasses exps) ++
242 map TypeClassRef (exportedTypeClasses exps) ++
186− map ValueRef (exportedValues exps))
243+ map ValueRef (exportedValues exps) ++
244+ map ModuleRef (exportedModules exps))
187
245
188-- |
246-- |
189-- Add `import X ()` for any modules where there are only fully qualified references to members.
247-- Add `import X ()` for any modules where there are only fully qualified references to members.
@@ -314,7 +372,7 @@ findExports = foldM addModule $ M.singleton (ModuleName [ProperName C.prim]) pri
314 where
372 where
315
373
316 -- The exported types from the Prim module
374 -- The exported types from the Prim module
317− primExports = Exports (mkTypeEntry `map` M.keys primTypes) [] []
375+ primExports = Exports (mkTypeEntry `map` M.keys primTypes) [] [] []
318 where
376 where
319 mkTypeEntry (Qualified _ name) = (name, [])
377 mkTypeEntry (Qualified _ name) = (name, [])
320
378
@@ -358,7 +416,8 @@ filterExports mn exps env = do
358 types' <- foldM (filterTypes $ exportedTypes exported) [] exps
416 types' <- foldM (filterTypes $ exportedTypes exported) [] exps
359 values <- foldM (filterValues $ exportedValues exported) [] exps
417 values <- foldM (filterValues $ exportedValues exported) [] exps
360 classes <- foldM (filterClasses $ exportedTypeClasses exported) [] exps
418 classes <- foldM (filterClasses $ exportedTypeClasses exported) [] exps
361− return exported { exportedTypes = types', exportedTypeClasses = classes, exportedValues = values }
419+ modules <- foldM (filterModules $ exportedModules exported) [] exps
420+ return exported { exportedTypes = types', exportedTypeClasses = classes, exportedValues = values, exportedModules = modules }
362
421
363 -- Ensure the exported types and data constructors exist in the module and add them to the set of
422 -- Ensure the exported types and data constructors exist in the module and add them to the set of
364 -- exports
423 -- exports
@@ -395,6 +454,12 @@ filterExports mn exps env = do
395 else throwError . errorMessage . UnknownValue $ Qualified (Just mn) name
454 else throwError . errorMessage . UnknownValue $ Qualified (Just mn) name
396 filterValues _ result _ = return result
455 filterValues _ result _ = return result
397
456
457+ -- Add the exported modules to the set of exports
458+ filterModules :: [ModuleName] -> [ModuleName] -> DeclarationRef -> m [ModuleName]
459+ filterModules exps' result (PositionedDeclarationRef pos _ r) = rethrowWithPosition pos $ filterModules exps' result r
460+ filterModules _ result (ModuleRef name) = return $ name : result
461+ filterModules _ result _ = return result
462+
398-- |
463-- |
399-- Finds the imports within a module, mapping the imported module name to an optional set of
464-- Finds the imports within a module, mapping the imported module name to an optional set of
400-- explicitly imported declarations.
465-- explicitly imported declarations.
@@ -501,6 +566,8 @@ resolveImport currentModule importModule exps imps impQual =
501 return ref
566 return ref
502 check ref@(TypeClassRef name) =
567 check ref@(TypeClassRef name) =
503 checkImportExists UnknownTypeClass classes name >> return ref
568 checkImportExists UnknownTypeClass classes name >> return ref
569+ check ref@(ModuleRef name) =
570+ checkImportExists (UnknownModule . (\(Qualified _ m) -> m)) (exportedModules exps) name >> return ref
504 check _ = error "Invalid argument to checkRefIsValid"
571 check _ = error "Invalid argument to checkRefIsValid"
505
572
506 -- Find all exported data constructors for a given type
573 -- Find all exported data constructors for a given type
src/Language/PureScript/Sugar/TypeClasses.hs+1−1
@@ -300,7 +300,7 @@ typeInstanceDictionaryDeclaration name mn deps className tys decls1 =
300
300
301 memberToValue :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [(Ident, Type)] -> Declaration -> Desugar m Expr
301 memberToValue :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [(Ident, Type)] -> Declaration -> Desugar m Expr
302 memberToValue tys' (ValueDeclaration ident _ [] (Right val)) = do
302 memberToValue tys' (ValueDeclaration ident _ [] (Right val)) = do
303− _ <- maybe (throwError . errorMessage $ MissingClassMember ident) return $ lookup ident tys'
303+ _ <- maybe (throwError . errorMessage $ ExtraneousClassMember ident) return $ lookup ident tys'
304 return val
304 return val
305 memberToValue tys' (PositionedDeclaration pos com d) = rethrowWithPosition pos $ do
305 memberToValue tys' (PositionedDeclaration pos com d) = rethrowWithPosition pos $ do
306 val <- memberToValue tys' d
306 val <- memberToValue tys' d
src/Language/PureScript/TypeChecker.hs+49−62
@@ -31,6 +31,7 @@ import Data.Foldable (for_)
31
31
32import qualified Data.Map as M
32import qualified Data.Map as M
33
33
34+import Control.Applicative ((<$>), (<*))
34import Control.Monad.State
35import Control.Monad.State
35import Control.Monad.Error.Class (MonadError(..))
36import Control.Monad.Error.Class (MonadError(..))
36
37
@@ -88,10 +89,10 @@ addTypeClass moduleName pn args implies ds =
88 toPair (PositionedDeclaration _ _ d) = toPair d
89 toPair (PositionedDeclaration _ _ d) = toPair d
89 toPair _ = error "Invalid declaration in TypeClassDeclaration"
90 toPair _ = error "Invalid declaration in TypeClassDeclaration"
90
91
91−addTypeClassDictionaries :: [TypeClassDictionaryInScope] -> Check ()
92+addTypeClassDictionaries :: Maybe ModuleName -> M.Map (Qualified ProperName) (M.Map (Qualified Ident) TypeClassDictionaryInScope) -> Check ()
92−addTypeClassDictionaries entries =
93+addTypeClassDictionaries mn entries =
93− let mentries = M.fromList [ ((canonicalizeDictionary entry, mn), entry) | entry@TypeClassDictionaryInScope{ tcdName = Qualified mn _ } <- entries ]
94+ modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = insertState st } }
94− in modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = (typeClassDictionaries . checkEnv $ st) `M.union` mentries } }
95+ where insertState st = M.insertWith (M.unionWith M.union) mn entries (typeClassDictionaries . checkEnv $ st)
95
96
96checkDuplicateTypeArguments :: [String] -> Check ()
97checkDuplicateTypeArguments :: [String] -> Check ()
97checkDuplicateTypeArguments args = for_ firstDup $ \dup ->
98checkDuplicateTypeArguments args = for_ firstDup $ \dup ->
@@ -129,25 +130,23 @@ checkTypeSynonyms = void . replaceAllTypeSynonyms
129-- * Process module imports
130-- * Process module imports
130--
131--
131typeCheckAll :: Maybe ModuleName -> ModuleName -> [DeclarationRef] -> [Declaration] -> Check [Declaration]
132typeCheckAll :: Maybe ModuleName -> ModuleName -> [DeclarationRef] -> [Declaration] -> Check [Declaration]
132−typeCheckAll mainModuleName moduleName exps = go
133+typeCheckAll mainModuleName moduleName exps ds = mapM go ds <* mapM_ checkOrphanFixities ds
133 where
134 where
134− go :: [Declaration] -> Check [Declaration]
135+ go :: Declaration -> Check Declaration
135− go [] = return []
136+ go (DataDeclaration dtype name args dctors) = do
136− go (DataDeclaration dtype name args dctors : rest) = do
137 rethrow (onErrorMessages (ErrorInTypeConstructor name)) $ do
137 rethrow (onErrorMessages (ErrorInTypeConstructor name)) $ do
138 when (dtype == Newtype) $ checkNewtype dctors
138 when (dtype == Newtype) $ checkNewtype dctors
139 checkDuplicateTypeArguments $ map fst args
139 checkDuplicateTypeArguments $ map fst args
140 ctorKind <- kindsOf True moduleName name args (concatMap snd dctors)
140 ctorKind <- kindsOf True moduleName name args (concatMap snd dctors)
141 let args' = args `withKinds` ctorKind
141 let args' = args `withKinds` ctorKind
142 addDataType moduleName dtype name args' dctors ctorKind
142 addDataType moduleName dtype name args' dctors ctorKind
143− ds <- go rest
143+ return $ DataDeclaration dtype name args dctors
144− return $ DataDeclaration dtype name args dctors : ds
145 where
144 where
146 checkNewtype :: [(ProperName, [Type])] -> Check ()
145 checkNewtype :: [(ProperName, [Type])] -> Check ()
147 checkNewtype [(_, [_])] = return ()
146 checkNewtype [(_, [_])] = return ()
148 checkNewtype [(_, _)] = throwError . errorMessage $ InvalidNewtype
147 checkNewtype [(_, _)] = throwError . errorMessage $ InvalidNewtype
149 checkNewtype _ = throwError . errorMessage $ InvalidNewtype
148 checkNewtype _ = throwError . errorMessage $ InvalidNewtype
150− go (d@(DataBindingGroupDeclaration tys) : rest) = do
149+ go (d@(DataBindingGroupDeclaration tys)) = do
151 rethrow (onErrorMessages ErrorInDataBindingGroup) $ do
150 rethrow (onErrorMessages ErrorInDataBindingGroup) $ do
152 let syns = mapMaybe toTypeSynonym tys
151 let syns = mapMaybe toTypeSynonym tys
153 let dataDecls = mapMaybe toDataDecl tys
152 let dataDecls = mapMaybe toDataDecl tys
@@ -160,8 +159,7 @@ typeCheckAll mainModuleName moduleName exps = go
160 checkDuplicateTypeArguments $ map fst args
159 checkDuplicateTypeArguments $ map fst args
161 let args' = args `withKinds` kind
160 let args' = args `withKinds` kind
162 addTypeSynonym moduleName name args' ty kind
161 addTypeSynonym moduleName name args' ty kind
163− ds <- go rest
162+ return d
164− return $ d : ds
165 where
163 where
166 toTypeSynonym (TypeSynonymDeclaration nm args ty) = Just (nm, args, ty)
164 toTypeSynonym (TypeSynonymDeclaration nm args ty) = Just (nm, args, ty)
167 toTypeSynonym (PositionedDeclaration _ _ d') = toTypeSynonym d'
165 toTypeSynonym (PositionedDeclaration _ _ d') = toTypeSynonym d'
@@ -169,26 +167,23 @@ typeCheckAll mainModuleName moduleName exps = go
169 toDataDecl (DataDeclaration dtype nm args dctors) = Just (dtype, nm, args, dctors)
167 toDataDecl (DataDeclaration dtype nm args dctors) = Just (dtype, nm, args, dctors)
170 toDataDecl (PositionedDeclaration _ _ d') = toDataDecl d'
168 toDataDecl (PositionedDeclaration _ _ d') = toDataDecl d'
171 toDataDecl _ = Nothing
169 toDataDecl _ = Nothing
172− go (TypeSynonymDeclaration name args ty : rest) = do
170+ go (TypeSynonymDeclaration name args ty) = do
173 rethrow (onErrorMessages (ErrorInTypeSynonym name)) $ do
171 rethrow (onErrorMessages (ErrorInTypeSynonym name)) $ do
174 checkDuplicateTypeArguments $ map fst args
172 checkDuplicateTypeArguments $ map fst args
175 kind <- kindsOf False moduleName name args [ty]
173 kind <- kindsOf False moduleName name args [ty]
176 let args' = args `withKinds` kind
174 let args' = args `withKinds` kind
177 addTypeSynonym moduleName name args' ty kind
175 addTypeSynonym moduleName name args' ty kind
178− ds <- go rest
176+ return $ TypeSynonymDeclaration name args ty
179− return $ TypeSynonymDeclaration name args ty : ds
177+ go (TypeDeclaration{}) = error "Type declarations should have been removed"
180− go (TypeDeclaration _ _ : _) = error "Type declarations should have been removed"
178+ go (ValueDeclaration name nameKind [] (Right val)) =
181− go (ValueDeclaration name nameKind [] (Right val) : rest) = do
179+ rethrow (onErrorMessages (ErrorInValueDeclaration name)) $ do
182− d <- rethrow (onErrorMessages (ErrorInValueDeclaration name)) $ do
183 valueIsNotDefined moduleName name
180 valueIsNotDefined moduleName name
184 [(_, (val', ty))] <- typesOf mainModuleName moduleName [(name, val)]
181 [(_, (val', ty))] <- typesOf mainModuleName moduleName [(name, val)]
185 addValue moduleName name ty nameKind
182 addValue moduleName name ty nameKind
186 return $ ValueDeclaration name nameKind [] $ Right val'
183 return $ ValueDeclaration name nameKind [] $ Right val'
187− ds <- go rest
184+ go (ValueDeclaration{}) = error "Binders were not desugared"
188− return $ d : ds
185+ go (BindingGroupDeclaration vals) =
189− go (ValueDeclaration{} : _) = error "Binders were not desugared"
186+ rethrow (onErrorMessages (ErrorInBindingGroup (map (\(ident, _, _) -> ident) vals))) $ do
190− go (BindingGroupDeclaration vals : rest) = do
191− d <- rethrow (onErrorMessages (ErrorInBindingGroup (map (\(ident, _, _) -> ident) vals))) $ do
192 forM_ (map (\(ident, _, _) -> ident) vals) $ \name ->
187 forM_ (map (\(ident, _, _) -> ident) vals) $ \name ->
193 valueIsNotDefined moduleName name
188 valueIsNotDefined moduleName name
194 tys <- typesOf mainModuleName moduleName $ map (\(ident, _, ty) -> (ident, ty)) vals
189 tys <- typesOf mainModuleName moduleName $ map (\(ident, _, ty) -> (ident, ty)) vals
@@ -200,14 +195,11 @@ typeCheckAll mainModuleName moduleName exps = go
200 addValue moduleName name ty nameKind
195 addValue moduleName name ty nameKind
201 return (name, nameKind, val)
196 return (name, nameKind, val)
202 return $ BindingGroupDeclaration vals'
197 return $ BindingGroupDeclaration vals'
203− ds <- go rest
198+ go (d@(ExternDataDeclaration name kind)) = do
204− return $ d : ds
205− go (d@(ExternDataDeclaration name kind) : rest) = do
206 env <- getEnv
199 env <- getEnv
207 putEnv $ env { types = M.insert (Qualified (Just moduleName) name) (kind, ExternData) (types env) }
200 putEnv $ env { types = M.insert (Qualified (Just moduleName) name) (kind, ExternData) (types env) }
208− ds <- go rest
201+ return d
209− return $ d : ds
202+ go (d@(ExternDeclaration name ty)) = do
210− go (d@(ExternDeclaration name ty) : rest) = do
211 rethrow (onErrorMessages (ErrorInForeignImport name)) $ do
203 rethrow (onErrorMessages (ErrorInForeignImport name)) $ do
212 env <- getEnv
204 env <- getEnv
213 kind <- kindOf moduleName ty
205 kind <- kindOf moduleName ty
@@ -215,42 +207,37 @@ typeCheckAll mainModuleName moduleName exps = go
215 case M.lookup (moduleName, name) (names env) of
207 case M.lookup (moduleName, name) (names env) of
216 Just _ -> throwError . errorMessage $ RedefinedIdent name
208 Just _ -> throwError . errorMessage $ RedefinedIdent name
217 Nothing -> putEnv (env { names = M.insert (moduleName, name) (ty, External, Defined) (names env) })
209 Nothing -> putEnv (env { names = M.insert (moduleName, name) (ty, External, Defined) (names env) })
218− ds <- go rest
210+ return d
219− return $ d : ds
211+ go (d@(FixityDeclaration{})) = return d
220− go (d@(FixityDeclaration _ name) : rest) = do
212+ go (d@(ImportDeclaration importedModule _ _)) = do
221− ds <- go rest
213+ instances <- lookupTypeClassDictionaries $ Just importedModule
214+ addTypeClassDictionaries (Just moduleName) instances
215+ return d
216+ go (d@(TypeClassDeclaration pn args implies tys)) = do
217+ addTypeClass moduleName pn args implies tys
218+ return d
219+ go (d@(TypeInstanceDeclaration dictName deps className tys _)) =
220+ goInstance d dictName deps className tys
221+ go (d@(ExternInstanceDeclaration dictName deps className tys)) =
222+ goInstance d dictName deps className tys
223+ go (PositionedDeclaration pos com d) =
224+ rethrowWithPosition pos $ PositionedDeclaration pos com <$> go d
225+
226+ checkOrphanFixities :: Declaration -> Check ()
227+ checkOrphanFixities (FixityDeclaration _ name) = do
222 env <- getEnv
228 env <- getEnv
223 guardWith (errorMessage (OrphanFixityDeclaration name)) $ M.member (moduleName, Op name) $ names env
229 guardWith (errorMessage (OrphanFixityDeclaration name)) $ M.member (moduleName, Op name) $ names env
224− return $ d : ds
230+ checkOrphanFixities (PositionedDeclaration pos _ d) =
225− go (d@(ImportDeclaration importedModule _ _) : rest) = do
231+ rethrowWithPosition pos $ checkOrphanFixities d
226− tcds <- getTypeClassDictionaries
232+ checkOrphanFixities _ = return ()
227− let instances = filter (\tcd -> let Qualified (Just mn) _ = tcdName tcd in importedModule == mn) tcds
233+
228− addTypeClassDictionaries [ tcd { tcdName = Qualified (Just moduleName) ident, tcdType = TCDAlias (canonicalizeDictionary tcd) }
234+ goInstance :: Declaration -> Ident -> [Constraint] -> Qualified ProperName -> [Type] -> Check Declaration
229− | tcd <- instances
235+ goInstance d dictName deps className tys = do
230− , tcdExported tcd
231− , let (Qualified _ ident) = tcdName tcd
232− ]
233− ds <- go rest
234− return $ d : ds
235− go (d@(TypeClassDeclaration pn args implies tys) : rest) = do
236− addTypeClass moduleName pn args implies tys
237− ds <- go rest
238− return $ d : ds
239− go (d@(TypeInstanceDeclaration dictName deps className tys _) : rest) = do
240− goInstance d dictName deps className tys rest
241− go (d@(ExternInstanceDeclaration dictName deps className tys) : rest) = do
242− goInstance d dictName deps className tys rest
243− go (PositionedDeclaration pos com d : rest) =
244− rethrowWithPosition pos $ do
245− (d' : rest') <- go (d : rest)
246− return (PositionedDeclaration pos com d' : rest')
247− goInstance :: Declaration -> Ident -> [Constraint] -> Qualified ProperName -> [Type] -> [Declaration] -> Check [Declaration]
248− goInstance d dictName deps className tys rest = do
249 mapM_ (checkTypeClassInstance moduleName) tys
236 mapM_ (checkTypeClassInstance moduleName) tys
250 forM_ deps $ mapM_ (checkTypeClassInstance moduleName) . snd
237 forM_ deps $ mapM_ (checkTypeClassInstance moduleName) . snd
251− addTypeClassDictionaries [TypeClassDictionaryInScope (Qualified (Just moduleName) dictName) className tys (Just deps) TCDRegular isInstanceExported]
238+ let dict = TypeClassDictionaryInScope (Qualified (Just moduleName) dictName) className tys (Just deps) TCDRegular isInstanceExported
252− ds <- go rest
239+ addTypeClassDictionaries (Just moduleName) . M.singleton className $ M.singleton (canonicalizeDictionary dict) dict
253− return $ d : ds
240+ return d
254
241
255 where
242 where
256
243
src/Language/PureScript/TypeChecker/Entailment.hs+9−14
@@ -47,20 +47,17 @@ newtype Work = Work Integer deriving (Show, Eq, Ord, Num)
47-- Check that the current set of type class dictionaries entail the specified type class goal, and, if so,
47-- Check that the current set of type class dictionaries entail the specified type class goal, and, if so,
48-- return a type class dictionary reference.
48-- return a type class dictionary reference.
49--
49--
50−entails :: Environment -> ModuleName -> [TypeClassDictionaryInScope] -> Constraint -> Bool -> Check Expr
50+entails :: Environment -> ModuleName -> M.Map (Maybe ModuleName) (M.Map (Qualified ProperName) (M.Map (Qualified Ident) TypeClassDictionaryInScope)) -> Constraint -> Bool -> Check Expr
51−entails env moduleName context = solve (sortedNubBy canonicalizeDictionary (filter filterModule context))
51+entails env moduleName context = solve
52 where
52 where
53− sortedNubBy :: (Ord k) => (v -> k) -> [v] -> [v]
53+ forClassName :: Qualified ProperName -> [TypeClassDictionaryInScope]
54− sortedNubBy f vs = M.elems (M.fromList (map (f &&& id) vs))
54+ forClassName cn = findDicts cn Nothing ++ findDicts cn (Just moduleName)
55
55
56− -- Filter out type dictionaries which are in scope in the current module
56+ findDicts :: Qualified ProperName -> Maybe ModuleName -> [TypeClassDictionaryInScope]
57− filterModule :: TypeClassDictionaryInScope -> Bool
57+ findDicts cn = maybe [] M.elems . (>>= M.lookup cn) . flip M.lookup context
58− filterModule (TypeClassDictionaryInScope { tcdName = Qualified (Just mn) _ }) | mn == moduleName = True
59− filterModule (TypeClassDictionaryInScope { tcdName = Qualified Nothing _ }) = True
60− filterModule _ = False
61
58
62− solve :: [TypeClassDictionaryInScope] -> Constraint -> Bool -> Check Expr
59+ solve :: Constraint -> Bool -> Check Expr
63− solve context' (className, tys) trySuperclasses = do
60+ solve (className, tys) trySuperclasses = do
64 let dicts = flip evalStateT (Work 0) $ go trySuperclasses className tys
61 let dicts = flip evalStateT (Work 0) $ go trySuperclasses className tys
65 checkOverlaps dicts
62 checkOverlaps dicts
66 where
63 where
@@ -73,9 +70,7 @@ entails env moduleName context = solve (sortedNubBy canonicalizeDictionary (filt
73 where
70 where
74 directInstances :: StateT Work [] DictionaryValue
71 directInstances :: StateT Work [] DictionaryValue
75 directInstances = do
72 directInstances = do
76− tcd <- lift context'
73+ tcd <- lift $ forClassName className'
77− -- Make sure the type class name matches the one we are trying to satisfy
78− guard $ className' == tcdClassName tcd
79 -- Make sure the type unifies with the type in the type instance definition
74 -- Make sure the type unifies with the type in the type instance definition
80 subst <- lift . maybeToList . (>>= verifySubstitution) . fmap concat $ zipWithM (typeHeadsAreEqual moduleName env) tys' (tcdInstanceTypes tcd)
75 subst <- lift . maybeToList . (>>= verifySubstitution) . fmap concat $ zipWithM (typeHeadsAreEqual moduleName env) tys' (tcdInstanceTypes tcd)
81 -- Solve any necessary subgoals
76 -- Solve any necessary subgoals
src/Language/PureScript/TypeChecker/Monad.hs+11−5
@@ -69,17 +69,23 @@ withScopedTypeVars mn ks = bindTypes (M.fromList (map (\(name, k) -> (Qualified
69withTypeClassDictionaries :: (MonadState CheckState m) => [TypeClassDictionaryInScope] -> m a -> m a
69withTypeClassDictionaries :: (MonadState CheckState m) => [TypeClassDictionaryInScope] -> m a -> m a
70withTypeClassDictionaries entries action = do
70withTypeClassDictionaries entries action = do
71 orig <- get
71 orig <- get
72− let mentries = M.fromList [ ((canonicalizeDictionary entry, mn), entry) | entry@TypeClassDictionaryInScope{ tcdName = Qualified mn _ } <- entries ]
72+ let mentries = M.fromListWith (M.unionWith M.union) [ (mn, M.singleton className (M.singleton (canonicalizeDictionary entry) entry)) | entry@TypeClassDictionaryInScope{ tcdName = Qualified mn _, tcdClassName = className } <- entries ]
73− modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = (typeClassDictionaries . checkEnv $ st) `M.union` mentries } }
73+ modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = M.unionWith (M.unionWith M.union) (typeClassDictionaries . checkEnv $ st) mentries } }
74 a <- action
74 a <- action
75 modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = typeClassDictionaries . checkEnv $ orig } }
75 modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = typeClassDictionaries . checkEnv $ orig } }
76 return a
76 return a
77
77
78-- |
78-- |
79−-- Get the currently available list of type class dictionaries
79+-- Get the currently available map of type class dictionaries
80--
80--
81−getTypeClassDictionaries :: (Functor m, MonadState CheckState m) => m [TypeClassDictionaryInScope]
81+getTypeClassDictionaries :: (Functor m, MonadState CheckState m) => m (M.Map (Maybe ModuleName) (M.Map (Qualified ProperName) (M.Map (Qualified Ident) TypeClassDictionaryInScope)))
82−getTypeClassDictionaries = M.elems . typeClassDictionaries . checkEnv <$> get
82+getTypeClassDictionaries = typeClassDictionaries . checkEnv <$> get
83+
84+-- |
85+-- Lookup type class dictionaries in a module.
86+--
87+lookupTypeClassDictionaries :: (Functor m, MonadState CheckState m) => Maybe ModuleName -> m (M.Map (Qualified ProperName) (M.Map (Qualified Ident) TypeClassDictionaryInScope))
88+lookupTypeClassDictionaries mn = fromMaybe M.empty . M.lookup mn . typeClassDictionaries . checkEnv <$> get
83
89
84-- |
90-- |
85-- Temporarily bind a collection of names to local variables
91-- Temporarily bind a collection of names to local variables
src/Language/PureScript/TypeChecker/Synonyms.hs+10−17
@@ -28,7 +28,6 @@ import Data.Maybe (fromMaybe)
28import qualified Data.Map as M
28import qualified Data.Map as M
29
29
30import Control.Applicative
30import Control.Applicative
31−import Control.Monad
32import Control.Monad.Error.Class (MonadError(..))
31import Control.Monad.Error.Class (MonadError(..))
33import Control.Monad.State
32import Control.Monad.State
34
33
@@ -41,28 +40,22 @@ import Language.PureScript.Types
41-- |
40-- |
42-- Build a type substitution for a type synonym
41-- Build a type substitution for a type synonym
43--
42--
44−buildTypeSubstitution :: Qualified ProperName -> Int -> Type -> Either ErrorMessage (Maybe Type)
43+buildTypeSubstitution :: M.Map (Qualified ProperName) Int -> Type -> Either ErrorMessage (Maybe Type)
45−buildTypeSubstitution name n = go n []
44+buildTypeSubstitution m = go 0 []
46 where
45 where
47 go :: Int -> [Type] -> Type -> Either ErrorMessage (Maybe Type)
46 go :: Int -> [Type] -> Type -> Either ErrorMessage (Maybe Type)
48− go 0 args (TypeConstructor ctor) | name == ctor = return (Just $ SaturatedTypeSynonym ctor args)
47+ go c args (TypeConstructor ctor) | M.lookup ctor m == Just c = return (Just $ SaturatedTypeSynonym ctor args)
49− go m _ (TypeConstructor ctor) | m > 0 && name == ctor = throwError $ SimpleErrorWrapper $ PartiallyAppliedSynonym name
48+ go c _ (TypeConstructor ctor) | M.lookup ctor m > Just c = throwError $ SimpleErrorWrapper $ PartiallyAppliedSynonym ctor
50− go m args (TypeApp f arg) = go (m - 1) (arg:args) f
49+ go c args (TypeApp f arg) = go (c + 1) (arg:args) f
51 go _ _ _ = return Nothing
50 go _ _ _ = return Nothing
52
51
53−-- |
54−-- Replace all instances of a specific type synonym with the @SaturatedTypeSynonym@ data constructor
55−--
56−saturateTypeSynonym :: Qualified ProperName -> Int -> Type -> Either ErrorMessage Type
57−saturateTypeSynonym name n = everywhereOnTypesTopDownM replace
58− where
59− replace t = fromMaybe t <$> buildTypeSubstitution name n t
60−
61-- |
52-- |
62-- Replace all type synonyms with the @SaturatedTypeSynonym@ data constructor
53-- Replace all type synonyms with the @SaturatedTypeSynonym@ data constructor
63--
54--
64−saturateAllTypeSynonyms :: [(Qualified ProperName, Int)] -> Type -> Either ErrorMessage Type
55+saturateAllTypeSynonyms :: M.Map (Qualified ProperName) Int -> Type -> Either ErrorMessage Type
65−saturateAllTypeSynonyms syns d = foldM (\result (name, n) -> saturateTypeSynonym name n result) d syns
56+saturateAllTypeSynonyms syns = everywhereOnTypesTopDownM replace
57+ where
58+ replace t = fromMaybe t <$> buildTypeSubstitution syns t
66
59
67-- |
60-- |
68-- \"Desaturate\" @SaturatedTypeSynonym@s
61-- \"Desaturate\" @SaturatedTypeSynonym@s
@@ -80,7 +73,7 @@ desaturateAllTypeSynonyms = everywhereOnTypes replaceSaturatedTypeSynonym
80replaceAllTypeSynonyms' :: Environment -> Type -> Either ErrorMessage Type
73replaceAllTypeSynonyms' :: Environment -> Type -> Either ErrorMessage Type
81replaceAllTypeSynonyms' env d =
74replaceAllTypeSynonyms' env d =
82 let
75 let
83− syns = map (\(name, (args, _)) -> (name, length args)) . M.toList $ typeSynonyms env
76+ syns = length . fst <$> typeSynonyms env
84 in
77 in
85 saturateAllTypeSynonyms syns d
78 saturateAllTypeSynonyms syns d
86
79
src/Language/PureScript/TypeChecker/Types.hs+7−4
@@ -369,12 +369,15 @@ inferBinder val (ConstructorBinder ctor binders) = do
369 fn' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ fn
369 fn' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ fn
370 go binders fn'
370 go binders fn'
371 where
371 where
372− go [] ty' = do
372+ go [] ty' = case (val, ty') of
373− _ <- subsumes Nothing val ty'
373+ (TypeConstructor _, TypeApp _ _) -> throwIncorrectArity
374− return M.empty
374+ _ -> do
375+ _ <- subsumes Nothing val ty'
376+ return M.empty
375 go (binder : binders') (TypeApp (TypeApp t obj) ret) | t == tyFunction =
377 go (binder : binders') (TypeApp (TypeApp t obj) ret) | t == tyFunction =
376 M.union <$> inferBinder obj binder <*> go binders' ret
378 M.union <$> inferBinder obj binder <*> go binders' ret
377− go _ _ = throwError . errorMessage $ IncorrectConstructorArity ctor
379+ go _ _ = throwIncorrectArity
380+ throwIncorrectArity = throwError . errorMessage $ IncorrectConstructorArity ctor
378 _ -> throwError . errorMessage $ UnknownDataConstructor ctor Nothing
381 _ -> throwError . errorMessage $ UnknownDataConstructor ctor Nothing
379inferBinder val (ObjectBinder props) = do
382inferBinder val (ObjectBinder props) = do
380 row <- fresh
383 row <- fresh
src/Language/PureScript/Types.hs+8−2
@@ -14,11 +14,15 @@
14-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
15
15
16{-# LANGUAGE DeriveDataTypeable #-}
16{-# LANGUAGE DeriveDataTypeable #-}
17+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
18+{-# LANGUAGE TemplateHaskell #-}
17
19
18module Language.PureScript.Types where
20module Language.PureScript.Types where
19
21
20import Data.Data
22import Data.Data
21import Data.List (nub)
23import Data.List (nub)
24+import qualified Data.Aeson as A
25+import qualified Data.Aeson.TH as A
22
26
23import Control.Monad.Unify
27import Control.Monad.Unify
24import Control.Arrow (second)
28import Control.Arrow (second)
@@ -32,7 +36,7 @@ import Language.PureScript.Traversals
32-- |
36-- |
33-- An identifier for the scope of a skolem variable
37-- An identifier for the scope of a skolem variable
34--
38--
35−newtype SkolemScope = SkolemScope { runSkolemScope :: Int } deriving (Show, Eq, Ord, Data, Typeable)
39+newtype SkolemScope = SkolemScope { runSkolemScope :: Int } deriving (Show, Eq, Ord, Data, Typeable, A.ToJSON, A.FromJSON)
36
40
37-- |
41-- |
38-- The type of types
42-- The type of types
@@ -98,13 +102,15 @@ data Type
98 -- |
102 -- |
99 -- A placeholder used in pretty printing
103 -- A placeholder used in pretty printing
100 --
104 --
101− | PrettyPrintForAll [String] Type deriving (Show, Eq, Data, Typeable)
105+ | PrettyPrintForAll [String] Type deriving (Show, Eq, Ord, Data, Typeable)
102
106
103-- |
107-- |
104-- A typeclass constraint
108-- A typeclass constraint
105--
109--
106type Constraint = (Qualified ProperName, [Type])
110type Constraint = (Qualified ProperName, [Type])
107
111
112+$(A.deriveJSON A.defaultOptions ''Type)
113+
108-- |
114-- |
109-- Convert a row to a list of pairs of labels and types
115-- Convert a row to a list of pairs of labels and types
110--
116--
stack.yamlnew file+9
@@ -0,0 +1,9 @@
1+flags: {}
2+packages:
3+- '.'
4+extra-deps:
5+- aeson-better-errors-0.8.0
6+- bower-json-0.7.0.0
7+- boxes-0.1.4
8+- pattern-arrows-0.0.2
9+resolver: lts-2.22
tests/Main.hs+175−65
@@ -12,107 +12,217 @@
12--
12--
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
14
14
15−{-# LANGUAGE DataKinds, DoAndIfThenElse, TupleSections #-}
15+{-# LANGUAGE DataKinds #-}
16+{-# LANGUAGE DoAndIfThenElse #-}
17+{-# LANGUAGE TupleSections #-}
18+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
19+{-# LANGUAGE FlexibleInstances #-}
20+
21+-- Failing tests can specify the kind of error that should be thrown with a
22+-- @shouldFailWith declaration. For example:
23+--
24+-- "-- @shouldFailWith TypesDoNotUnify"
25+--
26+-- will cause the test to fail unless that module fails to compile with exactly
27+-- one TypesDoNotUnify error.
28+--
29+-- If a module is expected to produce multiple type errors, then use multiple
30+-- @shouldFailWith lines; for example:
31+--
32+-- -- @shouldFailWith TypesDoNotUnify
33+-- -- @shouldFailWith TypesDoNotUnify
34+-- -- @shouldFailWith TransitiveExportError
16
35
17module Main (main) where
36module Main (main) where
18
37
19import qualified Language.PureScript as P
38import qualified Language.PureScript as P
39+import qualified Language.PureScript.CodeGen.JS as J
40+import qualified Language.PureScript.CoreFn as CF
20
41
21−import Data.List (isSuffixOf)
42+import Data.Char (isSpace)
43+import Data.Maybe (mapMaybe, fromMaybe)
44+import Data.List (isSuffixOf, sort, stripPrefix)
22import Data.Traversable (traverse)
45import Data.Traversable (traverse)
46+import Data.Time.Clock (UTCTime())
23
47
24import qualified Data.Map as M
48import qualified Data.Map as M
25
49
26import Control.Monad
50import Control.Monad
27import Control.Monad.IO.Class (liftIO)
51import Control.Monad.IO.Class (liftIO)
28−import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
29−import Control.Monad.Reader (runReaderT)
30−import Control.Monad.Writer (runWriterT)
31−import Control.Monad.Trans.Except (runExceptT)
32import Control.Applicative
52import Control.Applicative
53+import Control.Arrow ((>>>))
54+
55+import Control.Monad.Reader
56+import Control.Monad.Writer
57+import Control.Monad.Trans.Maybe
58+import Control.Monad.Trans.Except
59+import Control.Monad.Error.Class
33
60
34import System.Exit
61import System.Exit
35import System.Process
62import System.Process
36−import System.FilePath ((</>))
63+import System.FilePath
37−import System.Directory (getCurrentDirectory, getTemporaryDirectory, getDirectoryContents, findExecutable)
64+import System.Directory
65+import qualified System.FilePath.Glob as Glob
38
66
39import Text.Parsec (ParseError)
67import Text.Parsec (ParseError)
40
68
69+modulesDir :: FilePath
70+modulesDir = ".test_modules" </> "node_modules"
71+
72+makeActions :: M.Map P.ModuleName (FilePath, P.ForeignJS) -> P.MakeActions P.Make
73+makeActions foreigns = (P.buildMakeActions modulesDir (error "makeActions: input file map was read.") foreigns False)
74+ { P.getInputTimestamp = getInputTimestamp
75+ , P.getOutputTimestamp = getOutputTimestamp
76+ }
77+ where
78+ getInputTimestamp :: P.ModuleName -> P.Make (Either P.RebuildPolicy (Maybe UTCTime))
79+ getInputTimestamp mn
80+ | isSupportModule (P.runModuleName mn) = return (Left P.RebuildNever)
81+ | otherwise = return (Left P.RebuildAlways)
82+ where
83+ isSupportModule = flip elem supportModules
84+
85+ getOutputTimestamp :: P.ModuleName -> P.Make (Maybe UTCTime)
86+ getOutputTimestamp mn = do
87+ let filePath = modulesDir </> P.runModuleName mn
88+ exists <- liftIO $ doesDirectoryExist filePath
89+ return (if exists then Just (error "getOutputTimestamp: read timestamp") else Nothing)
90+
41readInput :: [FilePath] -> IO [(FilePath, String)]
91readInput :: [FilePath] -> IO [(FilePath, String)]
42readInput inputFiles = forM inputFiles $ \inputFile -> do
92readInput inputFiles = forM inputFiles $ \inputFile -> do
43 text <- readFile inputFile
93 text <- readFile inputFile
44 return (inputFile, text)
94 return (inputFile, text)
45
95
46−loadPrelude :: [(FilePath, String)] -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> Either P.MultipleErrors (String, String, P.Environment)
96+type TestM = WriterT [(FilePath, String)] IO
47−loadPrelude fs foreigns = do
48− ms <- P.parseModulesFromFiles id fs
49− fmap fst . runWriterT $ runReaderT (P.compileJS (map snd ms) foreigns []) (P.defaultCompileOptions { P.optionsAdditional = P.CompileOptions "Tests" [] [] })
50
97
51−compile :: P.Options P.Compile -> [FilePath] -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> IO (Either P.MultipleErrors (String, String, P.Environment))
98+runTest :: P.Make a -> IO (Either P.MultipleErrors a)
52−compile opts inputFiles foreigns = runExceptT . fmap fst . runWriterT . flip runReaderT opts $ do
99+runTest = fmap (fmap fst) . P.runMake P.defaultOptions
100+
101+compile :: [FilePath] -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> IO (Either P.MultipleErrors P.Environment)
102+compile inputFiles foreigns = runTest $ do
53 fs <- liftIO $ readInput inputFiles
103 fs <- liftIO $ readInput inputFiles
54 ms <- P.parseModulesFromFiles id fs
104 ms <- P.parseModulesFromFiles id fs
55− P.compileJS (map snd ms) foreigns []
105+ P.make (makeActions foreigns) (map snd ms)
56−
106+
57−assert :: FilePath -> P.Options P.Compile -> FilePath -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> (Either P.MultipleErrors (String, String, P.Environment) -> IO (Maybe String)) -> IO ()
107+assert :: [FilePath] ->
58−assert preludeExterns opts inputFile foreigns f = do
108+ M.Map P.ModuleName (FilePath, P.ForeignJS) ->
59− e <- compile opts [preludeExterns, inputFile] foreigns
109+ (Either P.MultipleErrors P.Environment -> IO (Maybe String)) ->
60− maybeErr <- f e
110+ TestM ()
111+assert inputFiles foreigns f = do
112+ e <- liftIO $ compile inputFiles foreigns
113+ maybeErr <- liftIO $ f e
61 case maybeErr of
114 case maybeErr of
62− Just err -> putStrLn err >> exitFailure
115+ Just err -> tell [(last inputFiles, err)]
63 Nothing -> return ()
116 Nothing -> return ()
64
117
65−assertCompiles :: String -> FilePath -> FilePath -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> IO ()
118+assertCompiles :: [FilePath] -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> TestM ()
66−assertCompiles preludeJs preludeExterns inputFile foreigns = do
119+assertCompiles inputFiles foreigns = do
67− putStrLn $ "Assert " ++ inputFile ++ " compiles successfully"
120+ liftIO . putStrLn $ "Assert " ++ last inputFiles ++ " compiles successfully"
68− let options = P.defaultCompileOptions
121+ assert inputFiles foreigns $ \e ->
69− { P.optionsMain = Just "Main"
70− , P.optionsAdditional = P.CompileOptions "Tests" ["Main"] ["Main"]
71− }
72− assert preludeExterns options inputFile foreigns $ either (return . Just . P.prettyPrintMultipleErrors False) $ \(js, _, _) -> do
73− process <- findNodeProcess
74− result <- traverse (\node -> readProcessWithExitCode node [] (preludeJs ++ js)) process
75− case result of
76− Just (ExitSuccess, out, _) -> putStrLn out >> return Nothing
77− Just (ExitFailure _, _, err) -> return $ Just err
78− Nothing -> return $ Just "Couldn't find node.js executable"
79−
80−assertDoesNotCompile :: FilePath -> FilePath -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> IO ()
81−assertDoesNotCompile preludeExterns inputFile foreigns = do
82− putStrLn $ "Assert " ++ inputFile ++ " does not compile"
83− assert preludeExterns (P.defaultCompileOptions { P.optionsAdditional = P.CompileOptions "Tests" [] [] }) inputFile foreigns $ \e ->
84 case e of
122 case e of
85− Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> return Nothing
123+ Left errs -> return . Just . P.prettyPrintMultipleErrors False $ errs
86− Right _ -> return $ Just "Should not have compiled"
124+ Right _ -> do
125+ process <- findNodeProcess
126+ let entryPoint = modulesDir </> "index.js"
127+ writeFile entryPoint "require('Main').main()"
128+ result <- traverse (\node -> readProcessWithExitCode node [entryPoint] "") process
129+ case result of
130+ Just (ExitSuccess, out, _) -> putStrLn out >> return Nothing
131+ Just (ExitFailure _, _, err) -> return $ Just err
132+ Nothing -> return $ Just "Couldn't find node.js executable"
133+
134+assertDoesNotCompile :: [FilePath] -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> TestM ()
135+assertDoesNotCompile inputFiles foreigns = do
136+ let testFile = last inputFiles
137+ liftIO . putStrLn $ "Assert " ++ testFile ++ " does not compile"
138+ shouldFailWith <- getShouldFailWith testFile
139+ assert inputFiles foreigns $ \e ->
140+ case e of
141+ Left errs -> do
142+ putStrLn (P.prettyPrintMultipleErrors False errs)
143+ return $ if null shouldFailWith
144+ then Just $ "shouldFailWith declaration is missing (errors were: "
145+ ++ show (map P.errorCode (P.runMultipleErrors errs))
146+ ++ ")"
147+ else checkShouldFailWith shouldFailWith errs
148+ Right _ ->
149+ return $ Just "Should not have compiled"
150+
151+ where
152+ getShouldFailWith =
153+ readFile
154+ >>> liftIO
155+ >>> fmap ( lines
156+ >>> mapMaybe (stripPrefix "-- @shouldFailWith ")
157+ >>> map trim
158+ )
159+
160+ checkShouldFailWith expected errs =
161+ let actual = map P.errorCode $ P.runMultipleErrors errs
162+ in if sort expected == sort actual
163+ then Nothing
164+ else Just $ "Expected these errors: " ++ show expected ++ ", but got these: " ++ show actual
165+
166+ trim =
167+ dropWhile isSpace >>> reverse >>> dropWhile isSpace >>> reverse
87
168
88findNodeProcess :: IO (Maybe String)
169findNodeProcess :: IO (Maybe String)
89findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names
170findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names
90− where
171+ where
91 names = ["nodejs", "node"]
172 names = ["nodejs", "node"]
92
173
93main :: IO ()
174main :: IO ()
94main = do
175main = do
176+ fetchSupportCode
95 cwd <- getCurrentDirectory
177 cwd <- getCurrentDirectory
96− let preludeDir = cwd </> "tests" </> "prelude"
178+
97− jsDir = preludeDir </> "js"
179+ let supportDir = cwd </> "tests" </> "support" </> "flattened"
98− prelude <- readInput [preludeDir </> "Prelude.purs"]
180+ let supportFiles ext = Glob.globDir1 (Glob.compile ("*." ++ ext)) supportDir
99− jsFiles <- map (jsDir </>) . filter (".js" `isSuffixOf`) <$> getDirectoryContents jsDir
181+
100− foreignFiles <- forM jsFiles (\f -> (f,) <$> readFile f)
182+ supportPurs <- supportFiles "purs"
183+ supportJS <- supportFiles "js"
184+
185+ foreignFiles <- forM supportJS (\f -> (f,) <$> readFile f)
101 Right (foreigns, _) <- runExceptT $ runWriterT $ P.parseForeignModulesFromFiles foreignFiles
186 Right (foreigns, _) <- runExceptT $ runWriterT $ P.parseForeignModulesFromFiles foreignFiles
102− putStrLn "Compiling Prelude"
187+
103− case loadPrelude prelude foreigns of
188+ let passing = cwd </> "examples" </> "passing"
104− Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> exitFailure
189+ passingTestCases <- sort . filter (".purs" `isSuffixOf`) <$> getDirectoryContents passing
105− Right (preludeJs, exts, _) -> do
190+ let failing = cwd </> "examples" </> "failing"
106− tmp <- getTemporaryDirectory
191+ failingTestCases <- sort . filter (".purs" `isSuffixOf`) <$> getDirectoryContents failing
107− let preludeExterns = tmp </> "prelude.externs"
192+
108− writeFile preludeExterns exts
193+ failures <- execWriterT $ do
109− putStrLn $ "Wrote " ++ preludeExterns
194+ forM_ passingTestCases $ \inputFile ->
110− let passing = cwd </> "examples" </> "passing"
195+ assertCompiles (supportPurs ++ [passing </> inputFile]) foreigns
111− passingTestCases <- getDirectoryContents passing
196+ forM_ failingTestCases $ \inputFile ->
112− forM_ passingTestCases $ \inputFile -> when (".purs" `isSuffixOf` inputFile) $
197+ assertDoesNotCompile (supportPurs ++ [failing </> inputFile]) foreigns
113− assertCompiles preludeJs preludeExterns (passing </> inputFile) foreigns
198+
114− let failing = cwd </> "examples" </> "failing"
199+ if null failures
115− failingTestCases <- getDirectoryContents failing
200+ then exitSuccess
116− forM_ failingTestCases $ \inputFile -> when (".purs" `isSuffixOf` inputFile) $
201+ else do
117− assertDoesNotCompile preludeExterns (failing </> inputFile) foreigns
202+ putStrLn "Failures:"
118− exitSuccess
203+ forM_ failures $ \(fp, err) ->
204+ let fp' = fromMaybe fp $ stripPrefix (failing ++ [pathSeparator]) fp
205+ in putStrLn $ fp' ++ ": " ++ err
206+ exitFailure
207+
208+fetchSupportCode :: IO ()
209+fetchSupportCode = do
210+ setCurrentDirectory "tests/support"
211+ callProcess "npm" ["install"]
212+ -- Sometimes we run as a root (e.g. in simple docker containers)
213+ -- And we are non-interactive: https://github.com/bower/bower/issues/1162
214+ callProcess "node_modules/.bin/bower" ["--allow-root", "install", "--config.interactive=false"]
215+ callProcess "node" ["setup.js"]
216+ setCurrentDirectory "../.."
217+
218+supportModules :: [String]
219+supportModules =
220+ [ "Control.Monad.Eff.Class"
221+ , "Control.Monad.Eff.Console"
222+ , "Control.Monad.Eff"
223+ , "Control.Monad.Eff.Unsafe"
224+ , "Control.Monad.ST"
225+ , "Data.Function"
226+ , "Prelude"
227+ , "Test.Assert"
228+ ]
tests/prelude/Prelude.pursdeleted−628
@@ -1,628 +0,0 @@
1−-- | This snapshot is provided for the purposes of running the test suite.
2−-- | It is not necessarily kept up to date with the official PureScript Prelude,
3−-- | and should not be used in user code.
4−-- | The official Prelude can be found at https://github.com/purescript/purescript-prelude
5−
6−module Prelude
7− ( Unit(..), unit
8− , ($), (#)
9− , length
10− , flip
11− , const
12− , asTypeOf
13− , otherwise
14− , (:), cons, concat
15− , Semigroupoid, (<<<), (>>>)
16− , Category, id
17− , Functor, (<$>), (<#>), void
18− , Apply, (<*>)
19− , Applicative, pure, liftA1
20− , Bind, (>>=)
21− , Monad, return, liftM1, ap
22− , Semigroup, (<>), (++)
23− , Semiring, (+), zero, (*), one
24− , ModuloSemiring, (/), mod, jsMod, (%)
25− , Ring, (-), negate
26− , Num
27− , DivisionRing
28− , Eq, (==), (/=)
29− , Ordering(..), Ord, compare, (<), (>), (<=), (>=)
30− , Bounded, top, bottom
31− , Lattice, sup, inf, (||), (&&)
32− , BoundedLattice
33− , ComplementedLattice, not
34− , DistributiveLattice
35− , BooleanAlgebra
36− , Show, show
37− ) where
38−
39− newtype Unit = Unit {}
40−
41− unit :: Unit
42− unit = Unit {}
43−
44− foreign import length :: forall a. Array a -> Number
45−
46− infixr 0 $
47− infixl 0 #
48−
49− ($) :: forall a b. (a -> b) -> a -> b
50− ($) f x = f x
51−
52− (#) :: forall a b. a -> (a -> b) -> b
53− (#) x f = f x
54−
55− flip :: forall a b c. (a -> b -> c) -> b -> a -> c
56− flip f b a = f a b
57−
58− const :: forall a b. a -> b -> a
59− const a _ = a
60−
61− asTypeOf :: forall a. a -> a -> a
62− asTypeOf x _ = x
63−
64− otherwise :: Boolean
65− otherwise = true
66−
67− foreign import cons :: forall a. a -> Array a -> Array a
68−
69− infixr 6 :
70−
71− (:) :: forall a. a -> Array a -> Array a
72− (:) = cons
73−
74− foreign import concat :: forall a. Array a -> Array a -> Array a
75−
76− infixr 9 >>>
77− infixr 9 <<<
78−
79− class Semigroupoid a where
80− (<<<) :: forall b c d. a c d -> a b c -> a b d
81−
82− instance semigroupoidArr :: Semigroupoid (->) where
83− (<<<) f g x = f (g x)
84−
85− (>>>) :: forall a b c d. (Semigroupoid a) => a b c -> a c d -> a b d
86− (>>>) f g = g <<< f
87−
88− class (Semigroupoid a) <= Category a where
89− id :: forall t. a t t
90−
91− instance categoryArr :: Category (->) where
92− id x = x
93−
94− infixl 4 <$>
95− infixl 1 <#>
96−
97− class Functor f where
98− (<$>) :: forall a b. (a -> b) -> f a -> f b
99−
100− instance functorArr :: Functor ((->) r) where
101− (<$>) = (<<<)
102−
103− (<#>) :: forall f a b. (Functor f) => f a -> (a -> b) -> f b
104− (<#>) fa f = f <$> fa
105−
106− void :: forall f a. (Functor f) => f a -> f Unit
107− void fa = const unit <$> fa
108−
109− infixl 4 <*>
110−
111− class (Functor f) <= Apply f where
112− (<*>) :: forall a b. f (a -> b) -> f a -> f b
113−
114− instance applyArr :: Apply ((->) r) where
115− (<*>) f g x = f x (g x)
116−
117− class (Apply f) <= Applicative f where
118− pure :: forall a. a -> f a
119−
120− instance applicativeArr :: Applicative ((->) r) where
121− pure = const
122−
123− return :: forall m a. (Applicative m) => a -> m a
124− return = pure
125−
126− liftA1 :: forall f a b. (Applicative f) => (a -> b) -> f a -> f b
127− liftA1 f a = pure f <*> a
128−
129− infixl 1 >>=
130−
131− class (Apply m) <= Bind m where
132− (>>=) :: forall a b. m a -> (a -> m b) -> m b
133−
134− instance bindArr :: Bind ((->) r) where
135− (>>=) m f x = f (m x) x
136−
137− class (Applicative m, Bind m) <= Monad m
138−
139− instance monadArr :: Monad ((->) r)
140−
141− liftM1 :: forall m a b. (Monad m) => (a -> b) -> m a -> m b
142− liftM1 f a = do
143− a' <- a
144− return (f a')
145−
146− ap :: forall m a b. (Monad m) => m (a -> b) -> m a -> m b
147− ap f a = do
148− f' <- f
149− a' <- a
150− return (f' a')
151−
152− infixr 5 <>
153− infixr 5 ++
154−
155− class Semigroup a where
156− (<>) :: a -> a -> a
157−
158− (++) :: forall s. (Semigroup s) => s -> s -> s
159− (++) = (<>)
160−
161− instance semigroupString :: Semigroup String where
162− (<>) = concatString
163−
164− instance semigroupUnit :: Semigroup Unit where
165− (<>) _ _ = unit
166−
167− instance semigroupArr :: (Semigroup s') => Semigroup (s -> s') where
168− (<>) f g = \x -> f x <> g x
169−
170− instance semigroupOrdering :: Semigroup Ordering where
171− (<>) LT _ = LT
172− (<>) GT _ = GT
173− (<>) EQ y = y
174−
175− foreign import concatString :: String -> String -> String
176−
177− infixl 6 +
178− infixl 7 *
179−
180− class Semiring a where
181− (+) :: a -> a -> a
182− zero :: a
183− (*) :: a -> a -> a
184− one :: a
185−
186− instance semiringNumber :: Semiring Number where
187− (+) = numAdd
188− zero = 0.0
189− (*) = numMul
190− one = 1.0
191−
192− instance semiringUnit :: Semiring Unit where
193− (+) _ _ = unit
194− zero = unit
195− (*) _ _ = unit
196− one = unit
197−
198− infixl 6 -
199−
200− class (Semiring a) <= Ring a where
201− (-) :: a -> a -> a
202−
203− instance ringNumber :: Ring Number where
204− (-) = numSub
205−
206− instance ringUnit :: Ring Unit where
207− (-) _ _ = unit
208−
209− negate :: forall a. (Ring a) => a -> a
210− negate a = zero - a
211−
212− infixl 7 /
213−
214− class (Semiring a) <= ModuloSemiring a where
215− (/) :: a -> a -> a
216− mod :: a -> a -> a
217−
218− instance moduloSemiringNumber :: ModuloSemiring Number where
219− (/) = numDiv
220− mod _ _ = 0.0
221−
222− instance moduloSemiringUnit :: ModuloSemiring Unit where
223− (/) _ _ = unit
224− mod _ _ = unit
225−
226− foreign import jsMod :: Number -> Number -> Number
227−
228− infixl 7 %
229−
230− (%) = jsMod
231−
232− class (Ring a, ModuloSemiring a) <= DivisionRing a
233−
234− instance divisionRingNumber :: DivisionRing Number
235−
236− instance divisionRingUnit :: DivisionRing Unit
237−
238− class (DivisionRing a) <= Num a
239−
240− instance numNumber :: Num Number
241−
242− instance numUnit :: Num Unit
243−
244− foreign import numAdd :: Number -> Number -> Number
245−
246− foreign import numMul :: Number -> Number -> Number
247−
248− foreign import numDiv :: Number -> Number -> Number
249−
250− foreign import numSub :: Number -> Number -> Number
251−
252− infix 4 ==
253− infix 4 /=
254−
255− class Eq a where
256− (==) :: a -> a -> Boolean
257− (/=) :: a -> a -> Boolean
258−
259− instance eqBoolean :: Eq Boolean where
260− (==) = refEq
261− (/=) = refIneq
262−
263− instance eqNumber :: Eq Number where
264− (==) = refEq
265− (/=) = refIneq
266−
267− instance eqInt :: Eq Int where
268− (==) = refEq
269− (/=) = refIneq
270−
271− instance eqChar :: Eq Char where
272− (==) = refEq
273− (/=) = refIneq
274−
275− instance eqString :: Eq String where
276− (==) = refEq
277− (/=) = refIneq
278−
279− instance eqUnit :: Eq Unit where
280− (==) _ _ = true
281− (/=) _ _ = false
282−
283− instance eqArray :: (Eq a) => Eq (Array a) where
284− (==) = eqArrayImpl (==)
285− (/=) xs ys = not (xs == ys)
286−
287− instance eqOrdering :: Eq Ordering where
288− (==) LT LT = true
289− (==) GT GT = true
290− (==) EQ EQ = true
291− (==) _ _ = false
292− (/=) x y = not (x == y)
293−
294− foreign import refEq :: forall a. a -> a -> Boolean
295−
296− foreign import refIneq :: forall a. a -> a -> Boolean
297−
298− foreign import eqArrayImpl :: forall a. (a -> a -> Boolean) -> Array a -> Array a -> Boolean
299−
300− data Ordering = LT | GT | EQ
301−
302− class (Eq a) <= Ord a where
303− compare :: a -> a -> Ordering
304−
305− instance ordBoolean :: Ord Boolean where
306− compare false false = EQ
307− compare false true = LT
308− compare true true = EQ
309− compare true false = GT
310−
311− instance ordNumber :: Ord Number where
312− compare = unsafeCompare
313−
314− instance ordString :: Ord String where
315− compare = unsafeCompare
316−
317− instance ordUnit :: Ord Unit where
318− compare _ _ = EQ
319−
320− instance ordArray :: (Ord a) => Ord (Array a) where
321− compare xs ys = compare 0.0 $ ordArrayImpl (\x y -> case compare x y of
322− EQ -> 0.0
323− LT -> -1.0
324− GT -> 1.0) xs ys
325−
326− foreign import ordArrayImpl :: forall a. (a -> a -> Number) -> Array a -> Array a -> Number
327−
328− instance ordOrdering :: Ord Ordering where
329− compare LT LT = EQ
330− compare EQ EQ = EQ
331− compare GT GT = EQ
332− compare LT _ = LT
333− compare EQ LT = GT
334− compare EQ GT = LT
335− compare GT _ = GT
336−
337− infixl 4 <
338− infixl 4 >
339− infixl 4 <=
340− infixl 4 >=
341−
342− (<) :: forall a. (Ord a) => a -> a -> Boolean
343− (<) a1 a2 = case a1 `compare` a2 of
344− LT -> true
345− _ -> false
346−
347− (>) :: forall a. (Ord a) => a -> a -> Boolean
348− (>) a1 a2 = case a1 `compare` a2 of
349− GT -> true
350− _ -> false
351−
352− (<=) :: forall a. (Ord a) => a -> a -> Boolean
353− (<=) a1 a2 = case a1 `compare` a2 of
354− GT -> false
355− _ -> true
356−
357− (>=) :: forall a. (Ord a) => a -> a -> Boolean
358− (>=) a1 a2 = case a1 `compare` a2 of
359− LT -> false
360− _ -> true
361−
362− unsafeCompare :: forall a. a -> a -> Ordering
363− unsafeCompare = unsafeCompareImpl LT EQ GT
364−
365− foreign import unsafeCompareImpl :: forall a. Ordering -> Ordering -> Ordering -> a -> a -> Ordering
366−
367− class (Ord a) <= Bounded a where
368− top :: a
369− bottom :: a
370−
371− instance boundedBoolean :: Bounded Boolean where
372− top = true
373− bottom = false
374−
375− instance boundedUnit :: Bounded Unit where
376− top = unit
377− bottom = unit
378−
379− instance boundedOrdering :: Bounded Ordering where
380− top = GT
381− bottom = LT
382−
383− class (Ord a) <= Lattice a where
384− sup :: a -> a -> a
385− inf :: a -> a -> a
386−
387− instance latticeBoolean :: Lattice Boolean where
388− sup = boolOr
389− inf = boolAnd
390−
391− instance latticeUnit :: Lattice Unit where
392− sup _ _ = unit
393− inf _ _ = unit
394−
395− infixr 2 ||
396− infixr 3 &&
397−
398− (||) :: forall a. (Lattice a) => a -> a -> a
399− (||) = sup
400−
401− (&&) :: forall a. (Lattice a) => a -> a -> a
402− (&&) = inf
403−
404− class (Bounded a, Lattice a) <= BoundedLattice a
405−
406− instance boundedLatticeBoolean :: BoundedLattice Boolean
407−
408− instance boundedLatticeUnit :: BoundedLattice Unit
409−
410− class (BoundedLattice a) <= ComplementedLattice a where
411− not :: a -> a
412−
413− instance complementedLatticeBoolean :: ComplementedLattice Boolean where
414− not = boolNot
415−
416− instance complementedLatticeUnit :: ComplementedLattice Unit where
417− not _ = unit
418−
419− class (Lattice a) <= DistributiveLattice a
420−
421− instance distributiveLatticeBoolean :: DistributiveLattice Boolean
422−
423− instance distributiveLatticeUnit :: DistributiveLattice Unit
424−
425− class (ComplementedLattice a, DistributiveLattice a) <= BooleanAlgebra a
426−
427− instance booleanAlgebraBoolean :: BooleanAlgebra Boolean
428−
429− instance booleanAlgebraUnit :: BooleanAlgebra Unit
430−
431− foreign import boolOr :: Boolean -> Boolean -> Boolean
432−
433− foreign import boolAnd :: Boolean -> Boolean -> Boolean
434−
435− foreign import boolNot :: Boolean -> Boolean
436−
437− class Show a where
438− show :: a -> String
439−
440− instance showBoolean :: Show Boolean where
441− show true = "true"
442− show false = "false"
443−
444− instance showNumber :: Show Number where
445− show = showNumberImpl
446−
447− instance showString :: Show String where
448− show = showStringImpl
449−
450− instance showUnit :: Show Unit where
451− show _ = "unit"
452−
453− instance showArray :: (Show a) => Show (Array a) where
454− show = showArrayImpl show
455−
456− instance showOrdering :: Show Ordering where
457− show LT = "LT"
458− show GT = "GT"
459− show EQ = "EQ"
460−
461− foreign import showNumberImpl :: Number -> String
462−
463− foreign import showStringImpl :: String -> String
464−
465− foreign import showArrayImpl :: forall a. (a -> String) -> Array a -> String
466−
467−module Data.Function where
468−
469− import Prelude
470−
471− on :: forall a b c. (b -> b -> c) -> (a -> b) -> a -> a -> c
472− on f g x y = g x `f` g y
473−
474− foreign import data Fn0 :: * -> *
475−
476− foreign import data Fn1 :: * -> * -> *
477−
478− foreign import data Fn2 :: * -> * -> * -> *
479−
480− foreign import data Fn3 :: * -> * -> * -> * -> *
481−
482− foreign import data Fn4 :: * -> * -> * -> * -> * -> *
483−
484− foreign import data Fn5 :: * -> * -> * -> * -> * -> * -> *
485−
486− foreign import data Fn6 :: * -> * -> * -> * -> * -> * -> * -> *
487−
488− foreign import data Fn7 :: * -> * -> * -> * -> * -> * -> * -> * -> *
489−
490− foreign import data Fn8 :: * -> * -> * -> * -> * -> * -> * -> * -> * -> *
491−
492− foreign import data Fn9 :: * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> *
493−
494− foreign import data Fn10 :: * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> *
495−
496− foreign import mkFn0 :: forall a. (Unit -> a) -> Fn0 a
497−
498− foreign import mkFn1 :: forall a b. (a -> b) -> Fn1 a b
499−
500− foreign import mkFn2 :: forall a b c. (a -> b -> c) -> Fn2 a b c
501−
502− foreign import mkFn3 :: forall a b c d. (a -> b -> c -> d) -> Fn3 a b c d
503−
504− foreign import mkFn4 :: forall a b c d e. (a -> b -> c -> d -> e) -> Fn4 a b c d e
505−
506− foreign import mkFn5 :: forall a b c d e f. (a -> b -> c -> d -> e -> f) -> Fn5 a b c d e f
507−
508− foreign import mkFn6 :: forall a b c d e f g. (a -> b -> c -> d -> e -> f -> g) -> Fn6 a b c d e f g
509−
510− foreign import mkFn7 :: forall a b c d e f g h. (a -> b -> c -> d -> e -> f -> g -> h) -> Fn7 a b c d e f g h
511−
512− foreign import mkFn8 :: forall a b c d e f g h i. (a -> b -> c -> d -> e -> f -> g -> h -> i) -> Fn8 a b c d e f g h i
513−
514− foreign import mkFn9 :: forall a b c d e f g h i j. (a -> b -> c -> d -> e -> f -> g -> h -> i -> j) -> Fn9 a b c d e f g h i j
515−
516− foreign import mkFn10 :: forall a b c d e f g h i j k. (a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k) -> Fn10 a b c d e f g h i j k
517−
518− foreign import runFn0 :: forall a. Fn0 a -> a
519−
520− foreign import runFn1 :: forall a b. Fn1 a b -> a -> b
521−
522− foreign import runFn2 :: forall a b c. Fn2 a b c -> a -> b -> c
523−
524− foreign import runFn3 :: forall a b c d. Fn3 a b c d -> a -> b -> c -> d
525−
526− foreign import runFn4 :: forall a b c d e. Fn4 a b c d e -> a -> b -> c -> d -> e
527−
528− foreign import runFn5 :: forall a b c d e f. Fn5 a b c d e f -> a -> b -> c -> d -> e -> f
529−
530− foreign import runFn6 :: forall a b c d e f g. Fn6 a b c d e f g -> a -> b -> c -> d -> e -> f -> g
531−
532− foreign import runFn7 :: forall a b c d e f g h. Fn7 a b c d e f g h -> a -> b -> c -> d -> e -> f -> g -> h
533−
534− foreign import runFn8 :: forall a b c d e f g h i. Fn8 a b c d e f g h i -> a -> b -> c -> d -> e -> f -> g -> h -> i
535−
536− foreign import runFn9 :: forall a b c d e f g h i j. Fn9 a b c d e f g h i j -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j
537−
538− foreign import runFn10 :: forall a b c d e f g h i j k. Fn10 a b c d e f g h i j k -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k
539−
540−module Assert where
541−
542− import Prelude
543− import Control.Monad.Eff
544−
545− foreign import data Assert :: !
546−
547− foreign import error :: forall a. String -> a
548−
549− foreign import assertPartial :: forall e a. (Unit -> a) -> Eff (assert :: Assert | e) Unit
550−
551− assert :: forall e. Boolean -> Eff (assert :: Assert | e) Unit
552− assert true = return unit
553− assert false = error "Assertion failed!"
554−
555−module Prelude.Unsafe where
556−
557− foreign import unsafeIndex :: forall a. Array a -> Number -> a
558−
559−module Control.Monad.Eff
560− ( Eff()
561− , Pure()
562− , runPure
563− , untilE, whileE
564− ) where
565−
566− import Prelude
567−
568− foreign import data Eff :: # ! -> * -> *
569−
570− foreign import returnE :: forall e a. a -> Eff e a
571−
572− foreign import bindE :: forall e a b. Eff e a -> (a -> Eff e b) -> Eff e b
573−
574− type Pure a = forall e. Eff e a
575−
576− foreign import runPure :: forall a. Pure a -> a
577−
578− instance functorEff :: Functor (Eff e) where
579− (<$>) = liftA1
580−
581− instance applyEff :: Apply (Eff e) where
582− (<*>) = ap
583−
584− instance applicativeEff :: Applicative (Eff e) where
585− pure = returnE
586−
587− instance bindEff :: Bind (Eff e) where
588− (>>=) = bindE
589−
590− instance monadEff :: Monad (Eff e)
591−
592− foreign import untilE :: forall e. Eff e Boolean -> Eff e Unit
593−
594− foreign import whileE :: forall e a. Eff e Boolean -> Eff e a -> Eff e Unit
595−
596−module Debug.Trace where
597−
598− import Prelude
599− import Control.Monad.Eff
600−
601− foreign import data Trace :: !
602−
603− foreign import trace :: forall r. String -> Eff (trace :: Trace | r) Unit
604−
605− print :: forall a r. (Show a) => a -> Eff (trace :: Trace | r) Unit
606− print o = trace (show o)
607−
608−module Control.Monad.ST where
609−
610− import Prelude
611− import Control.Monad.Eff
612−
613− foreign import data ST :: * -> !
614−
615− foreign import data STRef :: * -> * -> *
616−
617− foreign import newSTRef :: forall a h r. a -> Eff (st :: ST h | r) (STRef h a)
618−
619− foreign import readSTRef :: forall a h r. STRef h a -> Eff (st :: ST h | r) a
620−
621− foreign import modifySTRef :: forall a h r. STRef h a -> (a -> a) -> Eff (st :: ST h | r) a
622−
623− foreign import writeSTRef :: forall a h r. STRef h a -> a -> Eff (st :: ST h | r) a
624−
625− foreign import runST :: forall a r. (forall h. Eff (st :: ST h | r) a) -> Eff r a
626−
627− pureST :: forall a. (forall h r. Eff (st :: ST h | r) a) -> a
628− pureST st = runPure (runST st)
tests/prelude/js/Assert.jsdeleted−19
@@ -1,19 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Assert
5−
6−exports.error = function(msg) {
7− throw msg;
8−};
9−
10−exports.assertPartial = function(f) {
11− return function() {
12− try {
13− return f();
14− } catch (e) {
15− if (e instanceof Error) return;
16− throw new Error('Pattern match failure is not Error');
17− }
18− };
19−};
tests/prelude/js/Control.Monad.Eff.jsdeleted−40
@@ -1,40 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Control.Monad.Eff
5−
6−exports.returnE = function (a) {
7− return function () {
8− return a;
9− };
10−};
11−
12−exports.bindE = function (a) {
13− return function (f) {
14− return function () {
15− return f(a())();
16− };
17− };
18−};
19−
20−exports.runPure = function (f) {
21− return f();
22−};
23−
24−exports.untilE = function (f) {
25− return function () {
26− while (!f());
27− return {};
28− };
29−};
30−
31−exports.whileE = function (f) {
32− return function (a) {
33− return function () {
34− while (f()) {
35− a();
36− }
37− return {};
38− };
39− };
40−};
tests/prelude/js/Control.Monad.ST.jsdeleted−38
@@ -1,38 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Control.Monad.ST
5−
6−exports.newSTRef = function (val) {
7− return function () {
8− return { value: val };
9− };
10−};
11−
12−exports.readSTRef = function (ref) {
13− return function () {
14− return ref.value;
15− };
16−};
17−
18−exports.modifySTRef = function (ref) {
19− return function (f) {
20− return function () {
21− /* jshint boss: true */
22− return ref.value = f(ref.value);
23− };
24− };
25−};
26−
27−exports.writeSTRef = function (ref) {
28− return function (a) {
29− return function () {
30− /* jshint boss: true */
31− return ref.value = a;
32− };
33− };
34−};
35−
36−exports.runST = function (f) {
37− return f;
38−};
tests/prelude/js/Data.Function.jsdeleted−233
@@ -1,233 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Data.Function
5−
6−exports.mkFn0 = function (fn) {
7− return function () {
8− return fn({});
9− };
10−};
11−
12−exports.mkFn1 = function (fn) {
13− return function (a) {
14− return fn(a);
15− };
16−};
17−
18−exports.mkFn2 = function (fn) {
19− /* jshint maxparams: 2 */
20− return function (a, b) {
21− return fn(a)(b);
22− };
23−};
24−
25−exports.mkFn3 = function (fn) {
26− /* jshint maxparams: 3 */
27− return function (a, b, c) {
28− return fn(a)(b)(c);
29− };
30−};
31−
32−exports.mkFn4 = function (fn) {
33− /* jshint maxparams: 4 */
34− return function (a, b, c, d) {
35− return fn(a)(b)(c)(d);
36− };
37−};
38−
39−exports.mkFn5 = function (fn) {
40− /* jshint maxparams: 5 */
41− return function (a, b, c, d, e) {
42− return fn(a)(b)(c)(d)(e);
43− };
44−};
45−
46−exports.mkFn6 = function (fn) {
47− /* jshint maxparams: 6 */
48− return function (a, b, c, d, e, f) {
49− return fn(a)(b)(c)(d)(e)(f);
50− };
51−};
52−
53−exports.mkFn7 = function (fn) {
54− /* jshint maxparams: 7 */
55− return function (a, b, c, d, e, f, g) {
56− return fn(a)(b)(c)(d)(e)(f)(g);
57− };
58−};
59−
60−exports.mkFn8 = function (fn) {
61− /* jshint maxparams: 8 */
62− return function (a, b, c, d, e, f, g, h) {
63− return fn(a)(b)(c)(d)(e)(f)(g)(h);
64− };
65−};
66−
67−exports.mkFn9 = function (fn) {
68− /* jshint maxparams: 9 */
69− return function (a, b, c, d, e, f, g, h, i) {
70− return fn(a)(b)(c)(d)(e)(f)(g)(h)(i);
71− };
72−};
73−
74−exports.mkFn10 = function (fn) {
75− /* jshint maxparams: 10 */
76− return function (a, b, c, d, e, f, g, h, i, j) {
77− return fn(a)(b)(c)(d)(e)(f)(g)(h)(i)(j);
78− };
79−};
80−
81−exports.runFn0 = function (fn) {
82− return fn();
83−};
84−
85−exports.runFn1 = function (fn) {
86− return function (a) {
87− return fn(a);
88− };
89−};
90−
91−exports.runFn2 = function (fn) {
92− return function (a) {
93− return function (b) {
94− return fn(a, b);
95− };
96− };
97−};
98−
99−exports.runFn3 = function (fn) {
100− return function (a) {
101− return function (b) {
102− return function (c) {
103− return fn(a, b, c);
104− };
105− };
106− };
107−};
108−
109−exports.runFn4 = function (fn) {
110− return function (a) {
111− return function (b) {
112− return function (c) {
113− return function (d) {
114− return fn(a, b, c, d);
115− };
116− };
117− };
118− };
119−};
120−
121−exports.runFn5 = function (fn) {
122− return function (a) {
123− return function (b) {
124− return function (c) {
125− return function (d) {
126− return function (e) {
127− return fn(a, b, c, d, e);
128− };
129− };
130− };
131− };
132− };
133−};
134−
135−exports.runFn6 = function (fn) {
136− return function (a) {
137− return function (b) {
138− return function (c) {
139− return function (d) {
140− return function (e) {
141− return function (f) {
142− return fn(a, b, c, d, e, f);
143− };
144− };
145− };
146− };
147− };
148− };
149−};
150−
151−exports.runFn7 = function (fn) {
152− return function (a) {
153− return function (b) {
154− return function (c) {
155− return function (d) {
156− return function (e) {
157− return function (f) {
158− return function (g) {
159− return fn(a, b, c, d, e, f, g);
160− };
161− };
162− };
163− };
164− };
165− };
166− };
167−};
168−
169−exports.runFn8 = function (fn) {
170− return function (a) {
171− return function (b) {
172− return function (c) {
173− return function (d) {
174− return function (e) {
175− return function (f) {
176− return function (g) {
177− return function (h) {
178− return fn(a, b, c, d, e, f, g, h);
179− };
180− };
181− };
182− };
183− };
184− };
185− };
186− };
187−};
188−
189−exports.runFn9 = function (fn) {
190− return function (a) {
191− return function (b) {
192− return function (c) {
193− return function (d) {
194− return function (e) {
195− return function (f) {
196− return function (g) {
197− return function (h) {
198− return function (i) {
199− return fn(a, b, c, d, e, f, g, h, i);
200− };
201− };
202− };
203− };
204− };
205− };
206− };
207− };
208− };
209−};
210−
211−exports.runFn10 = function (fn) {
212− return function (a) {
213− return function (b) {
214− return function (c) {
215− return function (d) {
216− return function (e) {
217− return function (f) {
218− return function (g) {
219− return function (h) {
220− return function (i) {
221− return function (j) {
222− return fn(a, b, c, d, e, f, g, h, i, j);
223− };
224− };
225− };
226− };
227− };
228− };
229− };
230− };
231− };
232− };
233−};
tests/prelude/js/Debug.Trace.jsdeleted−11
@@ -1,11 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Debug.Trace
5−
6−exports.trace = function(s) {
7− return function() {
8− console.log(s);
9− return {};
10− };
11−};
tests/prelude/js/Prelude.Unsafe.jsdeleted−10
@@ -1,10 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Prelude.Unsafe
5−
6−exports.unsafeIndex = function(xs) {
7− return function(n) {
8− return xs[n];
9− };
10−};
tests/prelude/js/Prelude.jsdeleted−150
@@ -1,150 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Prelude
5−
6−exports.cons = function(e) {
7− return function(l) {
8− return [e].concat(l);
9− };
10−};
11−
12−exports.concat = function(l1) {
13− return function(l2) {
14− return l1.concat(l2);
15− };
16−};
17−
18−exports.length = function(a) {
19− return a.length;
20−};
21−
22−exports.concatString = function(s1) {
23− return function(s2) {
24− return s1 + s2;
25− };
26−};
27−
28−exports.numAdd = function (n1) {
29− return function (n2) {
30− return n1 + n2;
31− };
32−};
33−
34−exports.numMul = function (n1) {
35− return function (n2) {
36− return n1 * n2;
37− };
38−};
39−
40−exports.numDiv = function (n1) {
41− return function (n2) {
42− return n1 / n2;
43− };
44−};
45−
46−exports.numSub = function (n1) {
47− return function (n2) {
48− return n1 - n2;
49− };
50−};
51−
52−exports.jsMod = function(x) {
53− return function (y) {
54− return x % y;
55− };
56−};
57−
58−exports.refEq = function(r1) {
59− return function(r2) {
60− return r1 === r2;
61− };
62−};
63−
64−exports.refIneq = function(r1) {
65− return function(r2) {
66− return r1 !== r2;
67− };
68−};
69−
70−exports.eqArrayImpl = function(f) {
71− return function(xs) {
72− return function(ys) {
73− if (xs.length !== ys.length) return false;
74− for (var i = 0; i < xs.length; i++) {
75− if (!f(xs[i])(ys[i])) return false;
76− }
77− return true;
78− };
79− };
80−};
81−
82−exports.ordArrayImpl = function(f) {
83− return function (xs) {
84− return function (ys) {
85− var i = 0;
86− while (i < xs.length && i < ys.length) {
87− var x = xs[i];
88− var y = ys[i];
89− var o = f(x)(y);
90− if (o !== 0) {
91− return o;
92− }
93− }
94− if (xs.length == ys.length) {
95− return 0;
96− } else if (xs.length > ys.length) {
97− return 1;
98− } else {
99− return -1;
100− }
101− };
102− };
103−};
104−
105−exports.unsafeCompareImpl = function(lt) {
106− return function(eq) {
107− return function(gt) {
108− return function(x) {
109− return function(y) {
110− return x < y ? lt : x > y ? gt : eq;
111− };
112− };
113− };
114− };
115−};
116−
117−exports.boolOr = function (b1) {
118− return function (b2) {
119− return b1 || b2;
120− };
121−};
122−
123−exports.boolAnd = function (b1) {
124− return function (b2) {
125− return b1 && b2;
126− };
127−};
128−
129−exports.boolNot = function (b) {
130− return !b;
131−};
132−
133−exports.showNumberImpl = function (n) {
134− /* jshint bitwise: false */
135− return n === (n | 0) ? n + ".0" : n.toString();
136−};
137−
138−exports.showStringImpl = function (s) {
139− return JSON.stringify(s);
140−};
141−
142−exports.showArrayImpl = function (f) {
143− return function (xs) {
144− var ss = [];
145− for (var i = 0, l = xs.length; i < l; i++) {
146− ss[i] = f(xs[i]);
147− }
148− return "[" + ss.join(",") + "]";
149− };
150−};
tests/support/.gitignorenew file+2
@@ -0,0 +1,2 @@
1+node_modules/
2+bower_components/
tests/support/bower.jsonnew file+11
@@ -0,0 +1,11 @@
1+{
2+ "name": "purescript-test-suite-support",
3+ "dependencies": {
4+ "purescript-eff": "0.1.0",
5+ "purescript-prelude": "0.1.1",
6+ "purescript-assert": "0.1.1",
7+ "purescript-st": "0.1.0",
8+ "purescript-console": "0.1.0",
9+ "purescript-functions": "0.1.0"
10+ }
11+}
tests/support/package.jsonnew file+7
@@ -0,0 +1,7 @@
1+{
2+ "private": true,
3+ "dependencies": {
4+ "bower": "^1.4.1",
5+ "glob": "^5.0.14"
6+ }
7+}
tests/support/setup.jsnew file+22
@@ -0,0 +1,22 @@
1+var glob = require("glob");
2+var fs = require("fs");
3+
4+try {
5+ fs.mkdirSync("./flattened");
6+} catch(e) {
7+ // ignore the error if it already exists
8+ if (e.code !== "EEXIST") {
9+ throw(e);
10+ }
11+}
12+
13+glob("bower_components/*/src/**/*.{js,purs}", function(err, files) {
14+ if (err) throw err;
15+ files.forEach(function(file) {
16+ // We join with "-" because Cabal is weird about file extensions.
17+ var dest = "./flattened/" + file.split("/").slice(3).join("-");
18+ console.log("Copying " + file + " to " + dest);
19+ var content = fs.readFileSync(file, "utf-8");
20+ fs.writeFileSync(dest, content, "utf-8");
21+ });
22+})
travis-after-script.shdeleted−21
@@ -1,21 +0,0 @@
1−set -e
2−
3−pushd core-tests/
4−
5−./test-everything.sh
6−
7−popd
8−
9−if [ -z $( git describe --tags --exact-match 2>/dev/null ) ]
10−then
11− cabal install hpc-coveralls
12− case "$SUITE" in
13− "tests")
14− hpc-coveralls --exclude-dir=dist/build/autogen --exclude-dir=tests tests;;
15− "psci-tests")
16− hpc-coveralls --exclude-dir=dist/build/autogen --exclude-dir=src --exclude-dir=psci/tests psci-tests;;
17− *)
18− echo "unrecognised test suite $SUITE"
19− exit 1;;
20− esac
21−fi
travis-script.shdeleted−17
@@ -1,17 +0,0 @@
1−set -e
2−
3−if [ -z $( git describe --tags --exact-match 2>/dev/null ) ]
4−then
5− cabal configure --enable-tests --enable-coverage -v2
6−else
7− cabal configure --enable-tests -v2
8−fi
9−
10−cabal build
11−cabal test
12−
13−# Check that a source distribution can be successfully generated, and that
14−# the generated source distribution can be installed
15−cabal sdist
16−SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&
17− (cd dist && cabal install --force-reinstalls "$SRC_TGZ")
travis/after.shnew file+25
@@ -0,0 +1,25 @@
1+set -e
2+
3+pushd core-tests/
4+./test-everything.sh
5+popd
6+
7+if ! git describe --tags --exact-match >/dev/null 2>/dev/null && [ -n "$COVERAGE_SUITE" ]
8+then
9+ case "$COVERAGE_SUITE" in
10+ "tests")
11+ ./.cabal-sandbox/bin/hpc-coveralls \
12+ --exclude-dir=dist/build/autogen \
13+ --exclude-dir=tests \
14+ tests;;
15+ "psci-tests")
16+ ./.cabal-sandbox/bin/hpc-coveralls \
17+ --exclude-dir=dist/build/autogen \
18+ --exclude-dir=src \
19+ --exclude-dir=psci/tests \
20+ psci-tests;;
21+ *)
22+ echo "unrecognised test suite $COVERAGE_SUITE"
23+ exit 1;;
24+ esac
25+fi
travis/configure.shnew file+17
@@ -0,0 +1,17 @@
1+set -e
2+
3+configure_flags="--enable-tests -v2"
4+
5+if ! git describe --tags --exact-match >/dev/null 2>/dev/null
6+then
7+ # Not a release build
8+ configure_flags="--disable-optimization $configure_flags"
9+fi
10+
11+if [ -n "$COVERAGE_SUITE" ]
12+then
13+ configure_flags="--enable-coverage $configure_flags"
14+fi
15+
16+echo "> cabal configure $configure_flags"
17+cabal configure $configure_flags
travis/test-install.shnew file+12
@@ -0,0 +1,12 @@
1+set -e
2+
3+# Check that a source distribution can be successfully generated, and that
4+# the generated source distribution can be installed
5+cabal sdist
6+if SRC_TGZ="$PWD/dist/$(cabal info . | awk '{print $2;exit}').tar.gz"
7+then
8+ mkdir -p ../install-test
9+ cd ../install-test
10+ cabal sandbox init
11+ cabal install -j2 --ghc-options='+RTS -A32m -RTS' "$SRC_TGZ"
12+fi