git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge tag 'v0.8.1' into pure11
fa8106bAndy Arvanitis
.travis.yml+9−9
@@ -6,21 +6,21 @@ matrix:
6 compiler: ": #GHC 7.8.4 - tests"
6 compiler: ": #GHC 7.8.4 - tests"
7 # ^ HACK before https://github.com/travis-ci/travis-ci/issues/4393 is resolved
7 # ^ HACK before https://github.com/travis-ci/travis-ci/issues/4393 is resolved
8 addons: {apt: {packages: [cabal-install-1.22,ghc-7.8.4,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
8 addons: {apt: {packages: [cabal-install-1.22,ghc-7.8.4,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
9− - env: GHCVER=7.8.4 CABALVER=1.22 STACKAGE=lts-2.22
10− compiler: ": #GHC 7.8.4 - lts-2.22-1"
11− addons: {apt: {packages: [cabal-install-1.22,ghc-7.8.4,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
12 - env: GHCVER=7.6.3 CABALVER=1.22
9 - env: GHCVER=7.6.3 CABALVER=1.22
13 compiler: ": #GHC 7.6.3"
10 compiler: ": #GHC 7.6.3"
14 addons: {apt: {packages: [cabal-install-1.22,ghc-7.6.3,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
11 addons: {apt: {packages: [cabal-install-1.22,ghc-7.6.3,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
15 - env: GHCVER=7.10.1 CABALVER=1.22 DEPLOY=yes
12 - env: GHCVER=7.10.1 CABALVER=1.22 DEPLOY=yes
16 compiler: ": #GHC 7.10.1"
13 compiler: ": #GHC 7.10.1"
17 addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.1,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
14 addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.1,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
18− - env: GHCVER=7.10.2 CABALVER=1.22 STACKAGE=lts=3.6 RUNSDISTTESTS=YES
15+ - env: GHCVER=7.10.2 CABALVER=1.22 STACKAGE=lts-3.22 RUNSDISTTESTS=YES
19− compiler: ": #GHC 7.10.2 lts-3.6"
16+ compiler: ": #GHC 7.10.2 lts-3.22"
20− addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.2,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
21− - env: GHCVER=7.10.2 CABALVER=1.22 STACKAGE=nightly-2015-09-29
22− compiler: ": #GHC 7.10.2 nightly-2015-09-29"
23 addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.2,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
17 addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.2,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
18+ - env: GHCVER=7.10.3 CABALVER=1.22 STACKAGE=lts-5.4 RUNSDISTTESTS=YES
19+ compiler: ": #GHC 7.10.3 lts-5.4"
20+ addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
21+ - env: GHCVER=7.10.3 CABALVER=1.22 STACKAGE=nightly-2016-02-25
22+ compiler: ": #GHC 7.10.3 nightly-2016-02-25"
23+ addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
24 - env: GHCVER=7.10.3 CABALVER=1.22
24 - env: GHCVER=7.10.3 CABALVER=1.22
25 compiler: ": #GHC 7.10.3"
25 compiler: ": #GHC 7.10.3"
26 addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
26 addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
@@ -51,7 +51,7 @@ install:
51 - mkdir -p .cabal-sandbox
51 - mkdir -p .cabal-sandbox
52 - cabal sandbox init --sandbox .cabal-sandbox
52 - cabal sandbox init --sandbox .cabal-sandbox
53 # Download stackage cabal.config, not sure whether filtering is necessary
53 # Download stackage cabal.config, not sure whether filtering is necessary
54− - if [ -n "$STACKAGE" ]; then curl https://www.stackage.org/$STACKAGE/cabal.config | grep -v purescript > cabal.config; fi
54+ - if [ -n "$STACKAGE" ]; then curl https://www.stackage.org/$STACKAGE/cabal.config | egrep -v 'purescript|sourcemap' > cabal.config; fi
55 - cabal install --only-dependencies --enable-tests
55 - cabal install --only-dependencies --enable-tests
56 - cabal install hpc-coveralls
56 - cabal install hpc-coveralls
57 # Snapshot state of the sandbox now, so we don't need to make new one for test install
57 # Snapshot state of the sandbox now, so we don't need to make new one for test install
CONTRIBUTORS.md+8−8
@@ -13,7 +13,10 @@ This file lists the contributors to the PureScript compiler project, and the ter
13- [@bergmark](https://github.com/bergmark) (Adam Bergmark) - My existing contributions and all future contributions until further notice are Copyright Adam Bergmark, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.
13- [@bergmark](https://github.com/bergmark) (Adam Bergmark) - My existing contributions and all future contributions until further notice are Copyright Adam Bergmark, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.
14- [@Bogdanp](https://github.com/Bogdanp) (Bogdan Paul Popa) My existing contributions and all future contributions until further notice are Copyright Bogdan Paul Popa, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
14- [@Bogdanp](https://github.com/Bogdanp) (Bogdan Paul Popa) My existing contributions and all future contributions until further notice are Copyright Bogdan Paul Popa, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
15- [@cdepillabout](https://github.com/cdepillabout) (Dennis Gosnell) My existing contributions and all future contributions until further notice are Copyright Dennis Gosnell, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
15- [@cdepillabout](https://github.com/cdepillabout) (Dennis Gosnell) My existing contributions and all future contributions until further notice are Copyright Dennis Gosnell, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
16+- [@chrissmoak](https://github.com/chrissmoak) (Chris Smoak) My existing contributions to the PureScript compiler and all future contributions to the PureScript compiler until further notice, are Copyright Chris Smoak, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
17+- [@codedmart](https://github.com/codedmart) (Brandon Martin) My existing contributions and all future contributions until further notice are Copyright Brandon Martin, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
16- [@davidchambers](https://github.com/davidchambers) (David Chambers) My existing contributions and all future contributions until further notice are Copyright David Chambers, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
18- [@davidchambers](https://github.com/davidchambers) (David Chambers) My existing contributions and all future contributions until further notice are Copyright David Chambers, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
19+- [@DavidLindbom](https://github.com/DavidLindbom) (David Lindbom) My existing contributions and all future contributions until further notice are Copyright David Lindbom, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
17- [@dckc](https://github.com/dckc) (Dan Connolly) My existing contributions and all future contributions until further notice are Copyright Dan Connolly, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
20- [@dckc](https://github.com/dckc) (Dan Connolly) My existing contributions and all future contributions until further notice are Copyright Dan Connolly, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
18- [@dylex](https://github.com/dylex) (Dylan Simon) My existing and all future contributions to the PureScript compiler until further notice are Copyright Dylan Simon, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
21- [@dylex](https://github.com/dylex) (Dylan Simon) My existing and all future contributions to the PureScript compiler until further notice are Copyright Dylan Simon, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
19- [@eamelink](https://github.com/eamelink) (Erik Bakker) - My existing contributions and all future contributions until further notice are Copyright Erik Bakker, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.
22- [@eamelink](https://github.com/eamelink) (Erik Bakker) - My existing contributions and all future contributions until further notice are Copyright Erik Bakker, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.
@@ -22,6 +25,7 @@ This file lists the contributors to the PureScript compiler project, and the ter
22- [@etrepum](https://github.com/etrepum) (Bob Ippolito) My existing contributions and all future contributions until further notice are Copyright Bob Ippolito, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
25- [@etrepum](https://github.com/etrepum) (Bob Ippolito) My existing contributions and all future contributions until further notice are Copyright Bob Ippolito, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
23- [@garyb](https://github.com/garyb) (Gary Burgess) My existing contributions and all future contributions until further notice are Copyright Gary Burgess, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
26- [@garyb](https://github.com/garyb) (Gary Burgess) My existing contributions and all future contributions until further notice are Copyright Gary Burgess, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
24- [@hdgarrood](https://github.com/hdgarrood) (Harry Garrood) My existing contributions and all future contributions until further notice are Copyright Harry Garrood, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
27- [@hdgarrood](https://github.com/hdgarrood) (Harry Garrood) My existing contributions and all future contributions until further notice are Copyright Harry Garrood, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
28+- [@izgzhen](https://github.com/izgzhen) (Zhen Zhang) My existing contributions and all future contributions until further notice are Copyright Zhen Zhang, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
25- [@jacereda](https://github.com/jacereda) (Jorge Acereda) My existing contributions and all future contributions until further notice are Copyright Jorge Acereda, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
29- [@jacereda](https://github.com/jacereda) (Jorge Acereda) My existing contributions and all future contributions until further notice are Copyright Jorge Acereda, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
26- [@japesinator](https://github.com/japesinator) (JP Smith) My existing contributions and all future contributions until further notice are Copyright JP Smith, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
30- [@japesinator](https://github.com/japesinator) (JP Smith) My existing contributions and all future contributions until further notice are Copyright JP Smith, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
27- [@joneshf](https://github.com/joneshf) (Hardy Jones) - My existing contributions and all future contributions until further notice are Copyright Hardy Jones, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.
31- [@joneshf](https://github.com/joneshf) (Hardy Jones) - My existing contributions and all future contributions until further notice are Copyright Hardy Jones, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.
@@ -42,6 +46,7 @@ This file lists the contributors to the PureScript compiler project, and the ter
42- [@nwolverson](https://github.com/nwolverson) (Nicholas Wolverson) My existing contributions and all future contributions until further notice are Copyright Nicholas Wolverson, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
46- [@nwolverson](https://github.com/nwolverson) (Nicholas Wolverson) My existing contributions and all future contributions until further notice are Copyright Nicholas Wolverson, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
43- [@osa1](https://github.com/osa1) (Ömer Sinan Ağacan) - My existing contributions and all future contributions until further notice are Copyright Ömer Sinan Ağacan, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.
47- [@osa1](https://github.com/osa1) (Ömer Sinan Ağacan) - My existing contributions and all future contributions until further notice are Copyright Ömer Sinan Ağacan, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.
44- [@paf31](https://github.com/paf31) (Phil Freeman) My existing contributions and all future contributions until further notice are Copyright Phil Freeman, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
48- [@paf31](https://github.com/paf31) (Phil Freeman) My existing contributions and all future contributions until further notice are Copyright Phil Freeman, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
49+- [@passy](https://github.com/passy) (Pascal Hartig) My existing contributions and all future contributions until further notice are Copyright Pascal Hartig, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
45- [@paulyoung](https://github.com/paulyoung) (Paul Young) My existing contributions and all future contributions until further notice are Copyright Paul Young, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
50- [@paulyoung](https://github.com/paulyoung) (Paul Young) My existing contributions and all future contributions until further notice are Copyright Paul Young, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
46- [@pelotom](https://github.com/pelotom) (Thomas Crockett) My existing contributions and all future contributions until further notice are Copyright Thomas Crockett, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
51- [@pelotom](https://github.com/pelotom) (Thomas Crockett) My existing contributions and all future contributions until further notice are Copyright Thomas Crockett, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
47- [@phadej](https://github.com/phadej) (Oleg Grenrus) My existing contributions and all future contributions until further notice are Copyright Oleg Grenrus, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
52- [@phadej](https://github.com/phadej) (Oleg Grenrus) My existing contributions and all future contributions until further notice are Copyright Oleg Grenrus, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
@@ -51,21 +56,16 @@ This file lists the contributors to the PureScript compiler project, and the ter
51- [@robdaemon](https://github.com/robdaemon) (Robert Roland) My existing contributions and all future contributions until further notice are Copyright Robert Roland, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
56- [@robdaemon](https://github.com/robdaemon) (Robert Roland) My existing contributions and all future contributions until further notice are Copyright Robert Roland, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
52- [@RossMeikleham](https://github.com/RossMeikleham) (Ross Meikleham) My existing contributions and all future contributions until further notice are Copyright Ross Meikleham, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
57- [@RossMeikleham](https://github.com/RossMeikleham) (Ross Meikleham) My existing contributions and all future contributions until further notice are Copyright Ross Meikleham, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
53- [@sebastiaanvisser](https://github.com/sebastiaanvisser) (Sebastiaan Visser) - My existing contributions and all future contributions until further notice are Copyright Sebastiaan Visser, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.
58- [@sebastiaanvisser](https://github.com/sebastiaanvisser) (Sebastiaan Visser) - My existing contributions and all future contributions until further notice are Copyright Sebastiaan Visser, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.
59+- [@senju](https://github.com/senju) - My existing contributions and all future contributions until further notice are Copyright senju, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
54- [@sharkdp](https://github.com/sharkdp) (David Peter) My existing contributions and all future contributions until further notice are Copyright David Peter, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
60- [@sharkdp](https://github.com/sharkdp) (David Peter) My existing contributions and all future contributions until further notice are Copyright David Peter, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
61+- [@soupi](https://github.com/soupi) (Gil Mizrahi) My existing contributions and all future contributions until further notice are Copyright Gil Mizrahi, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
55- [@sztupi](https://github.com/sztupi) (Attila Sztupak) My existing contributions and all future contributions until further notice are Copyright Attila Sztupak, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
62- [@sztupi](https://github.com/sztupi) (Attila Sztupak) My existing contributions and all future contributions until further notice are Copyright Attila Sztupak, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
56- [@taku0](https://github.com/taku0) - My existing contributions and all future contributions until further notice are Copyright taku0, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
63- [@taku0](https://github.com/taku0) - My existing contributions and all future contributions until further notice are Copyright taku0, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
64+- [@tfausak](https://github.com/tfausak) (Taylor Fausak) My existing contributions and all future contributions until further notice are Copyright Taylor Fausak, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
57- [@trofi](https://github.com/trofi) (Sergei Trofimovich) My existing contributions and all future contributions until further notice are Copyright Sergei Trofimovich, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
65- [@trofi](https://github.com/trofi) (Sergei Trofimovich) My existing contributions and all future contributions until further notice are Copyright Sergei Trofimovich, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
58- [@utkarshkukreti](https://github.com/utkarshkukreti) (Utkarsh Kukreti) My existing contributions and all future contributions until further notice are Copyright Utkarsh Kukreti, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
66- [@utkarshkukreti](https://github.com/utkarshkukreti) (Utkarsh Kukreti) My existing contributions and all future contributions until further notice are Copyright Utkarsh Kukreti, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
59- [@vkorablin](https://github.com/vkorablin) (Vladimir Korablin) - My existing contributions and all future contributions until further notice are Copyright Vladimir Korablin, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.
67- [@vkorablin](https://github.com/vkorablin) (Vladimir Korablin) - My existing contributions and all future contributions until further notice are Copyright Vladimir Korablin, and are licensed to the owners and users of the PureScript compiler project under the terms of the MIT license.
60- [@zudov](https://github.com/zudov) (Konstantin Zudov) My existing contributions and all future contributions until further notice are Copyright Konstantin Zudov, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
68- [@zudov](https://github.com/zudov) (Konstantin Zudov) My existing contributions and all future contributions until further notice are Copyright Konstantin Zudov, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
61−- [@senju](https://github.com/senju) - My existing contributions and all future contributions until further notice are Copyright senju, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
62−<http://opensource.org/licenses/MIT>.
63−- [@soupi](https://github.com/soupi) (Gil Mizrahi) My existing contributions and all future contributions until further notice are Copyright Gil Mizrahi, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
64−- [@tfausak](https://github.com/tfausak) (Taylor Fausak) My existing contributions and all future contributions until further notice are Copyright Taylor Fausak, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
65−- [@codedmart](https://github.com/codedmart) (Brandon Martin) My existing contributions and all future contributions until further notice are Copyright Brandon Martin, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
66−- [@passy](https://github.com/passy) (Pascal Hartig) My existing contributions and all future contributions until further notice are Copyright Pascal Hartig, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
67−- [@DavidLindbom](https://github.com/DavidLindbom) (David Lindbom) My existing contributions and all future contributions until further notice are Copyright David Lindbom, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
68−- [@izgzhen](https://github.com/izgzhen) (Zhen Zhang) My existing contributions and all future contributions until further notice are Copyright Zhen Zhang, and are licensed to the owners and users of the PureScript compiler project under the terms of the [MIT license](http://opensource.org/licenses/MIT).
69
69
70### Companies
70### Companies
71
71
LICENSE+34
@@ -63,6 +63,7 @@ PureScript uses the following Haskell library packages. Their license files foll
63 safe
63 safe
64 scientific
64 scientific
65 semigroups
65 semigroups
66+ sourcemap
66 split
67 split
67 stm
68 stm
68 syb
69 syb
@@ -1589,6 +1590,39 @@ semigroups LICENSE file:
1589 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1590 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1590 POSSIBILITY OF SUCH DAMAGE.
1591 POSSIBILITY OF SUCH DAMAGE.
1591
1592
1593+sourcemap LICENSE file:
1594+
1595+ Copyright (c) 2012, Chris Done
1596+
1597+ All rights reserved.
1598+
1599+ Redistribution and use in source and binary forms, with or without
1600+ modification, are permitted provided that the following conditions are met:
1601+
1602+ * Redistributions of source code must retain the above copyright
1603+ notice, this list of conditions and the following disclaimer.
1604+
1605+ * Redistributions in binary form must reproduce the above
1606+ copyright notice, this list of conditions and the following
1607+ disclaimer in the documentation and/or other materials provided
1608+ with the distribution.
1609+
1610+ * Neither the name of Chris Done nor the names of other
1611+ contributors may be used to endorse or promote products derived
1612+ from this software without specific prior written permission.
1613+
1614+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1615+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1616+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1617+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1618+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1619+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1620+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1621+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1622+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1623+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1624+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1625+
1592split LICENSE file:
1626split LICENSE file:
1593
1627
1594 Copyright (c) 2008 Brent Yorgey, Louis Wasserman
1628 Copyright (c) 2008 Brent Yorgey, Louis Wasserman
bundle/README+9−6
@@ -10,12 +10,15 @@ Installation Instructions
10
10
11This bundle contains the following executables:
11This bundle contains the following executables:
12
12
13−- psc The PureScript compiler
13+- psc The PureScript compiler
14−- psci The PureScript interactive REPL (requires NodeJS)
14+- psci The PureScript interactive REPL (requires NodeJS)
15−- psc-docs A Markdown documentation generator for PureScript code
15+- psc-docs A Markdown documentation generator for PureScript code
16−- psc-bundle Bundles together CommonJS modules produced by `psc` into a
16+- psc-bundle Bundles together CommonJS modules produced by `psc` into a
17− single JavaScript file; useful for running in the browser.
17+ single JavaScript file; useful for running in the browser.
18−- psc-publish Generates documentation packages for uploading to Pursuit
18+- psc-publish Generates documentation packages for uploading to Pursuit
19+- psc-ide-server Provides Editor Support in the form of type information and
20+ autocompletion
21+- psc-ide-client Utility to query psc-ide-server
19
22
20Copy these files anywhere on your PATH.
23Copy these files anywhere on your PATH.
21
24
bundle/build-stack.shnew file+50
@@ -0,0 +1,50 @@
1+set -e
2+
3+SCRIPTPATH=$( cd "$(dirname "$0")" ; pwd -P )
4+
5+OS=$1
6+
7+if [ -z $OS ]
8+then
9+ echo "Usage: build.sh osname"
10+ exit 1
11+fi
12+
13+pushd ${SCRIPTPATH} > /dev/null
14+
15+# Make the staging directory
16+mkdir -p build/purescript/
17+
18+# Strip the binaries
19+strip ~/.local/bin/psc
20+strip ~/.local/bin/psci
21+strip ~/.local/bin/psc-docs
22+strip ~/.local/bin/psc-publish
23+strip ~/.local/bin/psc-bundle
24+strip ~/.local/bin/psc-ide-server
25+strip ~/.local/bin/psc-ide-client
26+
27+# Copy files to staging directory
28+cp ~/.local/bin/psc build/purescript/
29+cp ~/.local/bin/psci build/purescript/
30+cp ~/.local/bin/psc-docs build/purescript/
31+cp ~/.local/bin/psc-publish build/purescript/
32+cp ~/.local/bin/psc-bundle build/purescript/
33+cp ~/.local/bin/psc-ide-server build/purescript/
34+cp ~/.local/bin/psc-ide-client build/purescript/
35+cp README build/purescript/
36+cp ../LICENSE build/purescript/
37+cp ../INSTALL.md build/purescript/
38+
39+# Make the binary bundle
40+pushd build > /dev/null
41+tar -zcvf ../$OS.tar.gz purescript
42+popd > /dev/null
43+
44+# Calculate the SHA hash
45+shasum $OS.tar.gz > $OS.sha
46+
47+# Remove the staging directory
48+rm -rf build/
49+
50+popd > /dev/null
bundle/build.sh+12−8
@@ -21,16 +21,20 @@ strip ../dist/build/psci/psci
21strip ../dist/build/psc-docs/psc-docs
21strip ../dist/build/psc-docs/psc-docs
22strip ../dist/build/psc-publish/psc-publish
22strip ../dist/build/psc-publish/psc-publish
23strip ../dist/build/psc-bundle/psc-bundle
23strip ../dist/build/psc-bundle/psc-bundle
24+strip ../dist/build/psc-ide-server/psc-ide-server
25+strip ../dist/build/psc-ide-client/psc-ide-client
24
26
25# Copy files to staging directory
27# Copy files to staging directory
26−cp ../dist/build/psc/psc build/purescript/
28+cp ../dist/build/psc/psc build/purescript/
27−cp ../dist/build/psci/psci build/purescript/
29+cp ../dist/build/psci/psci build/purescript/
28−cp ../dist/build/psc-docs/psc-docs build/purescript/
30+cp ../dist/build/psc-docs/psc-docs build/purescript/
29−cp ../dist/build/psc-publish/psc-publish build/purescript/
31+cp ../dist/build/psc-publish/psc-publish build/purescript/
32+cp ../dist/build/psc-bundle/psc-bundle build/purescript/
33+cp ../dist/build/psc-ide-server/psc-ide-server build/purescript/
30−cp ../dist/build/psc-bundle/psc-bundle build/purescript/
34+cp ../dist/build/psc-ide-client/psc-ide-client build/purescript/
31−cp README build/purescript/
35+cp README build/purescript/
32−cp ../LICENSE build/purescript/
36+cp ../LICENSE build/purescript/
33−cp ../INSTALL.md build/purescript/
37+cp ../INSTALL.md build/purescript/
34
38
35# Make the binary bundle
39# Make the binary bundle
36pushd build > /dev/null
40pushd build > /dev/null
bundle/winbuild.sh+12−8
@@ -17,16 +17,20 @@ strip ../dist/build/psci/psci.exe
17strip ../dist/build/psc-docs/psc-docs.exe
17strip ../dist/build/psc-docs/psc-docs.exe
18strip ../dist/build/psc-publish/psc-publish.exe
18strip ../dist/build/psc-publish/psc-publish.exe
19strip ../dist/build/psc-bundle/psc-bundle.exe
19strip ../dist/build/psc-bundle/psc-bundle.exe
20+strip ../dist/build/psc-ide-server/psc-ide-server
21+strip ../dist/build/psc-ide-client/psc-ide-client
20
22
21# Copy files to staging directory
23# Copy files to staging directory
22−cp ../dist/build/psc/psc.exe build/purescript/
24+cp ../dist/build/psc/psc.exe build/purescript/
23−cp ../dist/build/psci/psci.exe build/purescript/
25+cp ../dist/build/psci/psci.exe build/purescript/
24−cp ../dist/build/psc-docs/psc-docs.exe build/purescript/
26+cp ../dist/build/psc-docs/psc-docs.exe build/purescript/
27+cp ../dist/build/psc-publish/psc-publish.exe build/purescript/
28+cp ../dist/build/psc-bundle/psc-bundle.exe build/purescript/
25−cp ../dist/build/psc-publish/psc-publish.exe build/purescript/
29+cp ../dist/build/psc-ide-server/psc-ide-server.exe build/purescript/
26−cp ../dist/build/psc-bundle/psc-bundle.exe build/purescript/
30+cp ../dist/build/psc-ide-client/psc-ide-client.exe build/purescript/
27−cp README build/purescript/
31+cp README build/purescript/
28−cp ../LICENSE build/purescript/
32+cp ../LICENSE build/purescript/
29−cp ../INSTALL.md build/purescript/
33+cp ../INSTALL.md build/purescript/
30
34
31# Make the binary bundle
35# Make the binary bundle
32pushd build
36pushd build
examples/failing/ConflictingExports2.pursdeleted−13
@@ -1,13 +0,0 @@
1−-- @shouldFailWith ScopeConflict
2−module A where
3−
4− thing :: Int
5− thing = 1
6−
7−-- Fails here because re-exporting forces any scope conflicts to be resolved
8−module Main (thing, module A) where
9−
10− import A
11−
12− thing :: Int
13− thing = 2
examples/failing/ConflictingImports2.purs+8−4
@@ -4,13 +4,17 @@ module A where
4 thing :: Int
4 thing :: Int
5 thing = 1
5 thing = 1
6
6
7−module Main where
7+module B where
8−
9− import A
10
8
11 thing :: Int
9 thing :: Int
12 thing = 2
10 thing = 2
13
11
12+module Main where
13+
14+ import A (thing)
15+ import B (thing)
16+
14− -- Error due to referencing `thing` which is in scope as A.thing and Main.thing
17+ -- Error due to referencing `thing` which is explicitly in scope as A.thing
18+ -- and B.thing
15 what :: Int
19 what :: Int
16 what = thing
20 what = thing
examples/passing/ResolvableScopeConflict.pursnew file+25
@@ -0,0 +1,25 @@
1+module A where
2+
3+ thing :: Int
4+ thing = 1
5+
6+module B where
7+
8+ thing :: Int
9+ thing = 2
10+
11+ zing :: Int
12+ zing = 3
13+
14+module Main where
15+
16+ import A (thing)
17+ import B
18+
19+ -- Not an error as although we have `thing` in scope from both A and B, it is
20+ -- imported explicitly from A, giving it a resolvable solution.
21+ what :: Boolean -> Int
22+ what true = thing
23+ what false = zing
24+
25+ main = Control.Monad.Eff.Console.log "Done"
examples/passing/ResolvableScopeConflict2.pursnew file+22
@@ -0,0 +1,22 @@
1+module A where
2+
3+ thing :: Int
4+ thing = 2
5+
6+ zing :: Int
7+ zing = 3
8+
9+module Main where
10+
11+ import A
12+
13+ thing :: Int
14+ thing = 1
15+
16+ -- Not an error as although we have `thing` in scope from both Main and A,
17+ -- as the local declaration takes precedence over the implicit import
18+ what :: Boolean -> Int
19+ what true = thing
20+ what false = zing
21+
22+ main = Control.Monad.Eff.Console.log "Done"
examples/passing/ResolvableScopeConflict3.pursnew file+15
@@ -0,0 +1,15 @@
1+module A where
2+
3+ thing :: Int
4+ thing = 1
5+
6+module Main (thing, main, module A) where
7+
8+ import A
9+
10+ thing :: Int
11+ thing = 2
12+
13+ main = Control.Monad.Eff.Console.log "Done"
14+
15+
psc-ide-client/Main.hsnew file+57
@@ -0,0 +1,57 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Main where
3+
4+import Prelude ()
5+import Prelude.Compat
6+
7+import Control.Exception
8+import Data.Maybe (fromMaybe)
9+import Data.Text (Text)
10+import qualified Data.Text as T
11+import qualified Data.Text.IO as T
12+import Data.Version (showVersion)
13+import Network
14+import Options.Applicative
15+import System.Exit
16+import System.IO
17+
18+import qualified Paths_purescript as Paths
19+
20+data Options = Options
21+ { optionsPort :: Maybe Int
22+ }
23+
24+main :: IO ()
25+main = do
26+ Options port <- execParser opts
27+ let port' = PortNumber . fromIntegral $ fromMaybe 4242 port
28+ client port'
29+ where
30+ parser =
31+ Options <$>
32+ optional (option auto (long "port" <> short 'p'))
33+ opts = info (version <*> parser) mempty
34+ version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> help "Show the version number" <> hidden
35+
36+client :: PortID -> IO ()
37+client port = do
38+ h <-
39+ connectTo "localhost" port `catch`
40+ (\(SomeException e) ->
41+ putStrLn
42+ ("Couldn't connect to psc-ide-server on port: " ++
43+ show port ++ " Error: " ++ show e) >>
44+ exitFailure)
45+ cmd <- T.getLine
46+ -- Temporary fix for emacs windows bug
47+ let cleanedCmd = removeSurroundingTicks cmd
48+ --
49+ T.hPutStrLn h cleanedCmd
50+ res <- T.hGetLine h
51+ putStrLn (T.unpack res)
52+ hFlush stdout
53+ hClose h
54+
55+-- TODO: Fix this in the emacs plugin by using a real process over shellcommands
56+removeSurroundingTicks :: Text -> Text
57+removeSurroundingTicks = T.dropWhile (== '\'') . T.dropWhileEnd (== '\'')
psc-ide-server/Main.hsnew file+135
@@ -0,0 +1,135 @@
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE MultiParamTypeClasses #-}
4+{-# LANGUAGE OverloadedStrings #-}
5+{-# LANGUAGE PackageImports #-}
6+{-# LANGUAGE TemplateHaskell #-}
7+module Main where
8+
9+import Prelude ()
10+import Prelude.Compat
11+
12+import Control.Concurrent (forkFinally)
13+import Control.Concurrent.STM
14+import Control.Exception (bracketOnError)
15+import Control.Monad
16+import "monad-logger" Control.Monad.Logger
17+import Control.Monad.Reader
18+import Control.Monad.Trans.Except
19+import qualified Data.Text as T
20+import qualified Data.Text.IO as T
21+import Data.Version (showVersion)
22+import Language.PureScript.Ide
23+import Language.PureScript.Ide.CodecJSON
24+import Language.PureScript.Ide.Error
25+import Language.PureScript.Ide.Types
26+import Language.PureScript.Ide.Watcher
27+import Network hiding (socketPort)
28+import Network.BSD (getProtocolNumber)
29+import Network.Socket hiding (PortNumber, Type,
30+ accept, sClose)
31+import Options.Applicative
32+import System.Directory
33+import System.FilePath
34+import System.IO
35+
36+import qualified Paths_purescript as Paths
37+
38+-- "Borrowed" from the Idris Compiler
39+-- Copied from upstream impl of listenOn
40+-- bound to localhost interface instead of iNADDR_ANY
41+listenOnLocalhost :: PortID -> IO Socket
42+listenOnLocalhost (PortNumber port) = do
43+ proto <- getProtocolNumber "tcp"
44+ localhost <- inet_addr "127.0.0.1"
45+ bracketOnError
46+ (socket AF_INET Stream proto)
47+ sClose
48+ (\sock -> do
49+ setSocketOption sock ReuseAddr 1
50+ bindSocket sock (SockAddrInet port localhost)
51+ listen sock maxListenQueue
52+ pure sock)
53+listenOnLocalhost _ = error "Wrong Porttype"
54+
55+data Options = Options
56+ { optionsDirectory :: Maybe FilePath
57+ , optionsOutputPath :: FilePath
58+ , optionsPort :: PortID
59+ , optionsDebug :: Bool
60+ }
61+
62+main :: IO ()
63+main = do
64+ Options dir outputPath port debug <- execParser opts
65+ maybe (pure ()) setCurrentDirectory dir
66+ serverState <- newTVarIO emptyPscIdeState
67+ cwd <- getCurrentDirectory
68+ _ <- forkFinally (watcher serverState (cwd </> outputPath)) print
69+ let conf =
70+ Configuration
71+ {
72+ confDebug = debug
73+ , confOutputPath = outputPath
74+ }
75+ let env =
76+ PscIdeEnvironment
77+ {
78+ envStateVar = serverState
79+ , envConfiguration = conf
80+ }
81+ startServer port env
82+ where
83+ parser =
84+ Options <$>
85+ optional (strOption (long "directory" <> short 'd')) <*>
86+ strOption (long "output-directory" <> value "output/") <*>
87+ (PortNumber . fromIntegral <$>
88+ option auto (long "port" <> short 'p' <> value (4242 :: Integer))) <*>
89+ switch (long "debug")
90+ opts = info (version <*> parser) mempty
91+ version = abortOption
92+ (InfoMsg (showVersion Paths.version))
93+ (long "version" <> help "Show the version number")
94+
95+startServer :: PortID -> PscIdeEnvironment -> IO ()
96+startServer port env = withSocketsDo $ do
97+ sock <- listenOnLocalhost port
98+ runLogger (runReaderT (forever (loop sock)) env)
99+ where
100+ runLogger = runStdoutLoggingT . filterLogger (\_ _ -> confDebug (envConfiguration env))
101+
102+ loop :: (PscIde m, MonadLogger m) => Socket -> m ()
103+ loop sock = do
104+ (cmd,h) <- acceptCommand sock
105+ case decodeT cmd of
106+ Just cmd' -> do
107+ result <- runExceptT (handleCommand cmd')
108+ $(logDebug) ("Answer was: " <> T.pack (show result))
109+ liftIO (hFlush stdout)
110+ case result of
111+ -- What function can I use to clean this up?
112+ Right r -> liftIO $ T.hPutStrLn h (encodeT r)
113+ Left err -> liftIO $ T.hPutStrLn h (encodeT err)
114+ Nothing -> do
115+ $(logDebug) ("Parsing the command failed. Command: " <> cmd)
116+ liftIO $ do
117+ T.hPutStrLn h (encodeT (GeneralError "Error parsing Command."))
118+ hFlush stdout
119+ liftIO (hClose h)
120+
121+
122+acceptCommand :: (Applicative m, MonadIO m, MonadLogger m)
123+ => Socket -> m (T.Text, Handle)
124+acceptCommand sock = do
125+ h <- acceptConnection
126+ $(logDebug) "Accepted a connection"
127+ cmd <- liftIO (T.hGetLine h)
128+ $(logDebug) cmd
129+ pure (cmd, h)
130+ where
131+ acceptConnection = liftIO $ do
132+ (h,_,_) <- accept sock
133+ hSetEncoding h utf8
134+ hSetBuffering h LineBuffering
135+ pure h
psc-ide-server/PROTOCOL.mdnew file+409
@@ -0,0 +1,409 @@
1+# Protocol
2+
3+Encode the following JSON formats into a single line string and pass them to
4+`psc-ide-client`s stdin. You can then read the result from `psc-ide-client`s
5+stdout as a single line. The result needs to be unwrapped from the "wrapper"
6+which separates success from failure. This wrapper is described at the end of
7+this document.
8+
9+## Command:
10+### Load
11+The `load` command "loads" the requested modules into the server
12+for completion and type info.
13+
14+**Params:**
15+ - `modules :: (optional) [ModuleName]`: A list of modules to load.
16+ psc-ide-server will try to parse all the declarations in these modules
17+ - `dependencies :: (optional) [ModuleName]`: A list of modules to load
18+ including their dependencies. In contrast to the `module` field, all the
19+ imports in these Modules will also be loaded.
20+
21+```json
22+{
23+ "command": "load",
24+ "params": {
25+ "modules": (optional)["Module.Name1", "Module.Name2"],
26+ "dependencies": (optional)["Module.Name3"]
27+ }
28+}
29+```
30+
31+**Result:**
32+
33+The Load Command returns a string.
34+
35+### Type
36+The `type` command looks up the type for a given identifier.
37+
38+**Params:**
39+ - `search :: String`: The identifier to look for. Only matches on equality.
40+ - `filters :: [Filter]`: These filters will be applied before looking for the
41+ identifier. These filters get combined with *AND*, so a candidate must match *ALL*
42+ of them to be eligible.
43+```json
44+{
45+ "command": "type",
46+ "params": {
47+ "search": "filterM",
48+ "filters": [Filter]
49+ }
50+}
51+```
52+
53+**Result:**
54+The possible types are returned in the same format as completions
55+
56+### Complete
57+The `complete` command looks up possible completions/corrections.
58+
59+**Params**:
60+ - `filters :: [Filter]`: The same as for the `type` command. A candidate must match
61+ all filters.
62+ - `matcher :: (optional) Matcher`: The strategy used for matching candidates after filtering.
63+ Results are scored internally and will be returned in the descending order where
64+ the nth element is better then the n+1-th.
65+
66+ If no matcher is given every candidate, that passes the filters, is returned in no
67+ particular order.
68+```json
69+{
70+ "command": "complete",
71+ "params": {
72+ "filters": [Filter],
73+ "matcher": (optional) Matcher
74+ }
75+}
76+```
77+
78+**Result:**
79+
80+The following format is returned as the Result:
81+
82+```json
83+[
84+ {
85+ "module": "Data.Array",
86+ "identifier": "filter",
87+ "type": "forall a. (a -> Boolean) -> Array a -> Array a"
88+ }
89+]
90+```
91+
92+
93+### CaseSplit
94+
95+The CaseSplit command takes a line of source code, an area in that line of code
96+and replaces it with all patterns for a given type. The parameter `annotations`
97+is used to turn type annotations on or off for the constructor fields.
98+
99+```json
100+{
101+ "command": "caseSplit",
102+ "params": {
103+ "line": "elem a as",
104+ "begin": 8,
105+ "end": 10,
106+ "annotations": true,
107+ "type": "List"
108+ }
109+}
110+```
111+
112+**Result:**
113+
114+The following format is returned as the Result:
115+
116+```json
117+[
118+ "elem a Nil",
119+ "elem a (Cons (_ :: a) (_ :: List a))"
120+]
121+```
122+You should then be able to replace the affected line of code in the editor with the new suggestions.
123+
124+### Add Clause
125+
126+The AddClause command takes a typedeclaration and generates a function template for the given type.
127+The `annotations` option turns type annotations on or off for the function arguments.
128+
129+```json
130+{
131+ "command": "addClause",
132+ "params": {
133+ "line": "elem :: forall a. (Eq a) => a -> List a",
134+ "annotations": true
135+ }
136+}
137+```
138+
139+**Result:**
140+
141+The following format is returned as the Result:
142+
143+```json
144+[
145+ "elem :: forall a. (Eq a) => a -> List a",
146+ "elem ( _ :: a) = ?elem"
147+]
148+```
149+You should then be able to replace the affected line of code in the editor with the new suggestions.
150+
151+### Pursuit
152+The `pursuit` command looks up the packages/completions for a given identifier from Pursuit.
153+
154+**Params:**
155+ - `query :: String`: With `type: "package"` this should be a module name. With
156+ `type: "completion"` this can be any string to look up.
157+ - `type :: String`: Takes the following values:
158+ - `package`: Looks for packages that contain the given module name.
159+ - `completion` Looks for declarations for the query from Pursuit.
160+
161+```json
162+{
163+ "command": "pursuit",
164+ "params": {
165+ "query": "Data.Array",
166+ "type": "package"
167+ }
168+}
169+```
170+
171+**Result:**
172+
173+`package` returns:
174+
175+```json
176+[
177+ {
178+ "module": "Module1.Name",
179+ "package": "purescript-packagename"
180+ }
181+]
182+```
183+
184+`completion` returns:
185+
186+```json
187+[
188+ {
189+ "module": "Data.Array",
190+ "identifier": "filter",
191+ "type": "forall a. (a -> Boolean) -> Array a -> Array a",
192+ "package": "purescript-arrays"
193+ }
194+]
195+```
196+
197+### List
198+
199+#### Loaded Modules
200+
201+`list` of type `loadedModules` lists all loaded modules (This means they can be searched for completions etc)
202+
203+```json
204+{
205+ "command": "list",
206+ "params": {
207+ "type": "loadedModules"
208+ }
209+}
210+```
211+
212+#### Response:
213+
214+The list loadedModules command returns a list of strings.
215+
216+#### Available Modules
217+
218+`list` of type `availableModules` lists all available modules. (This basically
219+means the contents of the `output/` folder.))
220+
221+```json
222+{
223+ "command": "list",
224+ "params": {
225+ "type": "availableModules"
226+ }
227+}
228+```
229+
230+#### Response:
231+
232+The list availableModules command returns a list of strings.
233+
234+#### Imports
235+
236+The list commmand can also list the imports for a given file.
237+
238+```json
239+{
240+ "command": "list",
241+ "params": {
242+ "type": "import",
243+ "file": "/home/kritzcreek/Documents/psc-ide/examples/Main.purs"
244+ }
245+}
246+```
247+
248+#### Response:
249+
250+The list import command returns a list of imports where imports are of the following form:
251+
252+Implicit Import(`import Data.Array`):
253+```json
254+[
255+ {
256+ "module": "Data.Array",
257+ "importType": "implicit"
258+ }
259+]
260+```
261+
262+Implicit qualified Import(`import qualified Data.Array as A`):
263+```json
264+[
265+ {
266+ "module": "Data.Array",
267+ "importType": "implicit",
268+ "qualifier": "A"
269+ }
270+]
271+```
272+
273+Explicit Import(`import Data.Array (filter, filterM, join)`):
274+```json
275+[
276+ {
277+ "module": "Data.Array",
278+ "importType": "explicit",
279+ "identifiers": ["filter", "filterM", "join"]
280+ }
281+]
282+```
283+
284+Hiding Import(`import Data.Array hiding (filter, filterM, join)`):
285+```json
286+[
287+ {
288+ "module": "Data.Array",
289+ "importType": "hiding",
290+ "identifiers": ["filter", "filterM", "join"]
291+ }
292+]
293+```
294+### Cwd/Quit
295+`cwd` returns the working directory of the server(should be your project root).
296+
297+`quit` quits the server.
298+
299+```json
300+{
301+ "command": "cwd|quit"
302+}
303+```
304+
305+**Result:**
306+These commands return strings.
307+
308+## Filter:
309+
310+### Exact filter
311+The Exact filter only keeps identifiers that are equal to the search term.
312+
313+```json
314+{
315+ "filter": "exact",
316+ "params": {
317+ "search": "filterM"
318+ }
319+}
320+```
321+### Prefix filter
322+The Prefix filter keeps identifiers/modules/data declarations that
323+are prefixed by the search term.
324+
325+```json
326+{
327+ "filter": "prefix",
328+ "params": {
329+ "search": "filt"
330+ }
331+}
332+```
333+
334+### Module filter
335+The Module filter only keeps identifiers that appear in the listed modules.
336+
337+```json
338+{
339+ "filter": "modules",
340+ "params": {
341+ "modules": ["My.Module"]
342+ }
343+}
344+```
345+
346+### Dependency filter
347+The Dependency filter only keeps identifiers that appear in the listed modules
348+and in any of their dependencies/imports.
349+
350+```json
351+{
352+ "filter": "dependencies",
353+ "params": {
354+ "modules": ["My.Module"]
355+ }
356+}
357+```
358+
359+## Matcher:
360+
361+### Flex matcher
362+Matches any occurence of the search string with intersections
363+
364+The scoring measures how far the matches span the string, where
365+closer is better. The matches then get sorted with highest score first.
366+
367+Examples:
368+- flMa matches **fl**ex**Ma**tcher. Score: 14.28
369+- sons matches **so**rtCompletio**ns**. Score: 6.25
370+```json
371+
372+{
373+ "matcher": "flex",
374+ "params": {
375+ "search": "filt"
376+ }
377+}
378+```
379+
380+### Distance Matcher
381+
382+The Distance matcher is meant to provide corrections for typos. It calculates
383+the edit distance in between the search and the loaded identifiers.
384+
385+```json
386+{
387+ "matcher": "distance",
388+ "params": {
389+ "search": "dilterM",
390+ "maximumDistance": 3
391+ }
392+}
393+```
394+
395+## Responses
396+
397+All Responses are wrapped in the following format:
398+
399+```json
400+{
401+ "resultType": "success|error",
402+ "result": Result|Error
403+}
404+```
405+
406+### Error
407+
408+Errors at this point are merely Error strings. Newlines are escaped like `\n`
409+and should be taken care of by the editor-plugin.
psc-ide-server/README.mdnew file+40
@@ -0,0 +1,40 @@
1+psc-ide
2+===
3+
4+A tool which provides editor support for the PureScript programming language.
5+
6+## Editor Integration
7+* [@epost](https://github.com/epost) wrote a plugin to integrate psc-ide with Emacs at https://github.com/epost/psc-ide-emacs.
8+* Atom integration is available with https://github.com/nwolverson/atom-ide-purescript.
9+* Visual Studio Code integration is available with https://github.com/nwolverson/vscode-ide-purescript.
10+* Vim integration is available here: https://github.com/FrigoEU/psc-ide-vim.
11+
12+## Running the Server
13+Start the server by running the `psc-ide-server` executable.
14+It supports the following options:
15+
16+- `-p / --port` specify a port. Defaults to 4242
17+- `-d / --directory` specify the toplevel directory of your project. Defaults to
18+ the current directory
19+- `--output-directory`: Specify where to look for compiled output inside your
20+ project directory. Defaults to `output/`, relative to either the current
21+ directory or the directory specified by `-d`.
22+- `--debug`: Enables some logging meant for debugging
23+- `--version`: Output psc-ide version
24+
25+## Issuing queries
26+
27+After you started the server you can start issuing requests using
28+`psc-ide-client`. Make sure you start by loading the modules before you try to
29+query them.
30+
31+`psc-ide-server` expects the build externs.purs inside the `output/` folder of
32+your project after running `pulp build` or `psc-make` respectively.
33+
34+(If you changed the port of the server you can change the port for
35+`psc-ide-client` by using the -p option accordingly)
36+
37+## Protocol
38+
39+For documentation about the protocol have a look at:
40+[PROTOCOL.md](PROTOCOL.md)
psc/Main.hs+6
@@ -177,6 +177,11 @@ jsonErrors :: Parser Bool
177jsonErrors = switch $
177jsonErrors = switch $
178 long "json-errors"
178 long "json-errors"
179 <> help "Print errors to stderr as JSON"
179 <> help "Print errors to stderr as JSON"
180+sourceMaps :: Parser Bool
181+sourceMaps = switch $
182+ long "source-maps"
183+ <> help "Generate source maps"
184+
180
185
181options :: Parser P.Options
186options :: Parser P.Options
182options = P.Options <$> noTco
187options = P.Options <$> noTco
@@ -186,6 +191,7 @@ options = P.Options <$> noTco
186 <*> verboseErrors
191 <*> verboseErrors
187 <*> (not <$> comments)
192 <*> (not <$> comments)
188 <*> requirePath
193 <*> requirePath
194+ <*> sourceMaps
189
195
190pscMakeOptions :: Parser PSCMakeOptions
196pscMakeOptions :: Parser PSCMakeOptions
191pscMakeOptions = PSCMakeOptions <$> many inputFile
197pscMakeOptions = PSCMakeOptions <$> many inputFile
purescript.cabal+69−8
@@ -1,5 +1,5 @@
1name: purescript
1name: purescript
2−version: 0.8.0.0
2+version: 0.8.1.0
3cabal-version: >=1.8
3cabal-version: >=1.8
4build-type: Simple
4build-type: Simple
5license: MIT
5license: MIT
@@ -14,7 +14,8 @@ Homepage: 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+ Harry Garrood <harry@garrood.me>,
18+ Christoph Hegemann <christoph.hegemann1337@gmail.com>
18
19
19tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.1
20tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.1
20
21
@@ -25,15 +26,15 @@ extra-source-files: examples/passing/*.purs
25 , examples/docs/src/*.purs
26 , examples/docs/src/*.purs
26 , tests/support/setup.js
27 , tests/support/setup.js
27 , tests/support/package.json
28 , tests/support/package.json
29+ , tests/support/prelude/bower.json
30+ , tests/support/prelude/src/*.purs
31+ , tests/support/prelude/src/*.js
32+ , tests/support/prelude/LICENSE
28 , tests/support/bower.json
33 , tests/support/bower.json
29 , tests/support/setup-win.cmd
34 , tests/support/setup-win.cmd
30 , tests/support/flattened/*.purs
35 , tests/support/flattened/*.purs
31 , tests/support/flattened/*.js
36 , tests/support/flattened/*.js
32 , tests/support/psci/*.purs
37 , tests/support/psci/*.purs
33− , tests/support/prelude/bower.json
34− , tests/support/prelude/src/*.purs
35− , tests/support/prelude/src/*.js
36− , tests/support/prelude/LICENSE
37 , stack.yaml
38 , stack.yaml
38 , stack-lts-2.yaml
39 , stack-lts-2.yaml
39 , stack-lts-3.yaml
40 , stack-lts-3.yaml
@@ -80,7 +81,16 @@ library
80 process >= 1.2.0 && < 1.5,
81 process >= 1.2.0 && < 1.5,
81 safe >= 0.3.9 && < 0.4,
82 safe >= 0.3.9 && < 0.4,
82 semigroups >= 0.16.2 && < 0.19,
83 semigroups >= 0.16.2 && < 0.19,
83− parallel >= 3.2 && < 3.3
84+ parallel >= 3.2 && < 3.3,
85+ sourcemap >= 0.1.6,
86+ stm >= 0.2.4.0,
87+ regex-tdfa -any,
88+ edit-distance -any,
89+ fsnotify >= 0.2.1,
90+ monad-logger >= 0.3 && < 0.4,
91+ pipes >= 4.0.0 && < 4.2.0 ,
92+ pipes-http -any,
93+ http-types -any
84
94
85 exposed-modules: Language.PureScript
95 exposed-modules: Language.PureScript
86 Language.PureScript.AST
96 Language.PureScript.AST
@@ -203,6 +213,22 @@ library
203 Language.PureScript.Publish.ErrorsWarnings
213 Language.PureScript.Publish.ErrorsWarnings
204 Language.PureScript.Publish.BoxesHelpers
214 Language.PureScript.Publish.BoxesHelpers
205
215
216+ Language.PureScript.Ide
217+ Language.PureScript.Ide.Command
218+ Language.PureScript.Ide.Externs
219+ Language.PureScript.Ide.Error
220+ Language.PureScript.Ide.CodecJSON
221+ Language.PureScript.Ide.Pursuit
222+ Language.PureScript.Ide.Completion
223+ Language.PureScript.Ide.Matcher
224+ Language.PureScript.Ide.Filter
225+ Language.PureScript.Ide.Types
226+ Language.PureScript.Ide.State
227+ Language.PureScript.Ide.CaseSplit
228+ Language.PureScript.Ide.SourceFile
229+ Language.PureScript.Ide.Watcher
230+ Language.PureScript.Ide.Reexports
231+
206 Control.Monad.Logger
232 Control.Monad.Logger
207 Control.Monad.Supply
233 Control.Monad.Supply
208 Control.Monad.Supply.Class
234 Control.Monad.Supply.Class
@@ -301,6 +327,39 @@ executable psc-bundle
301 ghc-options: -Wall -O2
327 ghc-options: -Wall -O2
302 hs-source-dirs: psc-bundle
328 hs-source-dirs: psc-bundle
303
329
330+executable psc-ide-server
331+ main-is: Main.hs
332+ other-modules:
333+ other-extensions:
334+ build-depends: base >=4 && <5
335+ , purescript -any
336+ , directory -any
337+ , filepath -any
338+ , monad-logger -any
339+ , mtl -any
340+ , transformers -any
341+ , transformers-compat -any
342+ , network -any
343+ , optparse-applicative >= 0.10.0
344+ , stm -any
345+ , text -any
346+ , base-compat >=0.6.0
347+ ghc-options: -Wall -O2 -threaded
348+ hs-source-dirs: psc-ide-server
349+
350+executable psc-ide-client
351+ main-is: Main.hs
352+ other-modules:
353+ other-extensions:
354+ build-depends: base >=4 && <5
355+ , mtl -any
356+ , text -any
357+ , optparse-applicative >= 0.10.0
358+ , network -any
359+ , base-compat >=0.6.0
360+ ghc-options: -Wall -O2
361+ hs-source-dirs: psc-ide-client
362+
304executable pcc
363executable pcc
305 build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
364 build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
306 file-embed >= 0.0.7 && < 0.0.8,
365 file-embed >= 0.0.7 && < 0.0.8,
@@ -319,7 +378,7 @@ test-suite tests
319 transformers -any, process -any, transformers-compat -any, time -any,
378 transformers -any, process -any, transformers-compat -any, time -any,
320 Glob -any, aeson-better-errors -any, bytestring -any, aeson -any,
379 Glob -any, aeson-better-errors -any, bytestring -any, aeson -any,
321 base-compat -any, haskeline >= 0.7.0.0, optparse-applicative -any,
380 base-compat -any, haskeline >= 0.7.0.0, optparse-applicative -any,
322− boxes -any, HUnit -any
381+ boxes -any, HUnit -any, hspec -any, hspec-discover -any, stm -any, text -any
323 ghc-options: -Wall
382 ghc-options: -Wall
324 type: exitcode-stdio-1.0
383 type: exitcode-stdio-1.0
325 main-is: Main.hs
384 main-is: Main.hs
@@ -328,6 +387,8 @@ test-suite tests
328 TestDocs
387 TestDocs
329 TestPscPublish
388 TestPscPublish
330 TestPsci
389 TestPsci
390+ TestPscIde
391+ PscIdeSpec
331 buildable: True
392 buildable: True
332 hs-source-dirs: tests psci
393 hs-source-dirs: tests psci
333
394
src/Language/PureScript/CodeGen/JS.hs+140−123
@@ -55,21 +55,21 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
55 rethrow (addHint (ErrorInModule mn)) $ do
55 rethrow (addHint (ErrorInModule mn)) $ do
56 let usedNames = concatMap getNames decls
56 let usedNames = concatMap getNames decls
57 let mnLookup = renameImports usedNames imps
57 let mnLookup = renameImports usedNames imps
58− jsImports <- T.traverse (importToJs mnLookup) . delete (ModuleName [ProperName C.prim]) . (\\ [mn]) $ imps
58+ jsImports <- T.traverse (importToJs mnLookup) . delete (ModuleName [ProperName C.prim]) . (\\ [mn]) $ map snd $ imps
59 let decls' = renameModules mnLookup decls
59 let decls' = renameModules mnLookup decls
60 jsDecls <- mapM bindToJs decls'
60 jsDecls <- mapM bindToJs decls'
61 optimized <- T.traverse (T.traverse optimize) jsDecls
61 optimized <- T.traverse (T.traverse optimize) jsDecls
62 F.traverse_ (F.traverse_ checkIntegers) optimized
62 F.traverse_ (F.traverse_ checkIntegers) optimized
63 comments <- not <$> asks optionsNoComments
63 comments <- not <$> asks optionsNoComments
64− let strict = JSStringLiteral "use strict"
64+ let strict = JSStringLiteral Nothing "use strict"
65− let header = if comments && not (null coms) then JSComment coms strict else strict
65+ let header = if comments && not (null coms) then JSComment Nothing coms strict else strict
66− let foreign' = [JSVariableIntroduction "$foreign" foreign_ | not $ null foreigns || isNothing foreign_]
66+ let foreign' = [JSVariableIntroduction Nothing "$foreign" foreign_ | not $ null foreigns || isNothing foreign_]
67 let moduleBody = header : foreign' ++ jsImports ++ concat optimized
67 let moduleBody = header : foreign' ++ jsImports ++ concat optimized
68 let foreignExps = exps `intersect` (fst `map` foreigns)
68 let foreignExps = exps `intersect` (fst `map` foreigns)
69 let standardExps = exps \\ foreignExps
69 let standardExps = exps \\ foreignExps
70− let exps' = JSObjectLiteral $ map (runIdent &&& JSVar . identToJs) standardExps
70+ let exps' = JSObjectLiteral Nothing $ map (runIdent &&& (JSVar Nothing) . identToJs) standardExps
71 ++ map (runIdent &&& foreignIdent) foreignExps
71 ++ map (runIdent &&& foreignIdent) foreignExps
72− return $ moduleBody ++ [JSAssignment (JSAccessor "exports" (JSVar "module")) exps']
72+ return $ moduleBody ++ [JSAssignment Nothing (JSAccessor Nothing "exports" (JSVar Nothing "module")) exps']
73
73
74 where
74 where
75
75
@@ -77,23 +77,23 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
77 -- Extracts all declaration names from a binding group.
77 -- Extracts all declaration names from a binding group.
78 --
78 --
79 getNames :: Bind Ann -> [Ident]
79 getNames :: Bind Ann -> [Ident]
80− getNames (NonRec ident _) = [ident]
80+ getNames (NonRec _ ident _) = [ident]
81− getNames (Rec vals) = map fst vals
81+ getNames (Rec vals) = map (snd . fst) vals
82
82
83 -- |
83 -- |
84 -- Creates alternative names for each module to ensure they don't collide
84 -- Creates alternative names for each module to ensure they don't collide
85 -- with declaration names.
85 -- with declaration names.
86 --
86 --
87− renameImports :: [Ident] -> [ModuleName] -> M.Map ModuleName ModuleName
87+ renameImports :: [Ident] -> [(Ann, ModuleName)] -> M.Map ModuleName (Ann, ModuleName)
88 renameImports ids mns = go M.empty ids mns
88 renameImports ids mns = go M.empty ids mns
89 where
89 where
90− go :: M.Map ModuleName ModuleName -> [Ident] -> [ModuleName] -> M.Map ModuleName ModuleName
90+ go :: M.Map ModuleName (Ann, ModuleName) -> [Ident] -> [(Ann, ModuleName)] -> M.Map ModuleName (Ann, ModuleName)
91− go acc used (mn' : mns') =
91+ go acc used ((ann, mn') : mns') =
92 let mni = Ident $ runModuleName mn'
92 let mni = Ident $ runModuleName mn'
93 in if mn' /= mn && mni `elem` used
93 in if mn' /= mn && mni `elem` used
94 then let newName = freshModuleName 1 mn' used
94 then let newName = freshModuleName 1 mn' used
95− in go (M.insert mn' newName acc) (Ident (runModuleName newName) : used) mns'
95+ in go (M.insert mn' (ann, newName) acc) (Ident (runModuleName newName) : used) mns'
96− else go (M.insert mn' mn' acc) (mni : used) mns'
96+ else go (M.insert mn' (ann, mn') acc) (mni : used) mns'
97 go acc _ [] = acc
97 go acc _ [] = acc
98
98
99 freshModuleName :: Integer -> ModuleName -> [Ident] -> ModuleName
99 freshModuleName :: Integer -> ModuleName -> [Ident] -> ModuleName
@@ -107,18 +107,18 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
107 -- Generates Javascript code for a module import, binding the required module
107 -- Generates Javascript code for a module import, binding the required module
108 -- to the alternative
108 -- to the alternative
109 --
109 --
110− importToJs :: M.Map ModuleName ModuleName -> ModuleName -> m JS
110+ importToJs :: M.Map ModuleName (Ann, ModuleName) -> ModuleName -> m JS
111 importToJs mnLookup mn' = do
111 importToJs mnLookup mn' = do
112 path <- asks optionsRequirePath
112 path <- asks optionsRequirePath
113− let mnSafe = fromMaybe (internalError "Missing value in mnLookup") $ M.lookup mn' mnLookup
113+ let ((ss, _, _, _), mnSafe) = fromMaybe (internalError "Missing value in mnLookup") $ M.lookup mn' mnLookup
114− let moduleBody = JSApp (JSVar "require") [JSStringLiteral (maybe id (</>) path $ runModuleName mn')]
114+ let moduleBody = JSApp Nothing (JSVar Nothing "require") [JSStringLiteral Nothing (maybe id (</>) path $ runModuleName mn')]
115− return $ JSVariableIntroduction (moduleNameToJs mnSafe) (Just moduleBody)
115+ withPos ss $ JSVariableIntroduction Nothing (moduleNameToJs mnSafe) (Just moduleBody)
116
116
117 -- |
117 -- |
118 -- Replaces the `ModuleName`s in the AST so that the generated code refers to
118 -- Replaces the `ModuleName`s in the AST so that the generated code refers to
119 -- the collision-avoiding renamed module imports.
119 -- the collision-avoiding renamed module imports.
120 --
120 --
121− renameModules :: M.Map ModuleName ModuleName -> [Bind Ann] -> [Bind Ann]
121+ renameModules :: M.Map ModuleName (Ann, ModuleName) -> [Bind Ann] -> [Bind Ann]
122 renameModules mnLookup binds =
122 renameModules mnLookup binds =
123 let (f, _, _) = everywhereOnValues id goExpr goBinder
123 let (f, _, _) = everywhereOnValues id goExpr goBinder
124 in map f binds
124 in map f binds
@@ -131,7 +131,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
131 goBinder b = b
131 goBinder b = b
132 renameQual :: Qualified a -> Qualified a
132 renameQual :: Qualified a -> Qualified a
133 renameQual (Qualified (Just mn') a) =
133 renameQual (Qualified (Just mn') a) =
134− let mnSafe = fromMaybe (internalError "Missing value in mnLookup") $ M.lookup mn' mnLookup
134+ let (_,mnSafe) = fromMaybe (internalError "Missing value in mnLookup") $ M.lookup mn' mnLookup
135 in Qualified (Just mnSafe) a
135 in Qualified (Just mnSafe) a
136 renameQual q = q
136 renameQual q = q
137
137
@@ -139,8 +139,8 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
139 -- Generate code in the simplified Javascript intermediate representation for a declaration
139 -- Generate code in the simplified Javascript intermediate representation for a declaration
140 --
140 --
141 bindToJs :: Bind Ann -> m [JS]
141 bindToJs :: Bind Ann -> m [JS]
142− bindToJs (NonRec ident val) = return <$> nonRecToJS ident val
142+ bindToJs (NonRec ann ident val) = return <$> nonRecToJS ann ident val
143− bindToJs (Rec vals) = forM vals (uncurry nonRecToJS)
143+ bindToJs (Rec vals) = forM vals (uncurry . uncurry $ nonRecToJS)
144
144
145 -- |
145 -- |
146 -- Generate code in the simplified Javascript intermediate representation for a single non-recursive
146 -- Generate code in the simplified Javascript intermediate representation for a single non-recursive
@@ -148,22 +148,30 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
148 --
148 --
149 -- The main purpose of this function is to handle code generation for comments.
149 -- The main purpose of this function is to handle code generation for comments.
150 --
150 --
151− nonRecToJS :: Ident -> Expr Ann -> m JS
151+ nonRecToJS :: Ann -> Ident -> Expr Ann -> m JS
152− nonRecToJS i e@(extractAnn -> (_, com, _, _)) | not (null com) = do
152+ nonRecToJS a i e@(extractAnn -> (_, com, _, _)) | not (null com) = do
153 withoutComment <- asks optionsNoComments
153 withoutComment <- asks optionsNoComments
154 if withoutComment
154 if withoutComment
155− then nonRecToJS i (modifyAnn removeComments e)
155+ then nonRecToJS a i (modifyAnn removeComments e)
156− else JSComment com <$> nonRecToJS i (modifyAnn removeComments e)
156+ else JSComment Nothing com <$> nonRecToJS a i (modifyAnn removeComments e)
157− nonRecToJS ident val = do
157+ nonRecToJS (ss, _, _, _) ident val = do
158 js <- valueToJs val
158 js <- valueToJs val
159− return $ JSVariableIntroduction (identToJs ident) (Just js)
159+ withPos ss $ JSVariableIntroduction Nothing (identToJs ident) (Just js)
160+
161+ withPos :: Maybe SourceSpan -> JS -> m JS
162+ withPos (Just ss) js = do
163+ withSM <- asks optionsSourceMaps
164+ return $ if withSM
165+ then withSourceSpan ss js
166+ else js
167+ withPos Nothing js = return js
160
168
161 -- |
169 -- |
162 -- Generate code in the simplified Javascript intermediate representation for a variable based on a
170 -- Generate code in the simplified Javascript intermediate representation for a variable based on a
163 -- PureScript identifier.
171 -- PureScript identifier.
164 --
172 --
165 var :: Ident -> JS
173 var :: Ident -> JS
166− var = JSVar . identToJs
174+ var = JSVar Nothing . identToJs
167
175
168 -- |
176 -- |
169 -- Generate code in the simplified Javascript intermediate representation for an accessor based on
177 -- Generate code in the simplified Javascript intermediate representation for an accessor based on
@@ -172,102 +180,106 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
172 --
180 --
173 accessor :: Ident -> JS -> JS
181 accessor :: Ident -> JS -> JS
174 accessor (Ident prop) = accessorString prop
182 accessor (Ident prop) = accessorString prop
175− accessor (Op op) = JSIndexer (JSStringLiteral op)
183+ accessor (Op op) = JSIndexer Nothing (JSStringLiteral Nothing op)
176 accessor (GenIdent _ _) = internalError "GenIdent in accessor"
184 accessor (GenIdent _ _) = internalError "GenIdent in accessor"
177
185
178 accessorString :: String -> JS -> JS
186 accessorString :: String -> JS -> JS
179− accessorString prop | identNeedsEscaping prop = JSIndexer (JSStringLiteral prop)
187+ accessorString prop | identNeedsEscaping prop = JSIndexer Nothing (JSStringLiteral Nothing prop)
180− | otherwise = JSAccessor prop
188+ | otherwise = JSAccessor Nothing prop
181
189
182 -- |
190 -- |
183 -- Generate code in the simplified Javascript intermediate representation for a value or expression.
191 -- Generate code in the simplified Javascript intermediate representation for a value or expression.
184 --
192 --
185 valueToJs :: Expr Ann -> m JS
193 valueToJs :: Expr Ann -> m JS
194+ valueToJs e =
195+ let (ss, _, _, _) = extractAnn e in
196+ withPos ss =<< valueToJs' e
197+
198+ valueToJs' :: Expr Ann -> m JS
186− valueToJs (Literal (pos, _, _, _) l) =
199+ valueToJs' (Literal (pos, _, _, _) l) =
187 maybe id rethrowWithPosition pos $ literalToValueJS l
200 maybe id rethrowWithPosition pos $ literalToValueJS l
188− valueToJs (Var (_, _, _, Just (IsConstructor _ [])) name) =
201+ valueToJs' (Var (_, _, _, Just (IsConstructor _ [])) name) =
189− return $ JSAccessor "value" $ qualifiedToJS id name
202+ return $ JSAccessor Nothing "value" $ qualifiedToJS id name
190− valueToJs (Var (_, _, _, Just (IsConstructor _ _)) name) =
203+ valueToJs' (Var (_, _, _, Just (IsConstructor _ _)) name) =
191− return $ JSAccessor "create" $ qualifiedToJS id name
204+ return $ JSAccessor Nothing "create" $ qualifiedToJS id name
192− valueToJs (Accessor _ prop val) =
205+ valueToJs' (Accessor _ prop val) =
193 accessorString prop <$> valueToJs val
206 accessorString prop <$> valueToJs val
194− valueToJs (ObjectUpdate _ o ps) = do
207+ valueToJs' (ObjectUpdate _ o ps) = do
195 obj <- valueToJs o
208 obj <- valueToJs o
196 sts <- mapM (sndM valueToJs) ps
209 sts <- mapM (sndM valueToJs) ps
197 extendObj obj sts
210 extendObj obj sts
198− valueToJs e@(Abs (_, _, _, Just IsTypeClassConstructor) _ _) =
211+ valueToJs' e@(Abs (_, _, _, Just IsTypeClassConstructor) _ _) =
199 let args = unAbs e
212 let args = unAbs e
200− in return $ JSFunction Nothing (map identToJs args) (JSBlock $ map assign args)
213+ in return $ JSFunction Nothing Nothing (map identToJs args) (JSBlock Nothing $ map assign args)
201 where
214 where
202 unAbs :: Expr Ann -> [Ident]
215 unAbs :: Expr Ann -> [Ident]
203 unAbs (Abs _ arg val) = arg : unAbs val
216 unAbs (Abs _ arg val) = arg : unAbs val
204 unAbs _ = []
217 unAbs _ = []
205 assign :: Ident -> JS
218 assign :: Ident -> JS
206− assign name = JSAssignment (accessorString (runIdent name) (JSVar "this"))
219+ assign name = JSAssignment Nothing (accessorString (runIdent name) (JSVar Nothing "this"))
207 (var name)
220 (var name)
208− valueToJs (Abs _ arg val) = do
221+ valueToJs' (Abs _ arg val) = do
209 ret <- valueToJs val
222 ret <- valueToJs val
210− return $ JSFunction Nothing [identToJs arg] (JSBlock [JSReturn ret])
223+ return $ JSFunction Nothing Nothing [identToJs arg] (JSBlock Nothing [JSReturn Nothing ret])
211− valueToJs e@App{} = do
224+ valueToJs' e@App{} = do
212 let (f, args) = unApp e []
225 let (f, args) = unApp e []
213 args' <- mapM valueToJs args
226 args' <- mapM valueToJs args
214 case f of
227 case f of
215 Var (_, _, _, Just IsNewtype) _ -> return (head args')
228 Var (_, _, _, Just IsNewtype) _ -> return (head args')
216 Var (_, _, _, Just (IsConstructor _ fields)) name | length args == length fields ->
229 Var (_, _, _, Just (IsConstructor _ fields)) name | length args == length fields ->
217− return $ JSUnary JSNew $ JSApp (qualifiedToJS id name) args'
230+ return $ JSUnary Nothing JSNew $ JSApp Nothing (qualifiedToJS id name) args'
218 Var (_, _, _, Just IsTypeClassConstructor) name ->
231 Var (_, _, _, Just IsTypeClassConstructor) name ->
219− return $ JSUnary JSNew $ JSApp (qualifiedToJS id name) args'
232+ return $ JSUnary Nothing JSNew $ JSApp Nothing (qualifiedToJS id name) args'
220− _ -> flip (foldl (\fn a -> JSApp fn [a])) args' <$> valueToJs f
233+ _ -> flip (foldl (\fn a -> JSApp Nothing fn [a])) args' <$> valueToJs f
221 where
234 where
222 unApp :: Expr Ann -> [Expr Ann] -> (Expr Ann, [Expr Ann])
235 unApp :: Expr Ann -> [Expr Ann] -> (Expr Ann, [Expr Ann])
223 unApp (App _ val arg) args = unApp val (arg : args)
236 unApp (App _ val arg) args = unApp val (arg : args)
224 unApp other args = (other, args)
237 unApp other args = (other, args)
225− valueToJs (Var (_, _, _, Just IsForeign) qi@(Qualified (Just mn') ident)) =
238+ valueToJs' (Var (_, _, _, Just IsForeign) qi@(Qualified (Just mn') ident)) =
226 return $ if mn' == mn
239 return $ if mn' == mn
227 then foreignIdent ident
240 then foreignIdent ident
228 else varToJs qi
241 else varToJs qi
229− valueToJs (Var (_, _, _, Just IsForeign) ident) =
242+ valueToJs' (Var (_, _, _, Just IsForeign) ident) =
230 error $ "Encountered an unqualified reference to a foreign ident " ++ showQualified showIdent ident
243 error $ "Encountered an unqualified reference to a foreign ident " ++ showQualified showIdent ident
231− valueToJs (Var _ ident) =
244+ valueToJs' (Var _ ident) = return $ varToJs ident
232− return $ varToJs ident
233− valueToJs (Case (maybeSpan, _, _, _) values binders) = do
245+ valueToJs' (Case (maybeSpan, _, _, _) values binders) = do
234 vals <- mapM valueToJs values
246 vals <- mapM valueToJs values
235 bindersToJs maybeSpan binders vals
247 bindersToJs maybeSpan binders vals
236− valueToJs (Let _ ds val) = do
248+ valueToJs' (Let _ ds val) = do
237 ds' <- concat <$> mapM bindToJs ds
249 ds' <- concat <$> mapM bindToJs ds
238 ret <- valueToJs val
250 ret <- valueToJs val
239− return $ JSApp (JSFunction Nothing [] (JSBlock (ds' ++ [JSReturn ret]))) []
251+ return $ JSApp Nothing (JSFunction Nothing Nothing [] (JSBlock Nothing (ds' ++ [JSReturn Nothing ret]))) []
240− valueToJs (Constructor (_, _, _, Just IsNewtype) _ (ProperName ctor) _) =
252+ valueToJs' (Constructor (_, _, _, Just IsNewtype) _ (ProperName ctor) _) =
241− return $ JSVariableIntroduction ctor (Just $
253+ return $ JSVariableIntroduction Nothing ctor (Just $
242− JSObjectLiteral [("create",
254+ JSObjectLiteral Nothing [("create",
243− JSFunction Nothing ["value"]
255+ JSFunction Nothing Nothing ["value"]
244− (JSBlock [JSReturn $ JSVar "value"]))])
256+ (JSBlock Nothing [JSReturn Nothing $ JSVar Nothing "value"]))])
245− valueToJs (Constructor _ _ (ProperName ctor) []) =
257+ valueToJs' (Constructor _ _ (ProperName ctor) []) =
246− return $ iife ctor [ JSFunction (Just ctor) [] (JSBlock [])
258+ return $ iife ctor [ JSFunction Nothing (Just ctor) [] (JSBlock Nothing [])
247− , JSAssignment (JSAccessor "value" (JSVar ctor))
259+ , JSAssignment Nothing (JSAccessor Nothing "value" (JSVar Nothing ctor))
248− (JSUnary JSNew $ JSApp (JSVar ctor) []) ]
260+ (JSUnary Nothing JSNew $ JSApp Nothing (JSVar Nothing ctor) []) ]
249− valueToJs (Constructor _ _ (ProperName ctor) fields) =
261+ valueToJs' (Constructor _ _ (ProperName ctor) fields) =
250 let constructor =
262 let constructor =
251− let body = [ JSAssignment (JSAccessor (identToJs f) (JSVar "this")) (var f) | f <- fields ]
263+ let body = [ JSAssignment Nothing (JSAccessor Nothing (identToJs f) (JSVar Nothing "this")) (var f) | f <- fields ]
252− in JSFunction (Just ctor) (identToJs `map` fields) (JSBlock body)
264+ in JSFunction Nothing (Just ctor) (identToJs `map` fields) (JSBlock Nothing body)
253 createFn =
265 createFn =
254− let body = JSUnary JSNew $ JSApp (JSVar ctor) (var `map` fields)
266+ let body = JSUnary Nothing JSNew $ JSApp Nothing (JSVar Nothing ctor) (var `map` fields)
255− in foldr (\f inner -> JSFunction Nothing [identToJs f] (JSBlock [JSReturn inner])) body fields
267+ in foldr (\f inner -> JSFunction Nothing Nothing [identToJs f] (JSBlock Nothing [JSReturn Nothing inner])) body fields
256 in return $ iife ctor [ constructor
268 in return $ iife ctor [ constructor
257− , JSAssignment (JSAccessor "create" (JSVar ctor)) createFn
269+ , JSAssignment Nothing (JSAccessor Nothing "create" (JSVar Nothing ctor)) createFn
258 ]
270 ]
259
271
260 iife :: String -> [JS] -> JS
272 iife :: String -> [JS] -> JS
261− iife v exprs = JSApp (JSFunction Nothing [] (JSBlock $ exprs ++ [JSReturn $ JSVar v])) []
273+ iife v exprs = JSApp Nothing (JSFunction Nothing Nothing [] (JSBlock Nothing $ exprs ++ [JSReturn Nothing $ JSVar Nothing v])) []
262
274
263 literalToValueJS :: Literal (Expr Ann) -> m JS
275 literalToValueJS :: Literal (Expr Ann) -> m JS
264− literalToValueJS (NumericLiteral (Left i)) = return $ JSNumericLiteral (Left i)
276+ literalToValueJS (NumericLiteral (Left i)) = return $ JSNumericLiteral Nothing (Left i)
265− literalToValueJS (NumericLiteral (Right n)) = return $ JSNumericLiteral (Right n)
277+ literalToValueJS (NumericLiteral (Right n)) = return $ JSNumericLiteral Nothing (Right n)
266− literalToValueJS (StringLiteral s) = return $ JSStringLiteral s
278+ literalToValueJS (StringLiteral s) = return $ JSStringLiteral Nothing s
267− literalToValueJS (CharLiteral c) = return $ JSStringLiteral [c]
279+ literalToValueJS (CharLiteral c) = return $ JSStringLiteral Nothing [c]
268− literalToValueJS (BooleanLiteral b) = return $ JSBooleanLiteral b
280+ literalToValueJS (BooleanLiteral b) = return $ JSBooleanLiteral Nothing b
269− literalToValueJS (ArrayLiteral xs) = JSArrayLiteral <$> mapM valueToJs xs
281+ literalToValueJS (ArrayLiteral xs) = JSArrayLiteral Nothing <$> mapM valueToJs xs
270− literalToValueJS (ObjectLiteral ps) = JSObjectLiteral <$> mapM (sndM valueToJs) ps
282+ literalToValueJS (ObjectLiteral ps) = JSObjectLiteral Nothing <$> mapM (sndM valueToJs) ps
271
283
272 -- |
284 -- |
273 -- Shallow copy an object.
285 -- Shallow copy an object.
@@ -277,16 +289,16 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
277 newObj <- freshName
289 newObj <- freshName
278 key <- freshName
290 key <- freshName
279 let
291 let
280− jsKey = JSVar key
292+ jsKey = JSVar Nothing key
281− jsNewObj = JSVar newObj
293+ jsNewObj = JSVar Nothing newObj
282− block = JSBlock (objAssign:copy:extend ++ [JSReturn jsNewObj])
294+ block = JSBlock Nothing (objAssign:copy:extend ++ [JSReturn Nothing jsNewObj])
283− objAssign = JSVariableIntroduction newObj (Just $ JSObjectLiteral [])
295+ objAssign = JSVariableIntroduction Nothing newObj (Just $ JSObjectLiteral Nothing [])
284− copy = JSForIn key obj $ JSBlock [JSIfElse cond assign Nothing]
296+ copy = JSForIn Nothing key obj $ JSBlock Nothing [JSIfElse Nothing cond assign Nothing]
285− cond = JSApp (JSAccessor "hasOwnProperty" obj) [jsKey]
297+ cond = JSApp Nothing (JSAccessor Nothing "hasOwnProperty" obj) [jsKey]
286− assign = JSBlock [JSAssignment (JSIndexer jsKey jsNewObj) (JSIndexer jsKey obj)]
298+ assign = JSBlock Nothing [JSAssignment Nothing (JSIndexer Nothing jsKey jsNewObj) (JSIndexer Nothing jsKey obj)]
287− stToAssign (s, js) = JSAssignment (JSAccessor s jsNewObj) js
299+ stToAssign (s, js) = JSAssignment Nothing (JSAccessor Nothing s jsNewObj) js
288 extend = map stToAssign sts
300 extend = map stToAssign sts
289− return $ JSApp (JSFunction Nothing [] block) []
301+ return $ JSApp Nothing (JSFunction Nothing Nothing [] block) []
290
302
291 -- |
303 -- |
292 -- Generate code in the simplified Javascript intermediate representation for a reference to a
304 -- Generate code in the simplified Javascript intermediate representation for a reference to a
@@ -301,12 +313,12 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
301 -- variable that may have a qualified name.
313 -- variable that may have a qualified name.
302 --
314 --
303 qualifiedToJS :: (a -> Ident) -> Qualified a -> JS
315 qualifiedToJS :: (a -> Ident) -> Qualified a -> JS
304− qualifiedToJS f (Qualified (Just (ModuleName [ProperName mn'])) a) | mn' == C.prim = JSVar . runIdent $ f a
316+ qualifiedToJS f (Qualified (Just (ModuleName [ProperName mn'])) a) | mn' == C.prim = JSVar Nothing . runIdent $ f a
305− qualifiedToJS f (Qualified (Just mn') a) | mn /= mn' = accessor (f a) (JSVar (moduleNameToJs mn'))
317+ qualifiedToJS f (Qualified (Just mn') a) | mn /= mn' = accessor (f a) (JSVar Nothing (moduleNameToJs mn'))
306− qualifiedToJS f (Qualified _ a) = JSVar $ identToJs (f a)
318+ qualifiedToJS f (Qualified _ a) = JSVar Nothing $ identToJs (f a)
307
319
308 foreignIdent :: Ident -> JS
320 foreignIdent :: Ident -> JS
309− foreignIdent ident = accessorString (runIdent ident) (JSVar "$foreign")
321+ foreignIdent ident = accessorString (runIdent ident) (JSVar Nothing "$foreign")
310
322
311 -- |
323 -- |
312 -- Generate code in the simplified Javascript intermediate representation for pattern match binders
324 -- Generate code in the simplified Javascript intermediate representation for pattern match binders
@@ -315,11 +327,11 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
315 bindersToJs :: Maybe SourceSpan -> [CaseAlternative Ann] -> [JS] -> m JS
327 bindersToJs :: Maybe SourceSpan -> [CaseAlternative Ann] -> [JS] -> m JS
316 bindersToJs maybeSpan binders vals = do
328 bindersToJs maybeSpan binders vals = do
317 valNames <- replicateM (length vals) freshName
329 valNames <- replicateM (length vals) freshName
318− let assignments = zipWith JSVariableIntroduction valNames (map Just vals)
330+ let assignments = zipWith (JSVariableIntroduction Nothing) valNames (map Just vals)
319 jss <- forM binders $ \(CaseAlternative bs result) -> do
331 jss <- forM binders $ \(CaseAlternative bs result) -> do
320 ret <- guardsToJs result
332 ret <- guardsToJs result
321 go valNames ret bs
333 go valNames ret bs
322− return $ JSApp (JSFunction Nothing [] (JSBlock (assignments ++ concat jss ++ [JSThrow $ failedPatternError valNames])))
334+ return $ JSApp Nothing (JSFunction Nothing Nothing [] (JSBlock Nothing (assignments ++ concat jss ++ [JSThrow Nothing $ failedPatternError valNames])))
323 []
335 []
324 where
336 where
325 go :: [String] -> [JS] -> [Binder Ann] -> m [JS]
337 go :: [String] -> [JS] -> [Binder Ann] -> m [JS]
@@ -330,43 +342,48 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
330 go _ _ _ = internalError "Invalid arguments to bindersToJs"
342 go _ _ _ = internalError "Invalid arguments to bindersToJs"
331
343
332 failedPatternError :: [String] -> JS
344 failedPatternError :: [String] -> JS
333− failedPatternError names = JSUnary JSNew $ JSApp (JSVar "Error") [JSBinary Add (JSStringLiteral failedPatternMessage) (JSArrayLiteral $ zipWith valueError names vals)]
345+ failedPatternError names = JSUnary Nothing JSNew $ JSApp Nothing (JSVar Nothing "Error") [JSBinary Nothing Add (JSStringLiteral Nothing failedPatternMessage) (JSArrayLiteral Nothing $ zipWith valueError names vals)]
334
346
335 failedPatternMessage :: String
347 failedPatternMessage :: String
336 failedPatternMessage = "Failed pattern match" ++ maybe "" (((" at " ++ runModuleName mn ++ " ") ++) . displayStartEndPos) maybeSpan ++ ": "
348 failedPatternMessage = "Failed pattern match" ++ maybe "" (((" at " ++ runModuleName mn ++ " ") ++) . displayStartEndPos) maybeSpan ++ ": "
337
349
338 valueError :: String -> JS -> JS
350 valueError :: String -> JS -> JS
339− valueError _ l@(JSNumericLiteral _) = l
351+ valueError _ l@(JSNumericLiteral _ _) = l
340− valueError _ l@(JSStringLiteral _) = l
352+ valueError _ l@(JSStringLiteral _ _) = l
341− valueError _ l@(JSBooleanLiteral _) = l
353+ valueError _ l@(JSBooleanLiteral _ _) = l
342− valueError s _ = JSAccessor "name" . JSAccessor "constructor" $ JSVar s
354+ valueError s _ = JSAccessor Nothing "name" . JSAccessor Nothing "constructor" $ JSVar Nothing s
343
355
344 guardsToJs :: Either [(Guard Ann, Expr Ann)] (Expr Ann) -> m [JS]
356 guardsToJs :: Either [(Guard Ann, Expr Ann)] (Expr Ann) -> m [JS]
345 guardsToJs (Left gs) = forM gs $ \(cond, val) -> do
357 guardsToJs (Left gs) = forM gs $ \(cond, val) -> do
346 cond' <- valueToJs cond
358 cond' <- valueToJs cond
347 done <- valueToJs val
359 done <- valueToJs val
348− return $ JSIfElse cond' (JSBlock [JSReturn done]) Nothing
360+ return $ JSIfElse Nothing cond' (JSBlock Nothing [JSReturn Nothing done]) Nothing
349− guardsToJs (Right v) = return . JSReturn <$> valueToJs v
361+ guardsToJs (Right v) = return . JSReturn Nothing <$> valueToJs v
362+
363+ binderToJs :: String -> [JS] -> Binder Ann -> m [JS]
364+ binderToJs s done binder =
365+ let (ss, _, _, _) = extractBinderAnn binder in
366+ traverse (withPos ss) =<< binderToJs' s done binder
350
367
351 -- |
368 -- |
352 -- Generate code in the simplified Javascript intermediate representation for a pattern match
369 -- Generate code in the simplified Javascript intermediate representation for a pattern match
353 -- binder.
370 -- binder.
354 --
371 --
355− binderToJs :: String -> [JS] -> Binder Ann -> m [JS]
372+ binderToJs' :: String -> [JS] -> Binder Ann -> m [JS]
356− binderToJs _ done (NullBinder{}) = return done
373+ binderToJs' _ done (NullBinder{}) = return done
357− binderToJs varName done (LiteralBinder _ l) =
374+ binderToJs' varName done (LiteralBinder _ l) =
358 literalToBinderJS varName done l
375 literalToBinderJS varName done l
359− binderToJs varName done (VarBinder _ ident) =
376+ binderToJs' varName done (VarBinder _ ident) =
360− return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : done)
377+ return (JSVariableIntroduction Nothing (identToJs ident) (Just (JSVar Nothing varName)) : done)
361− binderToJs varName done (ConstructorBinder (_, _, _, Just IsNewtype) _ _ [b]) =
378+ binderToJs' varName done (ConstructorBinder (_, _, _, Just IsNewtype) _ _ [b]) =
362 binderToJs varName done b
379 binderToJs varName done b
363− binderToJs varName done (ConstructorBinder (_, _, _, Just (IsConstructor ctorType fields)) _ ctor bs) = do
380+ binderToJs' varName done (ConstructorBinder (_, _, _, Just (IsConstructor ctorType fields)) _ ctor bs) = do
364 js <- go (zip fields bs) done
381 js <- go (zip fields bs) done
365 return $ case ctorType of
382 return $ case ctorType of
366 ProductType -> js
383 ProductType -> js
367 SumType ->
384 SumType ->
368− [JSIfElse (JSInstanceOf (JSVar varName) (qualifiedToJS (Ident . runProperName) ctor))
385+ [JSIfElse Nothing (JSInstanceOf Nothing (JSVar Nothing varName) (qualifiedToJS (Ident . runProperName) ctor))
369− (JSBlock js)
386+ (JSBlock Nothing js)
370 Nothing]
387 Nothing]
371 where
388 where
372 go :: [(Ident, Binder Ann)] -> [JS] -> m [JS]
389 go :: [(Ident, Binder Ann)] -> [JS] -> m [JS]
@@ -375,24 +392,24 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
375 argVar <- freshName
392 argVar <- freshName
376 done'' <- go remain done'
393 done'' <- go remain done'
377 js <- binderToJs argVar done'' binder
394 js <- binderToJs argVar done'' binder
378− return (JSVariableIntroduction argVar (Just (JSAccessor (identToJs field) (JSVar varName))) : js)
395+ return (JSVariableIntroduction Nothing argVar (Just (JSAccessor Nothing (identToJs field) (JSVar Nothing varName))) : js)
379− binderToJs _ _ ConstructorBinder{} =
396+ binderToJs' _ _ ConstructorBinder{} =
380 internalError "binderToJs: Invalid ConstructorBinder in binderToJs"
397 internalError "binderToJs: Invalid ConstructorBinder in binderToJs"
381− binderToJs varName done (NamedBinder _ ident binder) = do
398+ binderToJs' varName done (NamedBinder _ ident binder) = do
382 js <- binderToJs varName done binder
399 js <- binderToJs varName done binder
383− return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : js)
400+ return (JSVariableIntroduction Nothing (identToJs ident) (Just (JSVar Nothing varName)) : js)
384
401
385 literalToBinderJS :: String -> [JS] -> Literal (Binder Ann) -> m [JS]
402 literalToBinderJS :: String -> [JS] -> Literal (Binder Ann) -> m [JS]
386 literalToBinderJS varName done (NumericLiteral num) =
403 literalToBinderJS varName done (NumericLiteral num) =
387− return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSNumericLiteral num)) (JSBlock done) Nothing]
404+ return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSNumericLiteral Nothing num)) (JSBlock Nothing done) Nothing]
388 literalToBinderJS varName done (CharLiteral c) =
405 literalToBinderJS varName done (CharLiteral c) =
389− return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSStringLiteral [c])) (JSBlock done) Nothing]
406+ return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSStringLiteral Nothing [c])) (JSBlock Nothing done) Nothing]
390 literalToBinderJS varName done (StringLiteral str) =
407 literalToBinderJS varName done (StringLiteral str) =
391− return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSStringLiteral str)) (JSBlock done) Nothing]
408+ return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSVar Nothing varName) (JSStringLiteral Nothing str)) (JSBlock Nothing done) Nothing]
392 literalToBinderJS varName done (BooleanLiteral True) =
409 literalToBinderJS varName done (BooleanLiteral True) =
393− return [JSIfElse (JSVar varName) (JSBlock done) Nothing]
410+ return [JSIfElse Nothing (JSVar Nothing varName) (JSBlock Nothing done) Nothing]
394 literalToBinderJS varName done (BooleanLiteral False) =
411 literalToBinderJS varName done (BooleanLiteral False) =
395− return [JSIfElse (JSUnary Not (JSVar varName)) (JSBlock done) Nothing]
412+ return [JSIfElse Nothing (JSUnary Nothing Not (JSVar Nothing varName)) (JSBlock Nothing done) Nothing]
396 literalToBinderJS varName done (ObjectLiteral bs) = go done bs
413 literalToBinderJS varName done (ObjectLiteral bs) = go done bs
397 where
414 where
398 go :: [JS] -> [(String, Binder Ann)] -> m [JS]
415 go :: [JS] -> [(String, Binder Ann)] -> m [JS]
@@ -401,10 +418,10 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
401 propVar <- freshName
418 propVar <- freshName
402 done'' <- go done' bs'
419 done'' <- go done' bs'
403 js <- binderToJs propVar done'' binder
420 js <- binderToJs propVar done'' binder
404− return (JSVariableIntroduction propVar (Just (accessorString prop (JSVar varName))) : js)
421+ return (JSVariableIntroduction Nothing propVar (Just (accessorString prop (JSVar Nothing varName))) : js)
405 literalToBinderJS varName done (ArrayLiteral bs) = do
422 literalToBinderJS varName done (ArrayLiteral bs) = do
406 js <- go done 0 bs
423 js <- go done 0 bs
407− return [JSIfElse (JSBinary EqualTo (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left (fromIntegral $ length bs)))) (JSBlock js) Nothing]
424+ return [JSIfElse Nothing (JSBinary Nothing EqualTo (JSAccessor Nothing "length" (JSVar Nothing varName)) (JSNumericLiteral Nothing (Left (fromIntegral $ length bs)))) (JSBlock Nothing js) Nothing]
408 where
425 where
409 go :: [JS] -> Integer -> [Binder Ann] -> m [JS]
426 go :: [JS] -> Integer -> [Binder Ann] -> m [JS]
410 go done' _ [] = return done'
427 go done' _ [] = return done'
@@ -412,21 +429,21 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
412 elVar <- freshName
429 elVar <- freshName
413 done'' <- go done' (index + 1) bs'
430 done'' <- go done' (index + 1) bs'
414 js <- binderToJs elVar done'' binder
431 js <- binderToJs elVar done'' binder
415− return (JSVariableIntroduction elVar (Just (JSIndexer (JSNumericLiteral (Left index)) (JSVar varName))) : js)
432+ return (JSVariableIntroduction Nothing elVar (Just (JSIndexer Nothing (JSNumericLiteral Nothing (Left index)) (JSVar Nothing varName))) : js)
416
433
417 -- Check that all integers fall within the valid int range for JavaScript.
434 -- Check that all integers fall within the valid int range for JavaScript.
418 checkIntegers :: JS -> m ()
435 checkIntegers :: JS -> m ()
419 checkIntegers = void . everywhereOnJSTopDownM go
436 checkIntegers = void . everywhereOnJSTopDownM go
420 where
437 where
421 go :: JS -> m JS
438 go :: JS -> m JS
422− go (JSUnary Negate (JSNumericLiteral (Left i))) =
439+ go (JSUnary _ Negate (JSNumericLiteral ss (Left i))) =
423 -- Move the negation inside the literal; since this is a top-down
440 -- Move the negation inside the literal; since this is a top-down
424 -- traversal doing this replacement will stop the next case from raising
441 -- traversal doing this replacement will stop the next case from raising
425 -- the error when attempting to use -2147483648, as if left unrewritten
442 -- the error when attempting to use -2147483648, as if left unrewritten
426 -- the value is `JSUnary Negate (JSNumericLiteral (Left 2147483648))`, and
443 -- the value is `JSUnary Negate (JSNumericLiteral (Left 2147483648))`, and
427 -- 2147483648 is larger than the maximum allowed int.
444 -- 2147483648 is larger than the maximum allowed int.
428− return $ JSNumericLiteral (Left (-i))
445+ return $ JSNumericLiteral ss (Left (-i))
429− go js@(JSNumericLiteral (Left i)) =
446+ go js@(JSNumericLiteral _ (Left i)) =
430 let minInt = -2147483648
447 let minInt = -2147483648
431 maxInt = 2147483647
448 maxInt = 2147483647
432 in if i < minInt || i > maxInt
449 in if i < minInt || i > maxInt
src/Language/PureScript/CodeGen/JS/AST.hs+168−97
@@ -10,6 +10,7 @@ import Control.Monad.Identity
10
10
11import Language.PureScript.Comments
11import Language.PureScript.Comments
12import Language.PureScript.Traversals
12import Language.PureScript.Traversals
13+import Language.PureScript.AST (SourceSpan(..))
13
14
14-- |
15-- |
15-- Built-in unary operators
16-- Built-in unary operators
@@ -126,120 +127,190 @@ data JS
126 -- |
127 -- |
127 -- A numeric literal
128 -- A numeric literal
128 --
129 --
129− = JSNumericLiteral (Either Integer Double)
130+ = JSNumericLiteral (Maybe SourceSpan) (Either Integer Double)
130 -- |
131 -- |
131 -- A string literal
132 -- A string literal
132 --
133 --
133− | JSStringLiteral String
134+ | JSStringLiteral (Maybe SourceSpan) String
134 -- |
135 -- |
135 -- A boolean literal
136 -- A boolean literal
136 --
137 --
137− | JSBooleanLiteral Bool
138+ | JSBooleanLiteral (Maybe SourceSpan) Bool
138 -- |
139 -- |
139 -- A unary operator application
140 -- A unary operator application
140 --
141 --
141− | JSUnary UnaryOperator JS
142+ | JSUnary (Maybe SourceSpan) UnaryOperator JS
142 -- |
143 -- |
143 -- A binary operator application
144 -- A binary operator application
144 --
145 --
145− | JSBinary BinaryOperator JS JS
146+ | JSBinary (Maybe SourceSpan) BinaryOperator JS JS
146 -- |
147 -- |
147 -- An array literal
148 -- An array literal
148 --
149 --
149− | JSArrayLiteral [JS]
150+ | JSArrayLiteral (Maybe SourceSpan) [JS]
150 -- |
151 -- |
151 -- An array indexer expression
152 -- An array indexer expression
152 --
153 --
153− | JSIndexer JS JS
154+ | JSIndexer (Maybe SourceSpan) JS JS
154 -- |
155 -- |
155 -- An object literal
156 -- An object literal
156 --
157 --
157− | JSObjectLiteral [(String, JS)]
158+ | JSObjectLiteral (Maybe SourceSpan) [(String, JS)]
158 -- |
159 -- |
159 -- An object property accessor expression
160 -- An object property accessor expression
160 --
161 --
161− | JSAccessor String JS
162+ | JSAccessor (Maybe SourceSpan) String JS
162 -- |
163 -- |
163 -- A function introduction (optional name, arguments, body)
164 -- A function introduction (optional name, arguments, body)
164 --
165 --
165− | JSFunction (Maybe String) [String] JS
166+ | JSFunction (Maybe SourceSpan) (Maybe String) [String] JS
166 -- |
167 -- |
167 -- Function application
168 -- Function application
168 --
169 --
169− | JSApp JS [JS]
170+ | JSApp (Maybe SourceSpan) JS [JS]
170 -- |
171 -- |
171 -- Variable
172 -- Variable
172 --
173 --
173− | JSVar String
174+ | JSVar (Maybe SourceSpan) String
174 -- |
175 -- |
175 -- Conditional expression
176 -- Conditional expression
176 --
177 --
177− | JSConditional JS JS JS
178+ | JSConditional (Maybe SourceSpan) JS JS JS
178 -- |
179 -- |
179 -- A block of expressions in braces
180 -- A block of expressions in braces
180 --
181 --
181− | JSBlock [JS]
182+ | JSBlock (Maybe SourceSpan) [JS]
182 -- |
183 -- |
183 -- A variable introduction and optional initialization
184 -- A variable introduction and optional initialization
184 --
185 --
185− | JSVariableIntroduction String (Maybe JS)
186+ | JSVariableIntroduction (Maybe SourceSpan) String (Maybe JS)
186 -- |
187 -- |
187 -- A variable assignment
188 -- A variable assignment
188 --
189 --
189− | JSAssignment JS JS
190+ | JSAssignment (Maybe SourceSpan) JS JS
190 -- |
191 -- |
191 -- While loop
192 -- While loop
192 --
193 --
193− | JSWhile JS JS
194+ | JSWhile (Maybe SourceSpan) JS JS
194 -- |
195 -- |
195 -- For loop
196 -- For loop
196 --
197 --
197− | JSFor String JS JS JS
198+ | JSFor (Maybe SourceSpan) String JS JS JS
198 -- |
199 -- |
199 -- ForIn loop
200 -- ForIn loop
200 --
201 --
201− | JSForIn String JS JS
202+ | JSForIn (Maybe SourceSpan) String JS JS
202 -- |
203 -- |
203 -- If-then-else statement
204 -- If-then-else statement
204 --
205 --
205− | JSIfElse JS JS (Maybe JS)
206+ | JSIfElse (Maybe SourceSpan) JS JS (Maybe JS)
206 -- |
207 -- |
207 -- Return statement
208 -- Return statement
208 --
209 --
209− | JSReturn JS
210+ | JSReturn (Maybe SourceSpan) JS
210 -- |
211 -- |
211 -- Throw statement
212 -- Throw statement
212 --
213 --
213− | JSThrow JS
214+ | JSThrow (Maybe SourceSpan) JS
214 -- |
215 -- |
215 -- Type-Of operator
216 -- Type-Of operator
216 --
217 --
217− | JSTypeOf JS
218+ | JSTypeOf (Maybe SourceSpan) JS
218 -- |
219 -- |
219 -- InstanceOf test
220 -- InstanceOf test
220 --
221 --
221− | JSInstanceOf JS JS
222+ | JSInstanceOf (Maybe SourceSpan) JS JS
222 -- |
223 -- |
223 -- Labelled statement
224 -- Labelled statement
224 --
225 --
225− | JSLabel String JS
226+ | JSLabel (Maybe SourceSpan) String JS
226 -- |
227 -- |
227 -- Break statement
228 -- Break statement
228 --
229 --
229− | JSBreak String
230+ | JSBreak (Maybe SourceSpan) String
230 -- |
231 -- |
231 -- Continue statement
232 -- Continue statement
232 --
233 --
233− | JSContinue String
234+ | JSContinue (Maybe SourceSpan) String
234 -- |
235 -- |
235 -- Raw Javascript (generated when parsing fails for an inline foreign import declaration)
236 -- Raw Javascript (generated when parsing fails for an inline foreign import declaration)
236 --
237 --
237− | JSRaw String
238+ | JSRaw (Maybe SourceSpan) String
238 -- |
239 -- |
239 -- Commented Javascript
240 -- Commented Javascript
240 --
241 --
241− | JSComment [Comment] JS
242+ | JSComment (Maybe SourceSpan) [Comment] JS deriving (Show, Read, Eq)
242− deriving (Show, Read, Eq)
243+
244+withSourceSpan :: SourceSpan -> JS -> JS
245+withSourceSpan withSpan = go
246+ where
247+ ss :: Maybe SourceSpan
248+ ss = Just withSpan
249+
250+ go :: JS -> JS
251+ go (JSNumericLiteral _ n) = JSNumericLiteral ss n
252+ go (JSStringLiteral _ s) = JSStringLiteral ss s
253+ go (JSBooleanLiteral _ b) = JSBooleanLiteral ss b
254+ go (JSUnary _ op j) = JSUnary ss op j
255+ go (JSBinary _ op j1 j2) = JSBinary ss op j1 j2
256+ go (JSArrayLiteral _ js) = JSArrayLiteral ss js
257+ go (JSIndexer _ j1 j2) = JSIndexer ss j1 j2
258+ go (JSObjectLiteral _ js) = JSObjectLiteral ss js
259+ go (JSAccessor _ prop j) = JSAccessor ss prop j
260+ go (JSFunction _ name args j) = JSFunction ss name args j
261+ go (JSApp _ j js) = JSApp ss j js
262+ go (JSVar _ s) = JSVar ss s
263+ go (JSConditional _ j1 j2 j3) = JSConditional ss j1 j2 j3
264+ go (JSBlock _ js) = JSBlock ss js
265+ go (JSVariableIntroduction _ name j) = JSVariableIntroduction ss name j
266+ go (JSAssignment _ j1 j2) = JSAssignment ss j1 j2
267+ go (JSWhile _ j1 j2) = JSWhile ss j1 j2
268+ go (JSFor _ name j1 j2 j3) = JSFor ss name j1 j2 j3
269+ go (JSForIn _ name j1 j2) = JSForIn ss name j1 j2
270+ go (JSIfElse _ j1 j2 j3) = JSIfElse ss j1 j2 j3
271+ go (JSReturn _ js) = JSReturn ss js
272+ go (JSThrow _ js) = JSThrow ss js
273+ go (JSTypeOf _ js) = JSTypeOf ss js
274+ go (JSInstanceOf _ j1 j2) = JSInstanceOf ss j1 j2
275+ go (JSLabel _ name js) = JSLabel ss name js
276+ go (JSBreak _ s) = JSBreak ss s
277+ go (JSContinue _ s) = JSContinue ss s
278+ go (JSRaw _ s) = JSRaw ss s
279+ go (JSComment _ com j) = JSComment ss com j
280+
281+getSourceSpan :: JS -> Maybe SourceSpan
282+getSourceSpan = go
283+ where
284+ go :: JS -> Maybe SourceSpan
285+ go (JSNumericLiteral ss _) = ss
286+ go (JSStringLiteral ss _) = ss
287+ go (JSBooleanLiteral ss _) = ss
288+ go (JSUnary ss _ _) = ss
289+ go (JSBinary ss _ _ _) = ss
290+ go (JSArrayLiteral ss _) = ss
291+ go (JSIndexer ss _ _) = ss
292+ go (JSObjectLiteral ss _) = ss
293+ go (JSAccessor ss _ _) = ss
294+ go (JSFunction ss _ _ _) = ss
295+ go (JSApp ss _ _) = ss
296+ go (JSVar ss _) = ss
297+ go (JSConditional ss _ _ _) = ss
298+ go (JSBlock ss _) = ss
299+ go (JSVariableIntroduction ss _ _) = ss
300+ go (JSAssignment ss _ _) = ss
301+ go (JSWhile ss _ _) = ss
302+ go (JSFor ss _ _ _ _) = ss
303+ go (JSForIn ss _ _ _) = ss
304+ go (JSIfElse ss _ _ _) = ss
305+ go (JSReturn ss _) = ss
306+ go (JSThrow ss _) = ss
307+ go (JSTypeOf ss _) = ss
308+ go (JSInstanceOf ss _ _) = ss
309+ go (JSLabel ss _ _) = ss
310+ go (JSBreak ss _) = ss
311+ go (JSContinue ss _) = ss
312+ go (JSRaw ss _) = ss
313+ go (JSComment ss _ _) = ss
243
314
244--
315--
245-- Traversals
316-- Traversals
@@ -249,28 +320,28 @@ everywhereOnJS :: (JS -> JS) -> JS -> JS
249everywhereOnJS f = go
320everywhereOnJS f = go
250 where
321 where
251 go :: JS -> JS
322 go :: JS -> JS
252− go (JSUnary op j) = f (JSUnary op (go j))
323+ go (JSUnary ss op j) = f (JSUnary ss op (go j))
253− go (JSBinary op j1 j2) = f (JSBinary op (go j1) (go j2))
324+ go (JSBinary ss op j1 j2) = f (JSBinary ss op (go j1) (go j2))
254− go (JSArrayLiteral js) = f (JSArrayLiteral (map go js))
325+ go (JSArrayLiteral ss js) = f (JSArrayLiteral ss (map go js))
255− go (JSIndexer j1 j2) = f (JSIndexer (go j1) (go j2))
326+ go (JSIndexer ss j1 j2) = f (JSIndexer ss (go j1) (go j2))
256− go (JSObjectLiteral js) = f (JSObjectLiteral (map (fmap go) js))
327+ go (JSObjectLiteral ss js) = f (JSObjectLiteral ss (map (fmap go) js))
257− go (JSAccessor prop j) = f (JSAccessor prop (go j))
328+ go (JSAccessor ss prop j) = f (JSAccessor ss prop (go j))
258− go (JSFunction name args j) = f (JSFunction name args (go j))
329+ go (JSFunction ss name args j) = f (JSFunction ss name args (go j))
259− go (JSApp j js) = f (JSApp (go j) (map go js))
330+ go (JSApp ss j js) = f (JSApp ss (go j) (map go js))
260− go (JSConditional j1 j2 j3) = f (JSConditional (go j1) (go j2) (go j3))
331+ go (JSConditional ss j1 j2 j3) = f (JSConditional ss (go j1) (go j2) (go j3))
261− go (JSBlock js) = f (JSBlock (map go js))
332+ go (JSBlock ss js) = f (JSBlock ss (map go js))
262− go (JSVariableIntroduction name j) = f (JSVariableIntroduction name (fmap go j))
333+ go (JSVariableIntroduction ss name j) = f (JSVariableIntroduction ss name (fmap go j))
263− go (JSAssignment j1 j2) = f (JSAssignment (go j1) (go j2))
334+ go (JSAssignment ss j1 j2) = f (JSAssignment ss (go j1) (go j2))
264− go (JSWhile j1 j2) = f (JSWhile (go j1) (go j2))
335+ go (JSWhile ss j1 j2) = f (JSWhile ss (go j1) (go j2))
265− go (JSFor name j1 j2 j3) = f (JSFor name (go j1) (go j2) (go j3))
336+ go (JSFor ss name j1 j2 j3) = f (JSFor ss name (go j1) (go j2) (go j3))
266− go (JSForIn name j1 j2) = f (JSForIn name (go j1) (go j2))
337+ go (JSForIn ss name j1 j2) = f (JSForIn ss name (go j1) (go j2))
267− go (JSIfElse j1 j2 j3) = f (JSIfElse (go j1) (go j2) (fmap go j3))
338+ go (JSIfElse ss j1 j2 j3) = f (JSIfElse ss (go j1) (go j2) (fmap go j3))
268− go (JSReturn js) = f (JSReturn (go js))
339+ go (JSReturn ss js) = f (JSReturn ss (go js))
269− go (JSThrow js) = f (JSThrow (go js))
340+ go (JSThrow ss js) = f (JSThrow ss (go js))
270− go (JSTypeOf js) = f (JSTypeOf (go js))
341+ go (JSTypeOf ss js) = f (JSTypeOf ss (go js))
271− go (JSLabel name js) = f (JSLabel name (go js))
342+ go (JSLabel ss name js) = f (JSLabel ss name (go js))
272− go (JSInstanceOf j1 j2) = f (JSInstanceOf (go j1) (go j2))
343+ go (JSInstanceOf ss j1 j2) = f (JSInstanceOf ss (go j1) (go j2))
273− go (JSComment com j) = f (JSComment com (go j))
344+ go (JSComment ss com j) = f (JSComment ss com (go j))
274 go other = f other
345 go other = f other
275
346
276everywhereOnJSTopDown :: (JS -> JS) -> JS -> JS
347everywhereOnJSTopDown :: (JS -> JS) -> JS -> JS
@@ -280,54 +351,54 @@ everywhereOnJSTopDownM :: (Applicative m, Monad m) => (JS -> m JS) -> JS -> m JS
280everywhereOnJSTopDownM f = f >=> go
351everywhereOnJSTopDownM f = f >=> go
281 where
352 where
282 f' = f >=> go
353 f' = f >=> go
283− go (JSUnary op j) = JSUnary op <$> f' j
354+ go (JSUnary ss op j) = JSUnary ss op <$> f' j
284− go (JSBinary op j1 j2) = JSBinary op <$> f' j1 <*> f' j2
355+ go (JSBinary ss op j1 j2) = JSBinary ss op <$> f' j1 <*> f' j2
285− go (JSArrayLiteral js) = JSArrayLiteral <$> traverse f' js
356+ go (JSArrayLiteral ss js) = JSArrayLiteral ss <$> traverse f' js
286− go (JSIndexer j1 j2) = JSIndexer <$> f' j1 <*> f' j2
357+ go (JSIndexer ss j1 j2) = JSIndexer ss <$> f' j1 <*> f' j2
287− go (JSObjectLiteral js) = JSObjectLiteral <$> traverse (sndM f') js
358+ go (JSObjectLiteral ss js) = JSObjectLiteral ss <$> traverse (sndM f') js
288− go (JSAccessor prop j) = JSAccessor prop <$> f' j
359+ go (JSAccessor ss prop j) = JSAccessor ss prop <$> f' j
289− go (JSFunction name args j) = JSFunction name args <$> f' j
360+ go (JSFunction ss name args j) = JSFunction ss name args <$> f' j
290− go (JSApp j js) = JSApp <$> f' j <*> traverse f' js
361+ go (JSApp ss j js) = JSApp ss <$> f' j <*> traverse f' js
291− go (JSConditional j1 j2 j3) = JSConditional <$> f' j1 <*> f' j2 <*> f' j3
362+ go (JSConditional ss j1 j2 j3) = JSConditional ss <$> f' j1 <*> f' j2 <*> f' j3
292− go (JSBlock js) = JSBlock <$> traverse f' js
363+ go (JSBlock ss js) = JSBlock ss <$> traverse f' js
293− go (JSVariableIntroduction name j) = JSVariableIntroduction name <$> traverse f' j
364+ go (JSVariableIntroduction ss name j) = JSVariableIntroduction ss name <$> traverse f' j
294− go (JSAssignment j1 j2) = JSAssignment <$> f' j1 <*> f' j2
365+ go (JSAssignment ss j1 j2) = JSAssignment ss <$> f' j1 <*> f' j2
295− go (JSWhile j1 j2) = JSWhile <$> f' j1 <*> f' j2
366+ go (JSWhile ss j1 j2) = JSWhile ss <$> f' j1 <*> f' j2
296− go (JSFor name j1 j2 j3) = JSFor name <$> f' j1 <*> f' j2 <*> f' j3
367+ go (JSFor ss name j1 j2 j3) = JSFor ss name <$> f' j1 <*> f' j2 <*> f' j3
297− go (JSForIn name j1 j2) = JSForIn name <$> f' j1 <*> f' j2
368+ go (JSForIn ss name j1 j2) = JSForIn ss name <$> f' j1 <*> f' j2
298− go (JSIfElse j1 j2 j3) = JSIfElse <$> f' j1 <*> f' j2 <*> traverse f' j3
369+ go (JSIfElse ss j1 j2 j3) = JSIfElse ss <$> f' j1 <*> f' j2 <*> traverse f' j3
299− go (JSReturn j) = JSReturn <$> f' j
370+ go (JSReturn ss j) = JSReturn ss <$> f' j
300− go (JSThrow j) = JSThrow <$> f' j
371+ go (JSThrow ss j) = JSThrow ss <$> f' j
301− go (JSTypeOf j) = JSTypeOf <$> f' j
372+ go (JSTypeOf ss j) = JSTypeOf ss <$> f' j
302− go (JSLabel name j) = JSLabel name <$> f' j
373+ go (JSLabel ss name j) = JSLabel ss name <$> f' j
303− go (JSInstanceOf j1 j2) = JSInstanceOf <$> f' j1 <*> f' j2
374+ go (JSInstanceOf ss j1 j2) = JSInstanceOf ss <$> f' j1 <*> f' j2
304− go (JSComment com j) = JSComment com <$> f' j
375+ go (JSComment ss com j) = JSComment ss com <$> f' j
305 go other = f other
376 go other = f other
306
377
307everythingOnJS :: (r -> r -> r) -> (JS -> r) -> JS -> r
378everythingOnJS :: (r -> r -> r) -> (JS -> r) -> JS -> r
308everythingOnJS (<>) f = go
379everythingOnJS (<>) f = go
309 where
380 where
310− go j@(JSUnary _ j1) = f j <> go j1
381+ go j@(JSUnary _ _ j1) = f j <> go j1
311− go j@(JSBinary _ j1 j2) = f j <> go j1 <> go j2
382+ go j@(JSBinary _ _ j1 j2) = f j <> go j1 <> go j2
312− go j@(JSArrayLiteral js) = foldl (<>) (f j) (map go js)
383+ go j@(JSArrayLiteral _ js) = foldl (<>) (f j) (map go js)
313− go j@(JSIndexer j1 j2) = f j <> go j1 <> go j2
384+ go j@(JSIndexer _ j1 j2) = f j <> go j1 <> go j2
314− go j@(JSObjectLiteral js) = foldl (<>) (f j) (map (go . snd) js)
385+ go j@(JSObjectLiteral _ js) = foldl (<>) (f j) (map (go . snd) js)
315− go j@(JSAccessor _ j1) = f j <> go j1
386+ go j@(JSAccessor _ _ j1) = f j <> go j1
316− go j@(JSFunction _ _ j1) = f j <> go j1
387+ go j@(JSFunction _ _ _ j1) = f j <> go j1
317− go j@(JSApp j1 js) = foldl (<>) (f j <> go j1) (map go js)
388+ go j@(JSApp _ j1 js) = foldl (<>) (f j <> go j1) (map go js)
318− go j@(JSConditional j1 j2 j3) = f j <> go j1 <> go j2 <> go j3
389+ go j@(JSConditional _ j1 j2 j3) = f j <> go j1 <> go j2 <> go j3
319− go j@(JSBlock js) = foldl (<>) (f j) (map go js)
390+ go j@(JSBlock _ js) = foldl (<>) (f j) (map go js)
320− go j@(JSVariableIntroduction _ (Just j1)) = f j <> go j1
391+ go j@(JSVariableIntroduction _ _ (Just j1)) = f j <> go j1
321− go j@(JSAssignment j1 j2) = f j <> go j1 <> go j2
392+ go j@(JSAssignment _ j1 j2) = f j <> go j1 <> go j2
322− go j@(JSWhile j1 j2) = f j <> go j1 <> go j2
393+ go j@(JSWhile _ j1 j2) = f j <> go j1 <> go j2
323− go j@(JSFor _ j1 j2 j3) = f j <> go j1 <> go j2 <> go j3
394+ go j@(JSFor _ _ j1 j2 j3) = f j <> go j1 <> go j2 <> go j3
324− go j@(JSForIn _ j1 j2) = f j <> go j1 <> go j2
395+ go j@(JSForIn _ _ j1 j2) = f j <> go j1 <> go j2
325− go j@(JSIfElse j1 j2 Nothing) = f j <> go j1 <> go j2
396+ go j@(JSIfElse _ j1 j2 Nothing) = f j <> go j1 <> go j2
326− go j@(JSIfElse j1 j2 (Just j3)) = f j <> go j1 <> go j2 <> go j3
397+ go j@(JSIfElse _ j1 j2 (Just j3)) = f j <> go j1 <> go j2 <> go j3
327− go j@(JSReturn j1) = f j <> go j1
398+ go j@(JSReturn _ j1) = f j <> go j1
328− go j@(JSThrow j1) = f j <> go j1
399+ go j@(JSThrow _ j1) = f j <> go j1
329− go j@(JSTypeOf j1) = f j <> go j1
400+ go j@(JSTypeOf _ j1) = f j <> go j1
330− go j@(JSLabel _ j1) = f j <> go j1
401+ go j@(JSLabel _ _ j1) = f j <> go j1
331− go j@(JSInstanceOf j1 j2) = f j <> go j1 <> go j2
402+ go j@(JSInstanceOf _ j1 j2) = f j <> go j1 <> go j2
332− go j@(JSComment _ j1) = f j <> go j1
403+ go j@(JSComment _ _ j1) = f j <> go j1
333 go other = f other
404 go other = f other
src/Language/PureScript/CodeGen/JS/Optimizer.hs+5−5
@@ -53,11 +53,11 @@ optimize' js = do
53 opts <- ask
53 opts <- ask
54 js' <- untilFixedPoint (inlineFnComposition . tidyUp . applyAll
54 js' <- untilFixedPoint (inlineFnComposition . tidyUp . applyAll
55 [ inlineCommonValues
55 [ inlineCommonValues
56− , inlineOperator (C.prelude, (C.$)) $ \f x -> JSApp f [x]
56+ , inlineOperator (C.prelude, (C.$)) $ \f x -> JSApp Nothing f [x]
57− , inlineOperator (C.dataFunction, C.apply) $ \f x -> JSApp f [x]
57+ , inlineOperator (C.dataFunction, C.apply) $ \f x -> JSApp Nothing f [x]
58− , inlineOperator (C.prelude, (C.#)) $ \x f -> JSApp f [x]
58+ , inlineOperator (C.prelude, (C.#)) $ \x f -> JSApp Nothing f [x]
59− , inlineOperator (C.dataFunction, C.applyFlipped) $ \x f -> JSApp f [x]
59+ , inlineOperator (C.dataFunction, C.applyFlipped) $ \x f -> JSApp Nothing f [x]
60− , inlineOperator (C.dataArrayUnsafe, C.unsafeIndex) $ flip JSIndexer
60+ , inlineOperator (C.dataArrayUnsafe, C.unsafeIndex) $ flip (JSIndexer Nothing)
61 , inlineCommonOperators
61 , inlineCommonOperators
62 ]) js
62 ]) js
63 untilFixedPoint (return . tidyUp) . tco opts . magicDo opts $ js'
63 untilFixedPoint (return . tidyUp) . tco opts . magicDo opts $ js'
src/Language/PureScript/CodeGen/JS/Optimizer/Blocks.hs+4−4
@@ -27,16 +27,16 @@ collapseNestedBlocks :: JS -> JS
27collapseNestedBlocks = everywhereOnJS collapse
27collapseNestedBlocks = everywhereOnJS collapse
28 where
28 where
29 collapse :: JS -> JS
29 collapse :: JS -> JS
30− collapse (JSBlock sts) = JSBlock (concatMap go sts)
30+ collapse (JSBlock ss sts) = JSBlock ss (concatMap go sts)
31 collapse js = js
31 collapse js = js
32 go :: JS -> [JS]
32 go :: JS -> [JS]
33− go (JSBlock sts) = sts
33+ go (JSBlock _ sts) = sts
34 go s = [s]
34 go s = [s]
35
35
36collapseNestedIfs :: JS -> JS
36collapseNestedIfs :: JS -> JS
37collapseNestedIfs = everywhereOnJS collapse
37collapseNestedIfs = everywhereOnJS collapse
38 where
38 where
39 collapse :: JS -> JS
39 collapse :: JS -> JS
40− collapse (JSIfElse cond1 (JSBlock [JSIfElse cond2 body Nothing]) Nothing) =
40+ collapse (JSIfElse s1 cond1 (JSBlock _ [JSIfElse s2 cond2 body Nothing]) Nothing) =
41− JSIfElse (JSBinary And cond1 cond2) body Nothing
41+ JSIfElse s1 (JSBinary s2 And cond1 cond2) body Nothing
42 collapse js = js
42 collapse js = js
src/Language/PureScript/CodeGen/JS/Optimizer/Common.hs+18−18
@@ -14,67 +14,67 @@ applyAll = foldl1 (.)
14replaceIdent :: String -> JS -> JS -> JS
14replaceIdent :: String -> JS -> JS -> JS
15replaceIdent var1 js = everywhereOnJS replace
15replaceIdent var1 js = everywhereOnJS replace
16 where
16 where
17− replace (JSVar var2) | var1 == var2 = js
17+ replace (JSVar _ var2) | var1 == var2 = js
18 replace other = other
18 replace other = other
19
19
20replaceIdents :: [(String, JS)] -> JS -> JS
20replaceIdents :: [(String, JS)] -> JS -> JS
21replaceIdents vars = everywhereOnJS replace
21replaceIdents vars = everywhereOnJS replace
22 where
22 where
23− replace v@(JSVar var) = fromMaybe v $ lookup var vars
23+ replace v@(JSVar _ var) = fromMaybe v $ lookup var vars
24 replace other = other
24 replace other = other
25
25
26isReassigned :: String -> JS -> Bool
26isReassigned :: String -> JS -> Bool
27isReassigned var1 = everythingOnJS (||) check
27isReassigned var1 = everythingOnJS (||) check
28 where
28 where
29 check :: JS -> Bool
29 check :: JS -> Bool
30− check (JSFunction _ args _) | var1 `elem` args = True
30+ check (JSFunction _ _ args _) | var1 `elem` args = True
31− check (JSVariableIntroduction arg _) | var1 == arg = True
31+ check (JSVariableIntroduction _ arg _) | var1 == arg = True
32− check (JSAssignment (JSVar arg) _) | var1 == arg = True
32+ check (JSAssignment _ (JSVar _ arg) _) | var1 == arg = True
33− check (JSFor arg _ _ _) | var1 == arg = True
33+ check (JSFor _ arg _ _ _) | var1 == arg = True
34− check (JSForIn arg _ _) | var1 == arg = True
34+ check (JSForIn _ arg _ _) | var1 == arg = True
35 check _ = False
35 check _ = False
36
36
37isRebound :: JS -> JS -> Bool
37isRebound :: JS -> JS -> Bool
38isRebound js d = any (\v -> isReassigned v d || isUpdated v d) (everythingOnJS (++) variablesOf js)
38isRebound js d = any (\v -> isReassigned v d || isUpdated v d) (everythingOnJS (++) variablesOf js)
39 where
39 where
40− variablesOf (JSVar var) = [var]
40+ variablesOf (JSVar _ var) = [var]
41 variablesOf _ = []
41 variablesOf _ = []
42
42
43isUsed :: String -> JS -> Bool
43isUsed :: String -> JS -> Bool
44isUsed var1 = everythingOnJS (||) check
44isUsed var1 = everythingOnJS (||) check
45 where
45 where
46 check :: JS -> Bool
46 check :: JS -> Bool
47− check (JSVar var2) | var1 == var2 = True
47+ check (JSVar _ var2) | var1 == var2 = True
48− check (JSAssignment target _) | var1 == targetVariable target = True
48+ check (JSAssignment _ target _) | var1 == targetVariable target = True
49 check _ = False
49 check _ = False
50
50
51targetVariable :: JS -> String
51targetVariable :: JS -> String
52−targetVariable (JSVar var) = var
52+targetVariable (JSVar _ var) = var
53−targetVariable (JSAccessor _ tgt) = targetVariable tgt
53+targetVariable (JSAccessor _ _ tgt) = targetVariable tgt
54−targetVariable (JSIndexer _ tgt) = targetVariable tgt
54+targetVariable (JSIndexer _ _ tgt) = targetVariable tgt
55targetVariable _ = internalError "Invalid argument to targetVariable"
55targetVariable _ = internalError "Invalid argument to targetVariable"
56
56
57isUpdated :: String -> JS -> Bool
57isUpdated :: String -> JS -> Bool
58isUpdated var1 = everythingOnJS (||) check
58isUpdated var1 = everythingOnJS (||) check
59 where
59 where
60 check :: JS -> Bool
60 check :: JS -> Bool
61− check (JSAssignment target _) | var1 == targetVariable target = True
61+ check (JSAssignment _ target _) | var1 == targetVariable target = True
62 check _ = False
62 check _ = False
63
63
64removeFromBlock :: ([JS] -> [JS]) -> JS -> JS
64removeFromBlock :: ([JS] -> [JS]) -> JS -> JS
65−removeFromBlock go (JSBlock sts) = JSBlock (go sts)
65+removeFromBlock go (JSBlock ss sts) = JSBlock ss (go sts)
66removeFromBlock _ js = js
66removeFromBlock _ js = js
67
67
68isFn :: (String, String) -> JS -> Bool
68isFn :: (String, String) -> JS -> Bool
69−isFn (moduleName, fnName) (JSAccessor x (JSVar y)) = x == fnName && y == moduleName
69+isFn (moduleName, fnName) (JSAccessor _ x (JSVar _ y)) = x == fnName && y == moduleName
70−isFn (moduleName, fnName) (JSIndexer (JSStringLiteral x) (JSVar y)) = x == fnName && y == moduleName
70+isFn (moduleName, fnName) (JSIndexer _ (JSStringLiteral _ x) (JSVar _ y)) = x == fnName && y == moduleName
71isFn _ _ = False
71isFn _ _ = False
72
72
73isFn' :: [(String, String)] -> JS -> Bool
73isFn' :: [(String, String)] -> JS -> Bool
74isFn' xs js = any (`isFn` js) xs
74isFn' xs js = any (`isFn` js) xs
75
75
76isDict :: (String, String) -> JS -> Bool
76isDict :: (String, String) -> JS -> Bool
77−isDict (moduleName, dictName) (JSAccessor x (JSVar y)) = x == dictName && y == moduleName
77+isDict (moduleName, dictName) (JSAccessor _ x (JSVar _ y)) = x == dictName && y == moduleName
78isDict _ _ = False
78isDict _ _ = False
79
79
80isDict' :: [(String, String)] -> JS -> Bool
80isDict' :: [(String, String)] -> JS -> Bool
src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs+50−50
@@ -29,42 +29,42 @@ import qualified Language.PureScript.Constants as C
29-- Needs to be: { 0..toFixed(10); }
29-- Needs to be: { 0..toFixed(10); }
30-- Probably needs to be fixed in pretty-printer instead.
30-- Probably needs to be fixed in pretty-printer instead.
31shouldInline :: JS -> Bool
31shouldInline :: JS -> Bool
32−shouldInline (JSVar _) = True
32+shouldInline (JSVar _ _) = True
33−shouldInline (JSNumericLiteral _) = True
33+shouldInline (JSNumericLiteral _ _) = True
34−shouldInline (JSStringLiteral _) = True
34+shouldInline (JSStringLiteral _ _) = True
35−shouldInline (JSBooleanLiteral _) = True
35+shouldInline (JSBooleanLiteral _ _) = True
36−shouldInline (JSAccessor _ val) = shouldInline val
36+shouldInline (JSAccessor _ _ val) = shouldInline val
37−shouldInline (JSIndexer index val) = shouldInline index && shouldInline val
37+shouldInline (JSIndexer _ index val) = shouldInline index && shouldInline val
38shouldInline _ = False
38shouldInline _ = False
39
39
40etaConvert :: JS -> JS
40etaConvert :: JS -> JS
41etaConvert = everywhereOnJS convert
41etaConvert = everywhereOnJS convert
42 where
42 where
43 convert :: JS -> JS
43 convert :: JS -> JS
44− convert (JSBlock [JSReturn (JSApp (JSFunction Nothing idents block@(JSBlock body)) args)])
44+ convert (JSBlock ss [JSReturn _ (JSApp _ (JSFunction _ Nothing idents block@(JSBlock _ body)) args)])
45 | all shouldInline args &&
45 | all shouldInline args &&
46− not (any (`isRebound` block) (map JSVar idents)) &&
46+ not (any (`isRebound` block) (map (JSVar Nothing) idents)) &&
47 not (any (`isRebound` block) args)
47 not (any (`isRebound` block) args)
48− = JSBlock (map (replaceIdents (zip idents args)) body)
48+ = JSBlock ss (map (replaceIdents (zip idents args)) body)
49− convert (JSFunction Nothing [] (JSBlock [JSReturn (JSApp fn [])])) = fn
49+ convert (JSFunction _ Nothing [] (JSBlock _ [JSReturn _ (JSApp _ fn [])])) = fn
50 convert js = js
50 convert js = js
51
51
52unThunk :: JS -> JS
52unThunk :: JS -> JS
53unThunk = everywhereOnJS convert
53unThunk = everywhereOnJS convert
54 where
54 where
55 convert :: JS -> JS
55 convert :: JS -> JS
56− convert (JSBlock []) = JSBlock []
56+ convert (JSBlock ss []) = JSBlock ss []
57− convert (JSBlock jss) =
57+ convert (JSBlock ss jss) =
58 case last jss of
58 case last jss of
59− JSReturn (JSApp (JSFunction Nothing [] (JSBlock body)) []) -> JSBlock $ init jss ++ body
59+ JSReturn _ (JSApp _ (JSFunction _ Nothing [] (JSBlock _ body)) []) -> JSBlock ss $ init jss ++ body
60− _ -> JSBlock jss
60+ _ -> JSBlock ss jss
61 convert js = js
61 convert js = js
62
62
63evaluateIifes :: JS -> JS
63evaluateIifes :: JS -> JS
64evaluateIifes = everywhereOnJS convert
64evaluateIifes = everywhereOnJS convert
65 where
65 where
66 convert :: JS -> JS
66 convert :: JS -> JS
67− convert (JSApp (JSFunction Nothing [] (JSBlock [JSReturn ret])) []) = ret
67+ convert (JSApp _ (JSFunction _ Nothing [] (JSBlock _ [JSReturn _ ret])) []) = ret
68 convert js = js
68 convert js = js
69
69
70inlineVariables :: JS -> JS
70inlineVariables :: JS -> JS
@@ -72,7 +72,7 @@ inlineVariables = everywhereOnJS $ removeFromBlock go
72 where
72 where
73 go :: [JS] -> [JS]
73 go :: [JS] -> [JS]
74 go [] = []
74 go [] = []
75− go (JSVariableIntroduction var (Just js) : sts)
75+ go (JSVariableIntroduction _ var (Just js) : sts)
76 | shouldInline js && not (any (isReassigned var) sts) && not (any (isRebound js) sts) && not (any (isUpdated var) sts) =
76 | shouldInline js && not (any (isReassigned var) sts) && not (any (isRebound js) sts) && not (any (isUpdated var) sts) =
77 go (map (replaceIdent var js) sts)
77 go (map (replaceIdent var js) sts)
78 go (s:sts) = s : go sts
78 go (s:sts) = s : go sts
@@ -81,16 +81,16 @@ inlineCommonValues :: JS -> JS
81inlineCommonValues = everywhereOnJS convert
81inlineCommonValues = everywhereOnJS convert
82 where
82 where
83 convert :: JS -> JS
83 convert :: JS -> JS
84− convert (JSApp fn [dict])
84+ convert (JSApp ss fn [dict])
85− | isDict' (semiringNumber ++ semiringInt) dict && isFn' fnZero fn = JSNumericLiteral (Left 0)
85+ | isDict' (semiringNumber ++ semiringInt) dict && isFn' fnZero fn = JSNumericLiteral ss (Left 0)
86− | isDict' (semiringNumber ++ semiringInt) dict && isFn' fnOne fn = JSNumericLiteral (Left 1)
86+ | isDict' (semiringNumber ++ semiringInt) dict && isFn' fnOne fn = JSNumericLiteral ss (Left 1)
87− | isDict' boundedBoolean dict && isFn' fnBottom fn = JSBooleanLiteral False
87+ | isDict' boundedBoolean dict && isFn' fnBottom fn = JSBooleanLiteral ss False
88− | isDict' boundedBoolean dict && isFn' fnTop fn = JSBooleanLiteral True
88+ | isDict' boundedBoolean dict && isFn' fnTop fn = JSBooleanLiteral ss True
89− convert (JSApp (JSApp (JSApp fn [dict]) [x]) [y])
89+ convert (JSApp ss (JSApp _ (JSApp _ fn [dict]) [x]) [y])
90− | isDict' semiringInt dict && isFn' fnAdd fn = intOp Add x y
90+ | isDict' semiringInt dict && isFn' fnAdd fn = intOp ss Add x y
91− | isDict' semiringInt dict && isFn' fnMultiply fn = intOp Multiply x y
91+ | isDict' semiringInt dict && isFn' fnMultiply fn = intOp ss Multiply x y
92− | isDict' moduloSemiringInt dict && isFn' fnDivide fn = intOp Divide x y
92+ | isDict' moduloSemiringInt dict && isFn' fnDivide fn = intOp ss Divide x y
93− | isDict' ringInt dict && isFn' fnSubtract fn = intOp Subtract x y
93+ | isDict' ringInt dict && isFn' fnSubtract fn = intOp ss Subtract x y
94 convert other = other
94 convert other = other
95 fnZero = [(C.prelude, C.zero), (C.dataSemiring, C.zero)]
95 fnZero = [(C.prelude, C.zero), (C.dataSemiring, C.zero)]
96 fnOne = [(C.prelude, C.one), (C.dataSemiring, C.one)]
96 fnOne = [(C.prelude, C.one), (C.dataSemiring, C.one)]
@@ -100,16 +100,16 @@ inlineCommonValues = everywhereOnJS convert
100 fnDivide = [(C.prelude, (C./)), (C.prelude, (C.div)), (C.dataModuloSemiring, C.div)]
100 fnDivide = [(C.prelude, (C./)), (C.prelude, (C.div)), (C.dataModuloSemiring, C.div)]
101 fnMultiply = [(C.prelude, (C.*)), (C.prelude, (C.mul)), (C.dataSemiring, (C.*)), (C.dataSemiring, (C.mul))]
101 fnMultiply = [(C.prelude, (C.*)), (C.prelude, (C.mul)), (C.dataSemiring, (C.*)), (C.dataSemiring, (C.mul))]
102 fnSubtract = [(C.prelude, (C.-)), (C.prelude, C.sub), (C.dataRing, C.sub)]
102 fnSubtract = [(C.prelude, (C.-)), (C.prelude, C.sub), (C.dataRing, C.sub)]
103− intOp op x y = JSBinary BitwiseOr (JSBinary op x y) (JSNumericLiteral (Left 0))
103+ intOp ss op x y = JSBinary ss BitwiseOr (JSBinary ss op x y) (JSNumericLiteral ss (Left 0))
104
104
105inlineOperator :: (String, String) -> (JS -> JS -> JS) -> JS -> JS
105inlineOperator :: (String, String) -> (JS -> JS -> JS) -> JS -> JS
106inlineOperator (m, op) f = everywhereOnJS convert
106inlineOperator (m, op) f = everywhereOnJS convert
107 where
107 where
108 convert :: JS -> JS
108 convert :: JS -> JS
109− convert (JSApp (JSApp op' [x]) [y]) | isOp op' = f x y
109+ convert (JSApp _ (JSApp _ op' [x]) [y]) | isOp op' = f x y
110 convert other = other
110 convert other = other
111− isOp (JSAccessor longForm (JSVar m')) = m == m' && longForm == identToJs (Op op)
111+ isOp (JSAccessor _ longForm (JSVar _ m')) = m == m' && longForm == identToJs (Op op)
112− isOp (JSIndexer (JSStringLiteral op') (JSVar m')) = m == m' && op == op'
112+ isOp (JSIndexer _ (JSStringLiteral _ op') (JSVar _ m')) = m == m' && op == op'
113 isOp _ = False
113 isOp _ = False
114
114
115inlineCommonOperators :: JS -> JS
115inlineCommonOperators :: JS -> JS
@@ -177,49 +177,49 @@ inlineCommonOperators = applyAll $
177 binary dict fns op = everywhereOnJS convert
177 binary dict fns op = everywhereOnJS convert
178 where
178 where
179 convert :: JS -> JS
179 convert :: JS -> JS
180− convert (JSApp (JSApp (JSApp fn [dict']) [x]) [y]) | isDict' dict dict' && isFn' fns fn = JSBinary op x y
180+ convert (JSApp ss (JSApp _ (JSApp _ fn [dict']) [x]) [y]) | isDict' dict dict' && isFn' fns fn = JSBinary ss op x y
181 convert other = other
181 convert other = other
182 binary' :: String -> String -> BinaryOperator -> JS -> JS
182 binary' :: String -> String -> BinaryOperator -> JS -> JS
183 binary' moduleName opString op = everywhereOnJS convert
183 binary' moduleName opString op = everywhereOnJS convert
184 where
184 where
185 convert :: JS -> JS
185 convert :: JS -> JS
186− convert (JSApp (JSApp fn [x]) [y]) | isFn (moduleName, opString) fn = JSBinary op x y
186+ convert (JSApp ss (JSApp _ fn [x]) [y]) | isFn (moduleName, opString) fn = JSBinary ss op x y
187 convert other = other
187 convert other = other
188 unary :: [(String, String)] -> [(String, String)] -> UnaryOperator -> JS -> JS
188 unary :: [(String, String)] -> [(String, String)] -> UnaryOperator -> JS -> JS
189 unary dicts fns op = everywhereOnJS convert
189 unary dicts fns op = everywhereOnJS convert
190 where
190 where
191 convert :: JS -> JS
191 convert :: JS -> JS
192− convert (JSApp (JSApp fn [dict']) [x]) | isDict' dicts dict' && isFn' fns fn = JSUnary op x
192+ convert (JSApp ss (JSApp _ fn [dict']) [x]) | isDict' dicts dict' && isFn' fns fn = JSUnary ss op x
193 convert other = other
193 convert other = other
194 unary' :: String -> String -> UnaryOperator -> JS -> JS
194 unary' :: String -> String -> UnaryOperator -> JS -> JS
195 unary' moduleName fnName op = everywhereOnJS convert
195 unary' moduleName fnName op = everywhereOnJS convert
196 where
196 where
197 convert :: JS -> JS
197 convert :: JS -> JS
198− convert (JSApp fn [x]) | isFn (moduleName, fnName) fn = JSUnary op x
198+ convert (JSApp ss fn [x]) | isFn (moduleName, fnName) fn = JSUnary ss op x
199 convert other = other
199 convert other = other
200 mkFn :: Int -> JS -> JS
200 mkFn :: Int -> JS -> JS
201 mkFn 0 = everywhereOnJS convert
201 mkFn 0 = everywhereOnJS convert
202 where
202 where
203 convert :: JS -> JS
203 convert :: JS -> JS
204− convert (JSApp mkFnN [JSFunction Nothing [_] (JSBlock js)]) | isNFn C.mkFn 0 mkFnN =
204+ convert (JSApp _ mkFnN [JSFunction s1 Nothing [_] (JSBlock s2 js)]) | isNFn C.mkFn 0 mkFnN =
205− JSFunction Nothing [] (JSBlock js)
205+ JSFunction s1 Nothing [] (JSBlock s2 js)
206 convert other = other
206 convert other = other
207 mkFn n = everywhereOnJS convert
207 mkFn n = everywhereOnJS convert
208 where
208 where
209 convert :: JS -> JS
209 convert :: JS -> JS
210− convert orig@(JSApp mkFnN [fn]) | isNFn C.mkFn n mkFnN =
210+ convert orig@(JSApp ss mkFnN [fn]) | isNFn C.mkFn n mkFnN =
211 case collectArgs n [] fn of
211 case collectArgs n [] fn of
212− Just (args, js) -> JSFunction Nothing args (JSBlock js)
212+ Just (args, js) -> JSFunction ss Nothing args (JSBlock ss js)
213 Nothing -> orig
213 Nothing -> orig
214 convert other = other
214 convert other = other
215 collectArgs :: Int -> [String] -> JS -> Maybe ([String], [JS])
215 collectArgs :: Int -> [String] -> JS -> Maybe ([String], [JS])
216− collectArgs 1 acc (JSFunction Nothing [oneArg] (JSBlock js)) | length acc == n - 1 = Just (reverse (oneArg : acc), js)
216+ collectArgs 1 acc (JSFunction _ Nothing [oneArg] (JSBlock _ js)) | length acc == n - 1 = Just (reverse (oneArg : acc), js)
217− collectArgs m acc (JSFunction Nothing [oneArg] (JSBlock [JSReturn ret])) = collectArgs (m - 1) (oneArg : acc) ret
217+ collectArgs m acc (JSFunction _ Nothing [oneArg] (JSBlock _ [JSReturn _ ret])) = collectArgs (m - 1) (oneArg : acc) ret
218 collectArgs _ _ _ = Nothing
218 collectArgs _ _ _ = Nothing
219
219
220 isNFn :: String -> Int -> JS -> Bool
220 isNFn :: String -> Int -> JS -> Bool
221− isNFn prefix n (JSVar name) = name == (prefix ++ show n)
221+ isNFn prefix n (JSVar _ name) = name == (prefix ++ show n)
222− isNFn prefix n (JSAccessor name (JSVar dataFunction)) | dataFunction == C.dataFunction = name == (prefix ++ show n)
222+ isNFn prefix n (JSAccessor _ name (JSVar _ dataFunction)) | dataFunction == C.dataFunction = name == (prefix ++ show n)
223 isNFn _ _ _ = False
223 isNFn _ _ _ = False
224
224
225 runFn :: Int -> JS -> JS
225 runFn :: Int -> JS -> JS
@@ -229,8 +229,8 @@ inlineCommonOperators = applyAll $
229 convert js = fromMaybe js $ go n [] js
229 convert js = fromMaybe js $ go n [] js
230
230
231 go :: Int -> [JS] -> JS -> Maybe JS
231 go :: Int -> [JS] -> JS -> Maybe JS
232− go 0 acc (JSApp runFnN [fn]) | isNFn C.runFn n runFnN && length acc == n = Just (JSApp fn acc)
232+ go 0 acc (JSApp ss runFnN [fn]) | isNFn C.runFn n runFnN && length acc == n = Just (JSApp ss fn acc)
233− go m acc (JSApp lhs [arg]) = go (m - 1) (arg : acc) lhs
233+ go m acc (JSApp _ lhs [arg]) = go (m - 1) (arg : acc) lhs
234 go _ _ _ = Nothing
234 go _ _ _ = Nothing
235
235
236-- (f <<< g $ x) = f (g x)
236-- (f <<< g $ x) = f (g x)
@@ -239,16 +239,16 @@ inlineFnComposition :: (Applicative m, MonadSupply m) => JS -> m JS
239inlineFnComposition = everywhereOnJSTopDownM convert
239inlineFnComposition = everywhereOnJSTopDownM convert
240 where
240 where
241 convert :: (MonadSupply m) => JS -> m JS
241 convert :: (MonadSupply m) => JS -> m JS
242− convert (JSApp (JSApp (JSApp (JSApp fn [dict']) [x]) [y]) [z])
242+ convert (JSApp s1 (JSApp s2 (JSApp _ (JSApp _ fn [dict']) [x]) [y]) [z])
243− | isFnCompose dict' fn = return $ JSApp x [JSApp y [z]]
243+ | isFnCompose dict' fn = return $ JSApp s1 x [JSApp s2 y [z]]
244− | isFnComposeFlipped dict' fn = return $ JSApp y [JSApp x [z]]
244+ | isFnComposeFlipped dict' fn = return $ JSApp s2 y [JSApp s1 x [z]]
245− convert (JSApp (JSApp (JSApp fn [dict']) [x]) [y])
245+ convert (JSApp ss (JSApp _ (JSApp _ fn [dict']) [x]) [y])
246 | isFnCompose dict' fn = do
246 | isFnCompose dict' fn = do
247 arg <- freshName
247 arg <- freshName
248− return $ JSFunction Nothing [arg] (JSBlock [JSReturn $ JSApp x [JSApp y [JSVar arg]]])
248+ return $ JSFunction ss Nothing [arg] (JSBlock ss [JSReturn Nothing $ JSApp Nothing x [JSApp Nothing y [JSVar Nothing arg]]])
249 | isFnComposeFlipped dict' fn = do
249 | isFnComposeFlipped dict' fn = do
250 arg <- freshName
250 arg <- freshName
251− return $ JSFunction Nothing [arg] (JSBlock [JSReturn $ JSApp y [JSApp x [JSVar arg]]])
251+ return $ JSFunction ss Nothing [arg] (JSBlock ss [JSReturn Nothing $ JSApp Nothing y [JSApp Nothing x [JSVar Nothing arg]]])
252 convert other = return other
252 convert other = return other
253 isFnCompose :: JS -> JS -> Bool
253 isFnCompose :: JS -> JS -> Bool
254 isFnCompose dict' fn = isDict' semigroupoidFn dict' && isFn' fnCompose fn
254 isFnCompose dict' fn = isDict' semigroupoidFn dict' && isFn' fnCompose fn
src/Language/PureScript/CodeGen/JS/Optimizer/MagicDo.hs+34−34
@@ -40,46 +40,46 @@ magicDo' = everywhereOnJS undo . everywhereOnJSTopDown convert
40 -- Desugar monomorphic calls to >>= and return for the Eff monad
40 -- Desugar monomorphic calls to >>= and return for the Eff monad
41 convert :: JS -> JS
41 convert :: JS -> JS
42 -- Desugar pure & return
42 -- Desugar pure & return
43− convert (JSApp (JSApp pure' [val]) []) | isPure pure' = val
43+ convert (JSApp _ (JSApp _ pure' [val]) []) | isPure pure' = val
44 -- Desugar >>
44 -- Desugar >>
45− convert (JSApp (JSApp bind [m]) [JSFunction Nothing [] (JSBlock js)]) | isBind bind =
45+ convert (JSApp _ (JSApp _ bind [m]) [JSFunction s1 Nothing [] (JSBlock s2 js)]) | isBind bind =
46− JSFunction (Just fnName) [] $ JSBlock (JSApp m [] : map applyReturns js )
46+ JSFunction s1 (Just fnName) [] $ JSBlock s2 (JSApp s2 m [] : map applyReturns js )
47 -- Desugar >>=
47 -- Desugar >>=
48− convert (JSApp (JSApp bind [m]) [JSFunction Nothing [arg] (JSBlock js)]) | isBind bind =
48+ convert (JSApp _ (JSApp _ bind [m]) [JSFunction s1 Nothing [arg] (JSBlock s2 js)]) | isBind bind =
49− JSFunction (Just fnName) [] $ JSBlock (JSVariableIntroduction arg (Just (JSApp m [])) : map applyReturns js)
49+ JSFunction s1 (Just fnName) [] $ JSBlock s2 (JSVariableIntroduction s2 arg (Just (JSApp s2 m [])) : map applyReturns js)
50 -- Desugar untilE
50 -- Desugar untilE
51− convert (JSApp (JSApp f [arg]) []) | isEffFunc C.untilE f =
51+ convert (JSApp s1 (JSApp _ f [arg]) []) | isEffFunc C.untilE f =
52− JSApp (JSFunction Nothing [] (JSBlock [ JSWhile (JSUnary Not (JSApp arg [])) (JSBlock []), JSReturn $ JSObjectLiteral []])) []
52+ JSApp s1 (JSFunction s1 Nothing [] (JSBlock s1 [ JSWhile s1 (JSUnary s1 Not (JSApp s1 arg [])) (JSBlock s1 []), JSReturn s1 $ JSObjectLiteral s1 []])) []
53 -- Desugar whileE
53 -- Desugar whileE
54− convert (JSApp (JSApp (JSApp f [arg1]) [arg2]) []) | isEffFunc C.whileE f =
54+ convert (JSApp _ (JSApp _ (JSApp s1 f [arg1]) [arg2]) []) | isEffFunc C.whileE f =
55− JSApp (JSFunction Nothing [] (JSBlock [ JSWhile (JSApp arg1 []) (JSBlock [ JSApp arg2 [] ]), JSReturn $ JSObjectLiteral []])) []
55+ JSApp s1 (JSFunction s1 Nothing [] (JSBlock s1 [ JSWhile s1 (JSApp s1 arg1 []) (JSBlock s1 [ JSApp s1 arg2 [] ]), JSReturn s1 $ JSObjectLiteral s1 []])) []
56 convert other = other
56 convert other = other
57 -- Check if an expression represents a monomorphic call to >>= for the Eff monad
57 -- Check if an expression represents a monomorphic call to >>= for the Eff monad
58− isBind (JSApp fn [dict]) | isDict (C.eff, C.bindEffDictionary) dict && isBindPoly fn = True
58+ isBind (JSApp _ fn [dict]) | isDict (C.eff, C.bindEffDictionary) dict && isBindPoly fn = True
59 isBind _ = False
59 isBind _ = False
60 -- Check if an expression represents a monomorphic call to pure or return for the Eff applicative
60 -- Check if an expression represents a monomorphic call to pure or return for the Eff applicative
61− isPure (JSApp fn [dict]) | isDict (C.eff, C.applicativeEffDictionary) dict && isPurePoly fn = True
61+ isPure (JSApp _ fn [dict]) | isDict (C.eff, C.applicativeEffDictionary) dict && isPurePoly fn = True
62 isPure _ = False
62 isPure _ = False
63 -- Check if an expression represents the polymorphic >>= function
63 -- Check if an expression represents the polymorphic >>= function
64 isBindPoly = isFn' [(C.prelude, C.bind), (C.prelude, (C.>>=)), (C.controlBind, C.bind)]
64 isBindPoly = isFn' [(C.prelude, C.bind), (C.prelude, (C.>>=)), (C.controlBind, C.bind)]
65 -- Check if an expression represents the polymorphic pure or return function
65 -- Check if an expression represents the polymorphic pure or return function
66 isPurePoly = isFn' [(C.prelude, C.pure'), (C.prelude, C.return), (C.controlApplicative, C.pure')]
66 isPurePoly = isFn' [(C.prelude, C.pure'), (C.prelude, C.return), (C.controlApplicative, C.pure')]
67 -- Check if an expression represents a function in the Eff module
67 -- Check if an expression represents a function in the Eff module
68− isEffFunc name (JSAccessor name' (JSVar eff)) = eff == C.eff && name == name'
68+ isEffFunc name (JSAccessor _ name' (JSVar _ eff)) = eff == C.eff && name == name'
69 isEffFunc _ _ = False
69 isEffFunc _ _ = False
70
70
71 -- Remove __do function applications which remain after desugaring
71 -- Remove __do function applications which remain after desugaring
72 undo :: JS -> JS
72 undo :: JS -> JS
73− undo (JSReturn (JSApp (JSFunction (Just ident) [] body) [])) | ident == fnName = body
73+ undo (JSReturn _ (JSApp _ (JSFunction _ (Just ident) [] body) [])) | ident == fnName = body
74 undo other = other
74 undo other = other
75
75
76 applyReturns :: JS -> JS
76 applyReturns :: JS -> JS
77− applyReturns (JSReturn ret) = JSReturn (JSApp ret [])
77+ applyReturns (JSReturn ss ret) = JSReturn ss (JSApp ss ret [])
78− applyReturns (JSBlock jss) = JSBlock (map applyReturns jss)
78+ applyReturns (JSBlock ss jss) = JSBlock ss (map applyReturns jss)
79− applyReturns (JSWhile cond js) = JSWhile cond (applyReturns js)
79+ applyReturns (JSWhile ss cond js) = JSWhile ss cond (applyReturns js)
80− applyReturns (JSFor v lo hi js) = JSFor v lo hi (applyReturns js)
80+ applyReturns (JSFor ss v lo hi js) = JSFor ss v lo hi (applyReturns js)
81− applyReturns (JSForIn v xs js) = JSForIn v xs (applyReturns js)
81+ applyReturns (JSForIn ss v xs js) = JSForIn ss v xs (applyReturns js)
82− applyReturns (JSIfElse cond t f) = JSIfElse cond (applyReturns t) (applyReturns `fmap` f)
82+ applyReturns (JSIfElse ss cond t f) = JSIfElse ss cond (applyReturns t) (applyReturns `fmap` f)
83 applyReturns other = other
83 applyReturns other = other
84
84
85-- |
85-- |
@@ -91,7 +91,7 @@ inlineST = everywhereOnJS convertBlock
91 -- Look for runST blocks and inline the STRefs there.
91 -- Look for runST blocks and inline the STRefs there.
92 -- If all STRefs are used in the scope of the same runST, only using { read, write, modify }STRef then
92 -- If all STRefs are used in the scope of the same runST, only using { read, write, modify }STRef then
93 -- we can be more aggressive about inlining, and actually turn STRefs into local variables.
93 -- we can be more aggressive about inlining, and actually turn STRefs into local variables.
94− convertBlock (JSApp f [arg]) | isSTFunc C.runST f =
94+ convertBlock (JSApp _ f [arg]) | isSTFunc C.runST f =
95 let refs = nub . findSTRefsIn $ arg
95 let refs = nub . findSTRefsIn $ arg
96 usages = findAllSTUsagesIn arg
96 usages = findAllSTUsagesIn arg
97 allUsagesAreLocalVars = all (\u -> let v = toVar u in isJust v && fromJust v `elem` refs) usages
97 allUsagesAreLocalVars = all (\u -> let v = toVar u in isJust v && fromJust v `elem` refs) usages
@@ -101,34 +101,34 @@ inlineST = everywhereOnJS convertBlock
101 -- Convert a block in a safe way, preserving object wrappers of references,
101 -- Convert a block in a safe way, preserving object wrappers of references,
102 -- or in a more aggressive way, turning wrappers into local variables depending on the
102 -- or in a more aggressive way, turning wrappers into local variables depending on the
103 -- agg(ressive) parameter.
103 -- agg(ressive) parameter.
104− convert agg (JSApp f [arg]) | isSTFunc C.newSTRef f =
104+ convert agg (JSApp s1 f [arg]) | isSTFunc C.newSTRef f =
105− JSFunction Nothing [] (JSBlock [JSReturn $ if agg then arg else JSObjectLiteral [(C.stRefValue, arg)]])
105+ JSFunction s1 Nothing [] (JSBlock s1 [JSReturn s1 $ if agg then arg else JSObjectLiteral s1 [(C.stRefValue, arg)]])
106− convert agg (JSApp (JSApp f [ref]) []) | isSTFunc C.readSTRef f =
106+ convert agg (JSApp _ (JSApp s1 f [ref]) []) | isSTFunc C.readSTRef f =
107− if agg then ref else JSAccessor C.stRefValue ref
107+ if agg then ref else JSAccessor s1 C.stRefValue ref
108− convert agg (JSApp (JSApp (JSApp f [ref]) [arg]) []) | isSTFunc C.writeSTRef f =
108+ convert agg (JSApp _ (JSApp _ (JSApp s1 f [ref]) [arg]) []) | isSTFunc C.writeSTRef f =
109− if agg then JSAssignment ref arg else JSAssignment (JSAccessor C.stRefValue ref) arg
109+ if agg then JSAssignment s1 ref arg else JSAssignment s1 (JSAccessor s1 C.stRefValue ref) arg
110− convert agg (JSApp (JSApp (JSApp f [ref]) [func]) []) | isSTFunc C.modifySTRef f =
110+ convert agg (JSApp _ (JSApp _ (JSApp s1 f [ref]) [func]) []) | isSTFunc C.modifySTRef f =
111− if agg then JSAssignment ref (JSApp func [ref]) else JSAssignment (JSAccessor C.stRefValue ref) (JSApp func [JSAccessor C.stRefValue ref])
111+ if agg then JSAssignment s1 ref (JSApp s1 func [ref]) else JSAssignment s1 (JSAccessor s1 C.stRefValue ref) (JSApp s1 func [JSAccessor s1 C.stRefValue ref])
112 convert _ other = other
112 convert _ other = other
113 -- Check if an expression represents a function in the ST module
113 -- Check if an expression represents a function in the ST module
114− isSTFunc name (JSAccessor name' (JSVar st)) = st == C.st && name == name'
114+ isSTFunc name (JSAccessor _ name' (JSVar _ st)) = st == C.st && name == name'
115 isSTFunc _ _ = False
115 isSTFunc _ _ = False
116 -- Find all ST Refs initialized in this block
116 -- Find all ST Refs initialized in this block
117 findSTRefsIn = everythingOnJS (++) isSTRef
117 findSTRefsIn = everythingOnJS (++) isSTRef
118 where
118 where
119− isSTRef (JSVariableIntroduction ident (Just (JSApp (JSApp f [_]) []))) | isSTFunc C.newSTRef f = [ident]
119+ isSTRef (JSVariableIntroduction _ ident (Just (JSApp _ (JSApp _ f [_]) []))) | isSTFunc C.newSTRef f = [ident]
120 isSTRef _ = []
120 isSTRef _ = []
121 -- Find all STRefs used as arguments to readSTRef, writeSTRef, modifySTRef
121 -- Find all STRefs used as arguments to readSTRef, writeSTRef, modifySTRef
122 findAllSTUsagesIn = everythingOnJS (++) isSTUsage
122 findAllSTUsagesIn = everythingOnJS (++) isSTUsage
123 where
123 where
124− isSTUsage (JSApp (JSApp f [ref]) []) | isSTFunc C.readSTRef f = [ref]
124+ isSTUsage (JSApp _ (JSApp _ f [ref]) []) | isSTFunc C.readSTRef f = [ref]
125− isSTUsage (JSApp (JSApp (JSApp f [ref]) [_]) []) | isSTFunc C.writeSTRef f || isSTFunc C.modifySTRef f = [ref]
125+ isSTUsage (JSApp _ (JSApp _ (JSApp _ f [ref]) [_]) []) | isSTFunc C.writeSTRef f || isSTFunc C.modifySTRef f = [ref]
126 isSTUsage _ = []
126 isSTUsage _ = []
127 -- Find all uses of a variable
127 -- Find all uses of a variable
128 appearingIn ref = everythingOnJS (++) isVar
128 appearingIn ref = everythingOnJS (++) isVar
129 where
129 where
130− isVar e@(JSVar v) | v == ref = [e]
130+ isVar e@(JSVar _ v) | v == ref = [e]
131 isVar _ = []
131 isVar _ = []
132 -- Convert a JS value to a String if it is a JSVar
132 -- Convert a JS value to a String if it is a JSVar
133− toVar (JSVar v) = Just v
133+ toVar (JSVar _ v) = Just v
134 toVar _ = Nothing
134 toVar _ = Nothing
src/Language/PureScript/CodeGen/JS/Optimizer/TCO.hs+33−31
@@ -40,7 +40,7 @@ tco' = everywhereOnJS convert
40 copyVar arg = "__copy_" ++ arg
40 copyVar arg = "__copy_" ++ arg
41
41
42 convert :: JS -> JS
42 convert :: JS -> JS
43− convert js@(JSVariableIntroduction name (Just fn@JSFunction {})) =
43+ convert js@(JSVariableIntroduction ss name (Just fn@JSFunction {})) =
44 let
44 let
45 (argss, body', replace) = collectAllFunctionArgs [] id fn
45 (argss, body', replace) = collectAllFunctionArgs [] id fn
46 in case () of
46 in case () of
@@ -48,19 +48,19 @@ tco' = everywhereOnJS convert
48 let
48 let
49 allArgs = concat $ reverse argss
49 allArgs = concat $ reverse argss
50 in
50 in
51− JSVariableIntroduction name (Just (replace (toLoop name allArgs body')))
51+ JSVariableIntroduction ss name (Just (replace (toLoop name allArgs body')))
52 | otherwise -> js
52 | otherwise -> js
53 convert js = js
53 convert js = js
54
54
55 collectAllFunctionArgs :: [[String]] -> (JS -> JS) -> JS -> ([[String]], JS, JS -> JS)
55 collectAllFunctionArgs :: [[String]] -> (JS -> JS) -> JS -> ([[String]], JS, JS -> JS)
56− collectAllFunctionArgs allArgs f (JSFunction ident args (JSBlock (body@(JSReturn _):_))) =
56+ collectAllFunctionArgs allArgs f (JSFunction s1 ident args (JSBlock s2 (body@(JSReturn _ _):_))) =
57− collectAllFunctionArgs (args : allArgs) (\b -> f (JSFunction ident (map copyVar args) (JSBlock [b]))) body
57+ collectAllFunctionArgs (args : allArgs) (\b -> f (JSFunction s1 ident (map copyVar args) (JSBlock s2 [b]))) body
58− collectAllFunctionArgs allArgs f (JSFunction ident args body@(JSBlock _)) =
58+ collectAllFunctionArgs allArgs f (JSFunction ss ident args body@(JSBlock _ _)) =
59− (args : allArgs, body, f . JSFunction ident (map copyVar args))
59+ (args : allArgs, body, f . JSFunction ss ident (map copyVar args))
60− collectAllFunctionArgs allArgs f (JSReturn (JSFunction ident args (JSBlock [body]))) =
60+ collectAllFunctionArgs allArgs f (JSReturn s1 (JSFunction s2 ident args (JSBlock s3 [body]))) =
61− collectAllFunctionArgs (args : allArgs) (\b -> f (JSReturn (JSFunction ident (map copyVar args) (JSBlock [b])))) body
61+ collectAllFunctionArgs (args : allArgs) (\b -> f (JSReturn s1 (JSFunction s2 ident (map copyVar args) (JSBlock s3 [b])))) body
62− collectAllFunctionArgs allArgs f (JSReturn (JSFunction ident args body@(JSBlock _))) =
62+ collectAllFunctionArgs allArgs f (JSReturn s1 (JSFunction s2 ident args body@(JSBlock _ _))) =
63− (args : allArgs, body, f . JSReturn . JSFunction ident (map copyVar args))
63+ (args : allArgs, body, f . JSReturn s1 . JSFunction s2 ident (map copyVar args))
64 collectAllFunctionArgs allArgs f body = (allArgs, body, f)
64 collectAllFunctionArgs allArgs f body = (allArgs, body, f)
65
65
66 isTailCall :: String -> JS -> Bool
66 isTailCall :: String -> JS -> Bool
@@ -77,51 +77,53 @@ tco' = everywhereOnJS convert
77 && numSelfCallWithFnArgs == 0
77 && numSelfCallWithFnArgs == 0
78 where
78 where
79 countSelfCalls :: JS -> Int
79 countSelfCalls :: JS -> Int
80− countSelfCalls (JSApp (JSVar ident') _) | ident == ident' = 1
80+ countSelfCalls (JSApp _ (JSVar _ ident') _) | ident == ident' = 1
81 countSelfCalls _ = 0
81 countSelfCalls _ = 0
82−
82+
83 countSelfCallsInTailPosition :: JS -> Int
83 countSelfCallsInTailPosition :: JS -> Int
84− countSelfCallsInTailPosition (JSReturn ret) | isSelfCall ident ret = 1
84+ countSelfCallsInTailPosition (JSReturn _ ret) | isSelfCall ident ret = 1
85 countSelfCallsInTailPosition _ = 0
85 countSelfCallsInTailPosition _ = 0
86−
86+
87 countSelfCallsUnderFunctions :: JS -> Int
87 countSelfCallsUnderFunctions :: JS -> Int
88− countSelfCallsUnderFunctions (JSFunction _ _ js') = everythingOnJS (+) countSelfCalls js'
88+ countSelfCallsUnderFunctions (JSFunction _ _ _ js') = everythingOnJS (+) countSelfCalls js'
89 countSelfCallsUnderFunctions _ = 0
89 countSelfCallsUnderFunctions _ = 0
90−
90+
91 countSelfCallsWithFnArgs :: JS -> Int
91 countSelfCallsWithFnArgs :: JS -> Int
92 countSelfCallsWithFnArgs ret = if isSelfCallWithFnArgs ident ret [] then 1 else 0
92 countSelfCallsWithFnArgs ret = if isSelfCallWithFnArgs ident ret [] then 1 else 0
93
93
94 toLoop :: String -> [String] -> JS -> JS
94 toLoop :: String -> [String] -> JS -> JS
95− toLoop ident allArgs js = JSBlock $
95+ toLoop ident allArgs js = JSBlock rootSS $
96− map (\arg -> JSVariableIntroduction arg (Just (JSVar (copyVar arg)))) allArgs ++
96+ map (\arg -> JSVariableIntroduction rootSS arg (Just (JSVar rootSS (copyVar arg)))) allArgs ++
97− [ JSLabel tcoLabel $ JSWhile (JSBooleanLiteral True) (JSBlock [ everywhereOnJS loopify js ]) ]
97+ [ JSLabel rootSS tcoLabel $ JSWhile rootSS (JSBooleanLiteral rootSS True) (JSBlock rootSS [ everywhereOnJS loopify js ]) ]
98 where
98 where
99+ rootSS = Nothing
100+
99 loopify :: JS -> JS
101 loopify :: JS -> JS
100− loopify (JSReturn ret) | isSelfCall ident ret =
102+ loopify (JSReturn ss ret) | isSelfCall ident ret =
101 let
103 let
102 allArgumentValues = concat $ collectSelfCallArgs [] ret
104 allArgumentValues = concat $ collectSelfCallArgs [] ret
103 in
105 in
104− JSBlock $ zipWith (\val arg ->
106+ JSBlock ss $ zipWith (\val arg ->
105− JSVariableIntroduction (tcoVar arg) (Just val)) allArgumentValues allArgs
107+ JSVariableIntroduction ss (tcoVar arg) (Just val)) allArgumentValues allArgs
106 ++ map (\arg ->
108 ++ map (\arg ->
107− JSAssignment (JSVar arg) (JSVar (tcoVar arg))) allArgs
109+ JSAssignment ss (JSVar ss arg) (JSVar ss (tcoVar arg))) allArgs
108− ++ [ JSContinue tcoLabel ]
110+ ++ [ JSContinue ss tcoLabel ]
109 loopify other = other
111 loopify other = other
110 collectSelfCallArgs :: [[JS]] -> JS -> [[JS]]
112 collectSelfCallArgs :: [[JS]] -> JS -> [[JS]]
111− collectSelfCallArgs allArgumentValues (JSApp fn args') = collectSelfCallArgs (args' : allArgumentValues) fn
113+ collectSelfCallArgs allArgumentValues (JSApp _ fn args') = collectSelfCallArgs (args' : allArgumentValues) fn
112 collectSelfCallArgs allArgumentValues _ = allArgumentValues
114 collectSelfCallArgs allArgumentValues _ = allArgumentValues
113
115
114 isSelfCall :: String -> JS -> Bool
116 isSelfCall :: String -> JS -> Bool
115− isSelfCall ident (JSApp (JSVar ident') _) = ident == ident'
117+ isSelfCall ident (JSApp _ (JSVar _ ident') _) = ident == ident'
116− isSelfCall ident (JSApp fn _) = isSelfCall ident fn
118+ isSelfCall ident (JSApp _ fn _) = isSelfCall ident fn
117 isSelfCall _ _ = False
119 isSelfCall _ _ = False
118
120
119 isSelfCallWithFnArgs :: String -> JS -> [JS] -> Bool
121 isSelfCallWithFnArgs :: String -> JS -> [JS] -> Bool
120− isSelfCallWithFnArgs ident (JSVar ident') args | ident == ident' && any hasFunction args = True
122+ isSelfCallWithFnArgs ident (JSVar _ ident') args | ident == ident' && any hasFunction args = True
121− isSelfCallWithFnArgs ident (JSApp fn args) acc = isSelfCallWithFnArgs ident fn (args ++ acc)
123+ isSelfCallWithFnArgs ident (JSApp _ fn args) acc = isSelfCallWithFnArgs ident fn (args ++ acc)
122 isSelfCallWithFnArgs _ _ _ = False
124 isSelfCallWithFnArgs _ _ _ = False
123−
125+
124− hasFunction :: JS -> Bool
126+ hasFunction :: JS -> Bool
125 hasFunction = getAny . everythingOnJS mappend (Any . isFunction)
127 hasFunction = getAny . everythingOnJS mappend (Any . isFunction)
126 where
128 where
127 isFunction JSFunction{} = True
129 isFunction JSFunction{} = True
src/Language/PureScript/CodeGen/JS/Optimizer/Unused.hs+3−3
@@ -30,17 +30,17 @@ removeCodeAfterReturnStatements = everywhereOnJS (removeFromBlock go)
30 go :: [JS] -> [JS]
30 go :: [JS] -> [JS]
31 go jss | not (any isJSReturn jss) = jss
31 go jss | not (any isJSReturn jss) = jss
32 | otherwise = let (body, ret : _) = break isJSReturn jss in body ++ [ret]
32 | otherwise = let (body, ret : _) = break isJSReturn jss in body ++ [ret]
33− isJSReturn (JSReturn _) = True
33+ isJSReturn (JSReturn _ _) = True
34 isJSReturn _ = False
34 isJSReturn _ = False
35
35
36removeUnusedArg :: JS -> JS
36removeUnusedArg :: JS -> JS
37removeUnusedArg = everywhereOnJS convert
37removeUnusedArg = everywhereOnJS convert
38 where
38 where
39− convert (JSFunction name [arg] body) | arg == C.__unused = JSFunction name [] body
39+ convert (JSFunction ss name [arg] body) | arg == C.__unused = JSFunction ss name [] body
40 convert js = js
40 convert js = js
41
41
42removeUndefinedApp :: JS -> JS
42removeUndefinedApp :: JS -> JS
43removeUndefinedApp = everywhereOnJS convert
43removeUndefinedApp = everywhereOnJS convert
44 where
44 where
45− convert (JSApp fn [JSVar arg]) | arg == C.undefined = JSApp fn []
45+ convert (JSApp ss fn [JSVar _ arg]) | arg == C.undefined = JSApp ss fn []
46 convert js = js
46 convert js = js
src/Language/PureScript/CoreFn/Binders.hs+9−2
@@ -31,5 +31,12 @@ data Binder a
31 -- |
31 -- |
32 -- A binder which binds its input to an identifier
32 -- A binder which binds its input to an identifier
33 --
33 --
34− | NamedBinder a Ident (Binder a)
34+ | NamedBinder a Ident (Binder a) deriving (Show, Read, Functor)
35− deriving (Show, Read, Functor)
35+
36+
37+extractBinderAnn :: Binder a -> a
38+extractBinderAnn (NullBinder a) = a
39+extractBinderAnn (LiteralBinder a _) = a
40+extractBinderAnn (VarBinder a _) = a
41+extractBinderAnn (ConstructorBinder a _ _ _) = a
42+extractBinderAnn (NamedBinder a _ _) = a
src/Language/PureScript/CoreFn/Desugar.hs+36−17
@@ -1,5 +1,9 @@
1module Language.PureScript.CoreFn.Desugar (moduleToCoreFn) where
1module Language.PureScript.CoreFn.Desugar (moduleToCoreFn) where
2
2
3+import Prelude ()
4+import Prelude.Compat
5+
6+
3import Data.Function (on)
7import Data.Function (on)
4import Data.List (sort, sortBy, nub)
8import Data.List (sort, sortBy, nub)
5import Data.Maybe (mapMaybe)
9import Data.Maybe (mapMaybe)
@@ -30,38 +34,52 @@ moduleToCoreFn :: Environment -> A.Module -> Module Ann
30moduleToCoreFn _ (A.Module _ _ _ _ Nothing) =
34moduleToCoreFn _ (A.Module _ _ _ _ Nothing) =
31 internalError "Module exports were not elaborated before moduleToCoreFn"
35 internalError "Module exports were not elaborated before moduleToCoreFn"
32moduleToCoreFn env (A.Module _ coms mn decls (Just exps)) =
36moduleToCoreFn env (A.Module _ coms mn decls (Just exps)) =
33− let imports = nub $ mapMaybe importToCoreFn decls ++ findQualModules decls
37+ let imports = mapMaybe importToCoreFn decls ++ findQualModules decls
38+ imports' = nub $ filter (keepImp imports) imports-- TODO could be more efficient
34 exps' = nub $ concatMap exportToCoreFn exps
39 exps' = nub $ concatMap exportToCoreFn exps
35 externs = nub $ mapMaybe externToCoreFn decls
40 externs = nub $ mapMaybe externToCoreFn decls
36 decls' = concatMap (declToCoreFn Nothing []) decls
41 decls' = concatMap (declToCoreFn Nothing []) decls
37− in Module coms mn imports exps' externs decls'
42+ in Module coms mn imports' exps' externs decls'
38
43
39 where
44 where
40
45
46+ -- Remove duplicate imports favoring the one containing sourcespan info
47+ keepImp :: [(Ann, ModuleName)] -> (Ann, ModuleName) -> Bool
48+ keepImp imps (a, i) = hasSS a || not (any hasDup imps)
49+ where
50+ hasDup (a', i') = i == i' && hasSS a'
51+
52+ hasSS :: Ann -> Bool
53+ hasSS (Just _, _, _, _) = True
54+ hasSS _ = False
55+
56+ ssA :: Maybe SourceSpan -> Ann
57+ ssA ss = (ss, [], Nothing, Nothing)
58+
41 -- |
59 -- |
42 -- Desugars member declarations from AST to CoreFn representation.
60 -- Desugars member declarations from AST to CoreFn representation.
43 --
61 --
44 declToCoreFn :: Maybe SourceSpan -> [Comment] -> A.Declaration -> [Bind Ann]
62 declToCoreFn :: Maybe SourceSpan -> [Comment] -> A.Declaration -> [Bind Ann]
45 declToCoreFn ss com (A.DataDeclaration Newtype _ _ [(ctor, _)]) =
63 declToCoreFn ss com (A.DataDeclaration Newtype _ _ [(ctor, _)]) =
46− [NonRec (properToIdent ctor) $
64+ [NonRec (ssA ss) (properToIdent ctor) $
47 Abs (ss, com, Nothing, Just IsNewtype) (Ident "x") (Var nullAnn $ Qualified Nothing (Ident "x"))]
65 Abs (ss, com, Nothing, Just IsNewtype) (Ident "x") (Var nullAnn $ Qualified Nothing (Ident "x"))]
48 declToCoreFn _ _ d@(A.DataDeclaration Newtype _ _ _) =
66 declToCoreFn _ _ d@(A.DataDeclaration Newtype _ _ _) =
49 error $ "Found newtype with multiple constructors: " ++ show d
67 error $ "Found newtype with multiple constructors: " ++ show d
50 declToCoreFn ss com (A.DataDeclaration Data tyName _ ctors) =
68 declToCoreFn ss com (A.DataDeclaration Data tyName _ ctors) =
51 flip map ctors $ \(ctor, _) ->
69 flip map ctors $ \(ctor, _) ->
52 let (_, _, _, fields) = lookupConstructor env (Qualified (Just mn) ctor)
70 let (_, _, _, fields) = lookupConstructor env (Qualified (Just mn) ctor)
53− in NonRec (properToIdent ctor) $ Constructor (ss, com, Nothing, Nothing) tyName ctor fields
71+ in NonRec (ssA ss) (properToIdent ctor) $ Constructor (ss, com, Nothing, Nothing) tyName ctor fields
54 declToCoreFn ss _ (A.DataBindingGroupDeclaration ds) = concatMap (declToCoreFn ss []) ds
72 declToCoreFn ss _ (A.DataBindingGroupDeclaration ds) = concatMap (declToCoreFn ss []) ds
55 declToCoreFn ss com (A.ValueDeclaration name _ _ (Right e)) =
73 declToCoreFn ss com (A.ValueDeclaration name _ _ (Right e)) =
56− [NonRec name (exprToCoreFn ss com Nothing e)]
74+ [NonRec (ssA ss) name (exprToCoreFn ss com Nothing e)]
57 declToCoreFn ss com (A.FixityDeclaration _ name (Just alias)) =
75 declToCoreFn ss com (A.FixityDeclaration _ name (Just alias)) =
58 let meta = either getValueMeta (Just . getConstructorMeta) alias
76 let meta = either getValueMeta (Just . getConstructorMeta) alias
59 alias' = either id (fmap properToIdent) alias
77 alias' = either id (fmap properToIdent) alias
60− in [NonRec (Op name) (Var (ss, com, Nothing, meta) alias')]
78+ in [NonRec (ssA ss) (Op name) (Var (ss, com, Nothing, meta) alias')]
61 declToCoreFn ss _ (A.BindingGroupDeclaration ds) =
79 declToCoreFn ss _ (A.BindingGroupDeclaration ds) =
62− [Rec $ map (\(name, _, e) -> (name, exprToCoreFn ss [] Nothing e)) ds]
80+ [Rec $ map (\(name, _, e) -> ((ssA ss, name), exprToCoreFn ss [] Nothing e)) ds]
63 declToCoreFn ss com (A.TypeClassDeclaration name _ supers members) =
81 declToCoreFn ss com (A.TypeClassDeclaration name _ supers members) =
64− [NonRec (properToIdent name) $ mkTypeClassConstructor ss com supers members]
82+ [NonRec (ssA ss) (properToIdent name) $ mkTypeClassConstructor ss com supers members]
65 declToCoreFn _ com (A.PositionedDeclaration ss com1 d) =
83 declToCoreFn _ com (A.PositionedDeclaration ss com1 d) =
66 declToCoreFn (Just ss) (com ++ com1) d
84 declToCoreFn (Just ss) (com ++ com1) d
67 declToCoreFn _ _ _ = []
85 declToCoreFn _ _ _ = []
@@ -203,35 +221,36 @@ moduleToCoreFn env (A.Module _ coms mn decls (Just exps)) =
203-- ensure instances are imported from any module that is referenced by the
221-- ensure instances are imported from any module that is referenced by the
204-- current module, not just from those that are imported explicitly (#667).
222-- current module, not just from those that are imported explicitly (#667).
205--
223--
206−findQualModules :: [A.Declaration] -> [ModuleName]
224+findQualModules :: [A.Declaration] -> [(Ann, ModuleName)]
207findQualModules decls =
225findQualModules decls =
208 let (f, _, _, _, _) = everythingOnValues (++) fqDecls fqValues fqBinders (const []) (const [])
226 let (f, _, _, _, _) = everythingOnValues (++) fqDecls fqValues fqBinders (const []) (const [])
209 in f `concatMap` decls
227 in f `concatMap` decls
210 where
228 where
211− fqDecls :: A.Declaration -> [ModuleName]
229+ fqDecls :: A.Declaration -> [(Ann, ModuleName)]
212 fqDecls (A.TypeInstanceDeclaration _ _ q _ _) = getQual q
230 fqDecls (A.TypeInstanceDeclaration _ _ q _ _) = getQual q
213 fqDecls (A.FixityDeclaration _ _ (Just eq)) = either getQual getQual eq
231 fqDecls (A.FixityDeclaration _ _ (Just eq)) = either getQual getQual eq
214 fqDecls _ = []
232 fqDecls _ = []
215
233
216− fqValues :: A.Expr -> [ModuleName]
234+ fqValues :: A.Expr -> [(Ann, ModuleName)]
217 fqValues (A.Var q) = getQual q
235 fqValues (A.Var q) = getQual q
218 fqValues (A.Constructor q) = getQual q
236 fqValues (A.Constructor q) = getQual q
219 fqValues _ = []
237 fqValues _ = []
220
238
221− fqBinders :: A.Binder -> [ModuleName]
239+ fqBinders :: A.Binder -> [(Ann, ModuleName)]
222 fqBinders (A.ConstructorBinder q _) = getQual q
240 fqBinders (A.ConstructorBinder q _) = getQual q
223 fqBinders _ = []
241 fqBinders _ = []
224
242
225− getQual :: Qualified a -> [ModuleName]
243+ getQual :: Qualified a -> [(Ann, ModuleName)]
226− getQual (Qualified (Just mn) _) = [mn]
244+ getQual (Qualified (Just mn) _) = [(nullAnn, mn)]
227 getQual _ = []
245 getQual _ = []
228
246
229-- |
247-- |
230-- Desugars import declarations from AST to CoreFn representation.
248-- Desugars import declarations from AST to CoreFn representation.
231--
249--
232−importToCoreFn :: A.Declaration -> Maybe ModuleName
250+importToCoreFn :: A.Declaration -> Maybe (Ann, ModuleName)
233−importToCoreFn (A.ImportDeclaration name _ _ _) = Just name
251+importToCoreFn (A.ImportDeclaration name _ _ _) = Just (nullAnn, name)
234−importToCoreFn (A.PositionedDeclaration _ _ d) = importToCoreFn d
252+importToCoreFn (A.PositionedDeclaration ss _ d) =
253+ ((,) (Just ss, [], Nothing, Nothing) . snd) <$> importToCoreFn d
235importToCoreFn _ = Nothing
254importToCoreFn _ = Nothing
236
255
237-- |
256-- |
src/Language/PureScript/CoreFn/Expr.hs+3−5
@@ -60,12 +60,11 @@ data Bind a
60 -- |
60 -- |
61 -- Non-recursive binding for a single value
61 -- Non-recursive binding for a single value
62 --
62 --
63− = NonRec Ident (Expr a)
63+ = NonRec a Ident (Expr a)
64 -- |
64 -- |
65 -- Mutually recursive binding group for several values
65 -- Mutually recursive binding group for several values
66 --
66 --
67− | Rec [(Ident, Expr a)]
68− deriving (Show, Read, Functor)
67+ | Rec [((a, Ident), Expr a)] deriving (Show, Read, Functor)
69
68
70-- |
69-- |
71-- A guard is just a boolean-valued expression that appears alongside a set of binders
70-- A guard is just a boolean-valued expression that appears alongside a set of binders
@@ -84,8 +83,7 @@ data CaseAlternative a = CaseAlternative
84 -- The result expression or a collect of guarded expressions
83 -- The result expression or a collect of guarded expressions
85 --
84 --
86 , caseAlternativeResult :: Either [(Guard a, Expr a)] (Expr a)
85 , caseAlternativeResult :: Either [(Guard a, Expr a)] (Expr a)
87− }
88− deriving (Show, Read)
86+ } deriving (Show, Read)
89
87
90instance Functor CaseAlternative where
88instance Functor CaseAlternative where
91
89
src/Language/PureScript/CoreFn/Meta.hs+2−4
@@ -24,8 +24,7 @@ data Meta
24 -- |
24 -- |
25 -- The contained reference is for a foreign member
25 -- The contained reference is for a foreign member
26 --
26 --
27− | IsForeign
28− deriving (Show, Read)
27+ | IsForeign deriving (Show, Read, Eq)
29
28
30-- |
29-- |
31-- Data constructor metadata
30-- Data constructor metadata
@@ -38,5 +37,4 @@ data ConstructorType
38 -- |
37 -- |
39 -- The constructor is for a type with multiple construcors
38 -- The constructor is for a type with multiple construcors
40 --
39 --
41− | SumType
42− deriving (Show, Read)
40+ | SumType deriving (Show, Read, Eq)
src/Language/PureScript/CoreFn/Module.hs+1−1
@@ -22,7 +22,7 @@ import Language.PureScript.Types
22data Module a = Module
22data Module a = Module
23 { moduleComments :: [Comment]
23 { moduleComments :: [Comment]
24 , moduleName :: ModuleName
24 , moduleName :: ModuleName
25− , moduleImports :: [ModuleName]
25+ , moduleImports :: [(a, ModuleName)]
26 , moduleExports :: [Ident]
26 , moduleExports :: [Ident]
27 , moduleForeign :: [ForeignDecl]
27 , moduleForeign :: [ForeignDecl]
28 , moduleDecls :: [Bind a]
28 , moduleDecls :: [Bind a]
src/Language/PureScript/CoreFn/Traversals.hs+2−2
@@ -26,7 +26,7 @@ everywhereOnValues :: (Bind a -> Bind a) ->
26 (Bind a -> Bind a, Expr a -> Expr a, Binder a -> Binder a)
26 (Bind a -> Bind a, Expr a -> Expr a, Binder a -> Binder a)
27everywhereOnValues f g h = (f', g', h')
27everywhereOnValues f g h = (f', g', h')
28 where
28 where
29− f' (NonRec name e) = f (NonRec name (g' e))
29+ f' (NonRec a name e) = f (NonRec a name (g' e))
30 f' (Rec es) = f (Rec (map (second g') es))
30 f' (Rec es) = f (Rec (map (second g') es))
31
31
32 g' (Literal ann e) = g (Literal ann (handleLiteral g' e))
32 g' (Literal ann e) = g (Literal ann (handleLiteral g' e))
@@ -61,7 +61,7 @@ everythingOnValues :: (r -> r -> r) ->
61 (Bind a -> r, Expr a -> r, Binder a -> r, CaseAlternative a -> r)
61 (Bind a -> r, Expr a -> r, Binder a -> r, CaseAlternative a -> r)
62everythingOnValues (<>) f g h i = (f', g', h', i')
62everythingOnValues (<>) f g h i = (f', g', h', i')
63 where
63 where
64− f' b@(NonRec _ e) = f b <> g' e
64+ f' b@(NonRec _ _ e) = f b <> g' e
65 f' b@(Rec es) = foldl (<>) (f b) (map (g' . snd) es)
65 f' b@(Rec es) = foldl (<>) (f b) (map (g' . snd) es)
66
66
67 g' v@(Literal _ l) = foldl (<>) (g v) (map g' (extractLiteral l))
67 g' v@(Literal _ l) = foldl (<>) (g v) (map g' (extractLiteral l))
src/Language/PureScript/Docs/Convert/ReExports.hs+3−3
@@ -155,16 +155,16 @@ collectDeclarations imports exports = do
155--
155--
156findImport ::
156findImport ::
157 (Show name, Eq name, Applicative m, MonadReader P.ModuleName m) =>
157 (Show name, Eq name, Applicative m, MonadReader P.ModuleName m) =>
158− [(P.Qualified name, P.ModuleName)] ->
158+ [P.ImportRecord name] ->
159 (name, P.ModuleName) ->
159 (name, P.ModuleName) ->
160 m (P.ModuleName, name)
160 m (P.ModuleName, name)
161findImport imps (name, orig) =
161findImport imps (name, orig) =
162 let
162 let
163− matches (qual, mn) = P.disqualify qual == name && mn == orig
163+ matches (P.ImportRecord qual mn _) = P.disqualify qual == name && mn == orig
164 matching = filter matches imps
164 matching = filter matches imps
165 getQualified (P.Qualified mname _) = mname
165 getQualified (P.Qualified mname _) = mname
166 in
166 in
167− case mapMaybe (getQualified . fst) matching of
167+ case mapMaybe (getQualified . P.importName) matching of
168 -- A value can occur more than once if it is imported twice (eg, if it is
168 -- A value can occur more than once if it is imported twice (eg, if it is
169 -- exported by A, re-exported from A by B, and C imports it from both A
169 -- exported by A, re-exported from A by B, and C imports it from both A
170 -- and B). In this case, we just take its first appearance.
170 -- and B). In this case, we just take its first appearance.
src/Language/PureScript/Errors.hs+9
@@ -69,6 +69,7 @@ data SimpleErrorMessage
69 | UnknownImportDataConstructor ModuleName (ProperName 'TypeName) (ProperName 'ConstructorName)
69 | UnknownImportDataConstructor ModuleName (ProperName 'TypeName) (ProperName 'ConstructorName)
70 | UnknownExportDataConstructor (ProperName 'TypeName) (ProperName 'ConstructorName)
70 | UnknownExportDataConstructor (ProperName 'TypeName) (ProperName 'ConstructorName)
71 | ScopeConflict String [ModuleName]
71 | ScopeConflict String [ModuleName]
72+ | ScopeShadowing String (Maybe ModuleName) [ModuleName]
72 | ConflictingTypeDecls (ProperName 'TypeName)
73 | ConflictingTypeDecls (ProperName 'TypeName)
73 | ConflictingCtorDecls (ProperName 'ConstructorName)
74 | ConflictingCtorDecls (ProperName 'ConstructorName)
74 | TypeConflictsWithClass (ProperName 'TypeName)
75 | TypeConflictsWithClass (ProperName 'TypeName)
@@ -248,6 +249,7 @@ errorCode em = case unwrapErrorMessage em of
248 UnknownImportDataConstructor{} -> "UnknownImportDataConstructor"
249 UnknownImportDataConstructor{} -> "UnknownImportDataConstructor"
249 UnknownExportDataConstructor{} -> "UnknownExportDataConstructor"
250 UnknownExportDataConstructor{} -> "UnknownExportDataConstructor"
250 ScopeConflict{} -> "ScopeConflict"
251 ScopeConflict{} -> "ScopeConflict"
252+ ScopeShadowing{} -> "ScopeShadowing"
251 ConflictingTypeDecls{} -> "ConflictingTypeDecls"
253 ConflictingTypeDecls{} -> "ConflictingTypeDecls"
252 ConflictingCtorDecls{} -> "ConflictingCtorDecls"
254 ConflictingCtorDecls{} -> "ConflictingCtorDecls"
253 TypeConflictsWithClass{} -> "TypeConflictsWithClass"
255 TypeConflictsWithClass{} -> "TypeConflictsWithClass"
@@ -604,6 +606,13 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
604 paras [ line $ "Conflicting definitions are in scope for " ++ nm ++ " from the following modules:"
606 paras [ line $ "Conflicting definitions are in scope for " ++ nm ++ " from the following modules:"
605 , indent $ paras $ map (line . runModuleName) ms
607 , indent $ paras $ map (line . runModuleName) ms
606 ]
608 ]
609+ renderSimpleErrorMessage (ScopeShadowing nm exmn ms) =
610+ paras [ line $ "Shadowed definitions are in scope for " ++ nm ++ " from the following open imports:"
611+ , indent $ paras $ map (line . ("import " ++) . runModuleName) ms
612+ , line $ "These will be ignored and the " ++ case exmn of
613+ Just exmn' -> "declaration from " ++ runModuleName exmn' ++ " will be used."
614+ Nothing -> "local declaration will be used."
615+ ]
607 renderSimpleErrorMessage (ConflictingTypeDecls nm) =
616 renderSimpleErrorMessage (ConflictingTypeDecls nm) =
608 line $ "Conflicting type declarations for " ++ runProperName nm
617 line $ "Conflicting type declarations for " ++ runProperName nm
609 renderSimpleErrorMessage (ConflictingCtorDecls nm) =
618 renderSimpleErrorMessage (ConflictingCtorDecls nm) =
src/Language/PureScript/Ide.hsnew file+199
@@ -0,0 +1,199 @@
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE MultiParamTypeClasses #-}
4+{-# LANGUAGE OverloadedStrings #-}
5+{-# LANGUAGE PackageImports #-}
6+{-# LANGUAGE TemplateHaskell #-}
7+{-# LANGUAGE TupleSections #-}
8+
9+module Language.PureScript.Ide where
10+
11+import Prelude ()
12+import Prelude.Compat
13+
14+import Control.Monad.Error.Class
15+import Control.Monad.IO.Class
16+import "monad-logger" Control.Monad.Logger
17+import Control.Monad.Reader.Class
18+import Data.Foldable
19+import qualified Data.Map.Lazy as M
20+import Data.Maybe (catMaybes, mapMaybe)
21+import Data.Monoid
22+import Data.Text (Text)
23+import qualified Data.Text as T
24+import qualified Language.PureScript.Ide.CaseSplit as CS
25+import Language.PureScript.Ide.Command
26+import Language.PureScript.Ide.Completion
27+import Language.PureScript.Ide.Error
28+import Language.PureScript.Ide.Externs
29+import Language.PureScript.Ide.Filter
30+import Language.PureScript.Ide.Matcher
31+import Language.PureScript.Ide.Pursuit
32+import Language.PureScript.Ide.Reexports
33+import Language.PureScript.Ide.SourceFile
34+import Language.PureScript.Ide.State
35+import Language.PureScript.Ide.Types
36+import System.Directory
37+import System.FilePath
38+import System.Exit
39+
40+
41+handleCommand :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
42+ Command -> m Success
43+handleCommand (Load modules deps) =
44+ loadModulesAndDeps modules deps
45+handleCommand (Type search filters) =
46+ findType search filters
47+handleCommand (Complete filters matcher) =
48+ findCompletions filters matcher
49+handleCommand (Pursuit query Package) =
50+ findPursuitPackages query
51+handleCommand (Pursuit query Identifier) =
52+ findPursuitCompletions query
53+handleCommand (List LoadedModules) =
54+ printModules
55+handleCommand (List AvailableModules) =
56+ listAvailableModules
57+handleCommand (List (Imports fp)) =
58+ importsForFile fp
59+handleCommand (CaseSplit l b e wca t) =
60+ caseSplit l b e wca t
61+handleCommand (AddClause l wca) =
62+ pure $ addClause l wca
63+handleCommand Cwd =
64+ TextResult . T.pack <$> liftIO getCurrentDirectory
65+handleCommand Quit = liftIO exitSuccess
66+
67+findCompletions :: (PscIde m, MonadLogger m) =>
68+ [Filter] -> Matcher -> m Success
69+findCompletions filters matcher =
70+ CompletionResult . getCompletions filters matcher <$> getAllModulesWithReexports
71+
72+findType :: (PscIde m, MonadLogger m) =>
73+ DeclIdent -> [Filter] -> m Success
74+findType search filters =
75+ CompletionResult . getExactMatches search filters <$> getAllModulesWithReexports
76+
77+findPursuitCompletions :: (Applicative m, MonadIO m, MonadLogger m) =>
78+ PursuitQuery -> m Success
79+findPursuitCompletions (PursuitQuery q) =
80+ PursuitResult <$> liftIO (searchPursuitForDeclarations q)
81+
82+findPursuitPackages :: (Applicative m, MonadIO m, MonadLogger m) =>
83+ PursuitQuery -> m Success
84+findPursuitPackages (PursuitQuery q) =
85+ PursuitResult <$> liftIO (findPackagesForModuleIdent q)
86+
87+loadExtern ::(PscIde m, MonadLogger m, MonadError PscIdeError m) =>
88+ FilePath -> m ()
89+loadExtern fp = do
90+ m <- readExternFile fp
91+ insertModule m
92+
93+printModules :: (PscIde m) => m Success
94+printModules = printModules' <$> getPscIdeState
95+
96+printModules' :: M.Map ModuleIdent [ExternDecl] -> Success
97+printModules' = ModuleList . M.keys
98+
99+listAvailableModules :: PscIde m => m Success
100+listAvailableModules = do
101+ outputPath <- confOutputPath . envConfiguration <$> ask
102+ liftIO $ do
103+ cwd <- getCurrentDirectory
104+ dirs <- getDirectoryContents (cwd </> outputPath)
105+ return (ModuleList (listAvailableModules' dirs))
106+
107+listAvailableModules' :: [FilePath] -> [Text]
108+listAvailableModules' dirs =
109+ let cleanedModules = filter (`notElem` [".", ".."]) dirs
110+ in map T.pack cleanedModules
111+
112+caseSplit :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
113+ Text -> Int -> Int -> CS.WildcardAnnotations -> Text -> m Success
114+caseSplit l b e csa t = do
115+ patterns <- CS.makePattern l b e csa <$> CS.caseSplit t
116+ pure (MultilineTextResult patterns)
117+
118+addClause :: Text -> CS.WildcardAnnotations -> Success
119+addClause t wca = MultilineTextResult (CS.addClause t wca)
120+
121+importsForFile :: (Applicative m, MonadIO m, MonadLogger m, MonadError PscIdeError m) =>
122+ FilePath -> m Success
123+importsForFile fp = do
124+ imports <- getImportsForFile fp
125+ pure (ImportList imports)
126+
127+-- | The first argument is a set of modules to load. The second argument
128+-- denotes modules for which to load dependencies
129+loadModulesAndDeps :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
130+ [ModuleIdent] -> [ModuleIdent] -> m Success
131+loadModulesAndDeps mods deps = do
132+ r1 <- mapM loadModule (mods ++ deps)
133+ r2 <- mapM loadModuleDependencies deps
134+ let moduleResults = T.concat r1
135+ let dependencyResults = T.concat r2
136+ pure (TextResult (moduleResults <> ", " <> dependencyResults))
137+
138+loadModuleDependencies ::(PscIde m, MonadLogger m, MonadError PscIdeError m) =>
139+ ModuleIdent -> m Text
140+loadModuleDependencies moduleName = do
141+ m <- getModule moduleName
142+ case getDependenciesForModule <$> m of
143+ Just deps -> do
144+ mapM_ loadModule deps
145+ -- We need to load the modules, that get reexported from the dependencies
146+ depModules <- catMaybes <$> mapM getModule deps
147+ -- What to do with errors here? This basically means a reexported dependency
148+ -- doesn't exist in the output/ folder
149+ traverse_ loadReexports depModules
150+ pure ("Dependencies for " <> moduleName <> " loaded.")
151+ Nothing -> throwError (ModuleNotFound moduleName)
152+
153+loadReexports :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
154+ Module -> m [ModuleIdent]
155+loadReexports m = case getReexports m of
156+ [] -> pure []
157+ exportDeps -> do
158+ -- I'm fine with this crashing on a failed pattern match.
159+ -- If this ever fails I'll need to look at GADTs
160+ let reexports = map (\(Export mn) -> mn) exportDeps
161+ $(logDebug) ("Loading reexports for module: " <> fst m <>
162+ " reexports: " <> T.intercalate ", " reexports)
163+ traverse_ loadModule reexports
164+ exportDepsModules <- catMaybes <$> traverse getModule reexports
165+ exportDepDeps <- traverse loadReexports exportDepsModules
166+ return $ concat exportDepDeps
167+
168+getDependenciesForModule :: Module -> [ModuleIdent]
169+getDependenciesForModule (_, decls) = mapMaybe getDependencyName decls
170+ where getDependencyName (Dependency dependencyName _ _) = Just dependencyName
171+ getDependencyName _ = Nothing
172+
173+loadModule :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
174+ ModuleIdent -> m Text
175+loadModule "Prim" = pure "Prim won't be loaded"
176+loadModule mn = do
177+ path <- filePathFromModule mn
178+ loadExtern path
179+ $(logDebug) ("Loaded extern file at: " <> T.pack path)
180+ pure ("Loaded extern file at: " <> T.pack path)
181+
182+filePathFromModule :: (PscIde m, MonadError PscIdeError m) =>
183+ ModuleIdent -> m FilePath
184+filePathFromModule moduleName = do
185+ outputPath <- confOutputPath . envConfiguration <$> ask
186+ cwd <- liftIO getCurrentDirectory
187+ let path = cwd </> outputPath </> T.unpack moduleName </> "externs.json"
188+ ex <- liftIO $ doesFileExist path
189+ if ex
190+ then pure path
191+ else throwError (ModuleFileNotFound moduleName)
192+
193+-- | Taken from Data.Either.Utils
194+maybeToEither :: MonadError e m =>
195+ e -- ^ (Left e) will be returned if the Maybe value is Nothing
196+ -> Maybe a -- ^ (Right a) will be returned if this is (Just a)
197+ -> m a
198+maybeToEither errorval Nothing = throwError errorval
199+maybeToEither _ (Just normalval) = return normalval
src/Language/PureScript/Ide/CaseSplit.hsnew file+157
@@ -0,0 +1,157 @@
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE LambdaCase #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE OverloadedStrings #-}
7+{-# LANGUAGE PackageImports #-}
8+{-# LANGUAGE RecordWildCards #-}
9+
10+module Language.PureScript.Ide.CaseSplit
11+ ( WildcardAnnotations()
12+ , explicitAnnotations
13+ , noAnnotations
14+ , makePattern
15+ , addClause
16+ , caseSplit
17+ ) where
18+
19+import Prelude ()
20+import Prelude.Compat hiding (lex)
21+
22+import Control.Monad.Error.Class
23+import "monad-logger" Control.Monad.Logger
24+import Data.List (find)
25+import Data.Monoid
26+import Data.Text (Text)
27+import qualified Data.Text as T
28+import Language.PureScript.AST
29+import Language.PureScript.Environment
30+import Language.PureScript.Externs
31+import Language.PureScript.Ide.Error
32+import Language.PureScript.Ide.Externs (unwrapPositioned)
33+import Language.PureScript.Ide.State
34+import Language.PureScript.Ide.Types hiding (Type)
35+import Language.PureScript.Names
36+import Language.PureScript.Parser.Common (runTokenParser)
37+import Language.PureScript.Parser.Declarations
38+import Language.PureScript.Parser.Lexer (lex)
39+import Language.PureScript.Parser.Types
40+import Language.PureScript.Pretty
41+import Language.PureScript.Types
42+import Text.Parsec as P
43+
44+type Constructor = (ProperName 'ConstructorName, [Type])
45+
46+newtype WildcardAnnotations = WildcardAnnotations Bool
47+
48+explicitAnnotations :: WildcardAnnotations
49+explicitAnnotations = WildcardAnnotations True
50+
51+noAnnotations :: WildcardAnnotations
52+noAnnotations = WildcardAnnotations False
53+
54+caseSplit :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
55+ Text -> m [Constructor]
56+caseSplit q = do
57+ (tc, args) <- splitTypeConstructor (parseType' (T.unpack q))
58+ (EDType _ _ (DataType typeVars ctors)) <- findTypeDeclaration tc
59+ let applyTypeVars = everywhereOnTypes (replaceAllTypeVars (zip (map fst typeVars) args))
60+ let appliedCtors = map (\(n, ts) -> (n, map applyTypeVars ts)) ctors
61+ pure appliedCtors
62+
63+{- ["EDType {
64+ edTypeName = ProperName {runProperName = \"Either\"}
65+ , edTypeKind = FunKind Star (FunKind Star Star)
66+ , edTypeDeclarationKind =
67+ DataType [(\"a\",Just Star),(\"b\",Just Star)]
68+ [(ProperName {runProperName = \"Left\"},[TypeVar \"a\"])
69+ ,(ProperName {runProperName = \"Right\"},[TypeVar \"b\"])]}"]
70+-}
71+
72+findTypeDeclaration :: (PscIde m, MonadLogger m, MonadError PscIdeError m) =>
73+ ProperName 'TypeName -> m ExternsDeclaration
74+findTypeDeclaration q = do
75+ efs <- getExternFiles
76+ let m = getFirst $ foldMap (findTypeDeclaration' q) efs
77+ case m of
78+ Just mn -> pure mn
79+ Nothing -> throwError (GeneralError "Not Found")
80+
81+findTypeDeclaration' ::
82+ ProperName 'TypeName
83+ -> ExternsFile
84+ -> First ExternsDeclaration
85+findTypeDeclaration' t ExternsFile{..} =
86+ First $ find (\case
87+ EDType tn _ _ -> tn == t
88+ _ -> False) efDeclarations
89+
90+splitTypeConstructor :: (Applicative m, MonadError PscIdeError m) =>
91+ Type -> m (ProperName 'TypeName, [Type])
92+splitTypeConstructor = go []
93+ where
94+ go acc (TypeApp ty arg) = go (arg : acc) ty
95+ go acc (TypeConstructor tc) = pure (disqualify tc, acc)
96+ go _ _ = throwError (GeneralError "Failed to read TypeConstructor")
97+
98+prettyCtor :: WildcardAnnotations -> Constructor -> Text
99+prettyCtor _ (ctorName, []) = T.pack (runProperName ctorName)
100+prettyCtor wsa (ctorName, ctorArgs) =
101+ "("<> T.pack (runProperName ctorName) <> " "
102+ <> T.unwords (map (prettyPrintWildcard wsa) ctorArgs) <>")"
103+
104+prettyPrintWildcard :: WildcardAnnotations -> Type -> Text
105+prettyPrintWildcard (WildcardAnnotations True) = prettyWildcard
106+prettyPrintWildcard (WildcardAnnotations False) = const "_"
107+
108+prettyWildcard :: Type -> Text
109+prettyWildcard t = "( _ :: " <> T.strip (T.pack (prettyPrintTypeAtom t)) <> ")"
110+
111+-- | Constructs Patterns to insert into a sourcefile
112+makePattern :: Text -- ^ Current line
113+ -> Int -- ^ Begin of the split
114+ -> Int -- ^ End of the split
115+ -> WildcardAnnotations -- ^ Whether to explicitly type the splits
116+ -> [Constructor] -- ^ Constructors to split
117+ -> [Text]
118+makePattern t x y wsa = makePattern' (T.take x t) (T.drop y t)
119+ where
120+ makePattern' lhs rhs = map (\ctor -> lhs <> prettyCtor wsa ctor <> rhs)
121+
122+addClause :: Text -> WildcardAnnotations -> [Text]
123+addClause s wca =
124+ let (fName, fType) = parseTypeDeclaration' (T.unpack s)
125+ (args, _) = splitFunctionType fType
126+ template = T.pack (runIdent fName) <> " " <>
127+ T.unwords (map (prettyPrintWildcard wca) args) <>
128+ " = ?" <> (T.strip . T.pack . runIdent $ fName)
129+ in [s, template]
130+
131+parseType' :: String -> Type
132+parseType' s = let (Right t) = do
133+ ts <- lex "" s
134+ runTokenParser "" (parseType <* P.eof) ts
135+ in t
136+
137+parseTypeDeclaration' :: String -> (Ident, Type)
138+parseTypeDeclaration' s =
139+ let x = do
140+ ts <- lex "" s
141+ runTokenParser "" (parseDeclaration <* P.eof) ts
142+ in
143+ case unwrapPositioned <$> x of
144+ Right (TypeDeclaration i t) -> (i, t)
145+ y -> error (show y)
146+
147+splitFunctionType :: Type -> ([Type], Type)
148+splitFunctionType t = (arguments, returns)
149+ where
150+ returns = last splitted
151+ arguments = init splitted
152+ splitted = splitType' t
153+ splitType' (ForAll _ t' _) = splitType' t'
154+ splitType' (ConstrainedType _ t') = splitType' t'
155+ splitType' (TypeApp (TypeApp t' lhs) rhs)
156+ | t' == tyFunction = lhs : splitType' rhs
157+ splitType' t' = [t']
src/Language/PureScript/Ide/CodecJSON.hsnew file+13
@@ -0,0 +1,13 @@
1+module Language.PureScript.Ide.CodecJSON where
2+
3+import Data.Aeson
4+import Data.Text (Text())
5+import Data.Text.Lazy (toStrict, fromStrict)
6+import Data.Text.Lazy.Encoding (decodeUtf8, encodeUtf8)
7+
8+encodeT :: (ToJSON a) => a -> Text
9+encodeT = toStrict . decodeUtf8 . encode
10+
11+decodeT :: (FromJSON a) => Text -> Maybe a
12+decodeT = decode . encodeUtf8 . fromStrict
13+
src/Language/PureScript/Ide/Command.hsnew file+101
@@ -0,0 +1,101 @@
1+{-# LANGUAGE MultiParamTypeClasses #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
4+
5+module Language.PureScript.Ide.Command where
6+
7+import Prelude ()
8+import Prelude.Compat
9+
10+import Control.Monad
11+import Data.Aeson
12+import Data.Maybe
13+import Data.Text (Text)
14+import Language.PureScript.Ide.CaseSplit
15+import Language.PureScript.Ide.Filter
16+import Language.PureScript.Ide.Matcher
17+import Language.PureScript.Ide.Types
18+
19+data Command
20+ = Load { loadModules :: [ModuleIdent]
21+ , loadDependencies :: [ModuleIdent]}
22+ | Type { typeSearch :: DeclIdent
23+ , typeFilters :: [Filter]}
24+ | Complete { completeFilters :: [Filter]
25+ , completeMatcher :: Matcher}
26+ | Pursuit { pursuitQuery :: PursuitQuery
27+ , pursuitSearchType :: PursuitSearchType}
28+ | List {listType :: ListType}
29+ | CaseSplit {
30+ caseSplitLine :: Text
31+ , caseSplitBegin :: Int
32+ , caseSplitEnd :: Int
33+ , caseSplitAnnotations :: WildcardAnnotations
34+ , caseSplitType :: Type}
35+ | AddClause {
36+ addClauseLine :: Text
37+ , addClauseAnnotations :: WildcardAnnotations}
38+ | Cwd
39+ | Quit
40+
41+data ListType = LoadedModules | Imports FilePath | AvailableModules
42+
43+instance FromJSON ListType where
44+ parseJSON = withObject "ListType" $ \o -> do
45+ (listType' :: String) <- o .: "type"
46+ case listType' of
47+ "import" -> do
48+ fp <- o .: "file"
49+ return (Imports fp)
50+ "loadedModules" -> return LoadedModules
51+ "availableModules" -> return AvailableModules
52+ _ -> mzero
53+
54+instance FromJSON Command where
55+ parseJSON = withObject "command" $ \o -> do
56+ (command :: String) <- o .: "command"
57+ case command of
58+ "list" -> do
59+ listType' <- o .:? "params"
60+ return $ List (fromMaybe LoadedModules listType')
61+ "cwd" -> return Cwd
62+ "quit" -> return Quit
63+ "load" -> do
64+ params <- o .: "params"
65+ mods <- params .:? "modules"
66+ deps <- params .:? "dependencies"
67+ return $ Load (fromMaybe [] mods) (fromMaybe [] deps)
68+ "type" -> do
69+ params <- o .: "params"
70+ search <- params .: "search"
71+ filters <- params .: "filters"
72+ return $ Type search filters
73+ "complete" -> do
74+ params <- o .: "params"
75+ filters <- params .:? "filters"
76+ matcher <- params .:? "matcher"
77+ return $ Complete (fromMaybe [] filters) (fromMaybe mempty matcher)
78+ "pursuit" -> do
79+ params <- o .: "params"
80+ query <- params .: "query"
81+ queryType <- params .: "type"
82+ return $ Pursuit query queryType
83+ "caseSplit" -> do
84+ params <- o .: "params"
85+ line <- params .: "line"
86+ begin <- params .: "begin"
87+ end <- params .: "end"
88+ annotations <- params .: "annotations"
89+ type' <- params .: "type"
90+ return $ CaseSplit line begin end (if annotations
91+ then explicitAnnotations
92+ else noAnnotations) type'
93+ "addClause" -> do
94+ params <- o .: "params"
95+ line <- params .: "line"
96+ annotations <- params .: "annotations"
97+ return $ AddClause line (if annotations
98+ then explicitAnnotations
99+ else noAnnotations)
100+ _ -> mzero
101+
src/Language/PureScript/Ide/Completion.hsnew file+35
@@ -0,0 +1,35 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Language.PureScript.Ide.Completion
3+ (getCompletions, getExactMatches)
4+ where
5+
6+import Prelude ()
7+import Prelude.Compat
8+
9+import Data.Maybe (mapMaybe)
10+import Language.PureScript.Ide.Filter
11+import Language.PureScript.Ide.Matcher
12+import Language.PureScript.Ide.Types
13+
14+-- | Applies the CompletionFilters and the Matcher to the given Modules
15+-- and sorts the found Completions according to the Matching Score
16+getCompletions :: [Filter] -> Matcher -> [Module] -> [Completion]
17+getCompletions filters matcher modules =
18+ runMatcher matcher $ completionsFromModules (applyFilters filters modules)
19+
20+getExactMatches :: DeclIdent -> [Filter] -> [Module] -> [Completion]
21+getExactMatches search filters modules =
22+ completionsFromModules $
23+ applyFilters (equalityFilter search : filters) modules
24+
25+completionsFromModules :: [Module] -> [Completion]
26+completionsFromModules = foldMap completionFromModule
27+ where
28+ completionFromModule :: Module -> [Completion]
29+ completionFromModule (moduleIdent, decls) = mapMaybe (completionFromDecl moduleIdent) decls
30+
31+completionFromDecl :: ModuleIdent -> ExternDecl -> Maybe Completion
32+completionFromDecl mi (FunctionDecl name type') = Just (Completion (mi, name, type'))
33+completionFromDecl mi (DataDecl name kind) = Just (Completion (mi, name, kind))
34+completionFromDecl _ (ModuleDecl name _) = Just (Completion ("module", name, "module"))
35+completionFromDecl _ _ = Nothing
src/Language/PureScript/Ide/Error.hsnew file+43
@@ -0,0 +1,43 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Language.PureScript.Ide.Error
3+ (ErrorMsg, PscIdeError(..), textError, first)
4+ where
5+
6+import Data.Aeson
7+import Data.Monoid
8+import Data.Text (Text, pack)
9+import Language.PureScript.Ide.Types (ModuleIdent)
10+import qualified Text.Parsec.Error as P
11+
12+type ErrorMsg = String
13+
14+data PscIdeError
15+ = GeneralError ErrorMsg
16+ | NotFound Text
17+ | ModuleNotFound ModuleIdent
18+ | ModuleFileNotFound ModuleIdent
19+ | ParseError P.ParseError ErrorMsg
20+ deriving (Show, Eq)
21+
22+instance ToJSON PscIdeError where
23+ toJSON err = object
24+ [
25+ "resultType" .= ("error" :: Text),
26+ "result" .= textError err
27+ ]
28+
29+textError :: PscIdeError -> Text
30+textError (GeneralError msg) = pack msg
31+textError (NotFound ident) = "Symbol '" <> ident <> "' not found."
32+textError (ModuleNotFound ident) = "Module '" <> ident <> "' not found."
33+textError (ModuleFileNotFound ident) = "Extern file for module " <> ident <>" could not be found"
34+textError (ParseError parseError msg) = pack $ msg <> ": " <> show (escape parseError)
35+ where
36+ -- escape newlines and other special chars so we can send the error over the socket as a single line
37+ escape :: P.ParseError -> String
38+ escape = show
39+
40+-- | Specialized version of `first` from `Data.Bifunctors`
41+first :: (a -> b) -> Either a r -> Either b r
42+first f (Left x) = Left (f x)
43+first _ (Right r2) = Right r2
src/Language/PureScript/Ide/Externs.hsnew file+102
@@ -0,0 +1,102 @@
1+{-# LANGUAGE FlexibleContexts #-}
2+{-# LANGUAGE MultiParamTypeClasses #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE RecordWildCards #-}
5+{-# LANGUAGE ScopedTypeVariables #-}
6+
7+module Language.PureScript.Ide.Externs
8+ (
9+ ExternDecl(..),
10+ ModuleIdent,
11+ DeclIdent,
12+ Type,
13+ Fixity(..),
14+ readExternFile,
15+ convertExterns,
16+ unwrapPositioned,
17+ unwrapPositionedRef
18+ ) where
19+
20+import Prelude ()
21+import Prelude.Compat
22+
23+import Control.Monad.Error.Class
24+import Control.Monad.IO.Class
25+import Data.Maybe (mapMaybe)
26+import Data.Text (Text)
27+import qualified Data.Text as T
28+import qualified Data.Text.IO as T
29+import qualified Language.PureScript.AST.Declarations as D
30+import qualified Language.PureScript.Externs as PE
31+import Language.PureScript.Ide.CodecJSON
32+import Language.PureScript.Ide.Error (PscIdeError (..))
33+import Language.PureScript.Ide.Types
34+import qualified Language.PureScript.Names as N
35+import qualified Language.PureScript.Pretty as PP
36+
37+readExternFile :: (Applicative m, MonadIO m, MonadError PscIdeError m) =>
38+ FilePath -> m PE.ExternsFile
39+readExternFile fp = do
40+ parseResult <- liftIO (decodeT <$> T.readFile fp)
41+ case parseResult of
42+ Nothing -> throwError . GeneralError $ "Parsing the extern at: " ++ fp ++ " failed"
43+ Just externs -> pure externs
44+
45+moduleNameToText :: N.ModuleName -> Text
46+moduleNameToText = T.pack . N.runModuleName
47+
48+properNameToText :: N.ProperName a -> Text
49+properNameToText = T.pack . N.runProperName
50+
51+identToText :: N.Ident -> Text
52+identToText = T.pack . N.runIdent
53+
54+convertExterns :: PE.ExternsFile -> Module
55+convertExterns ef = (moduleName, exportDecls ++ importDecls ++ otherDecls)
56+ where
57+ moduleName = moduleNameToText (PE.efModuleName ef)
58+ importDecls = convertImport <$> PE.efImports ef
59+ exportDecls = mapMaybe (convertExport . unwrapPositionedRef) (PE.efExports ef)
60+ -- Ignoring operator fixities for now since we're not using them
61+ -- operatorDecls = convertOperator <$> PE.efFixities ef
62+ otherDecls = mapMaybe convertDecl (PE.efDeclarations ef)
63+
64+convertImport :: PE.ExternsImport -> ExternDecl
65+convertImport ei = Dependency
66+ (moduleNameToText (PE.eiModule ei))
67+ []
68+ (moduleNameToText <$> PE.eiImportedAs ei)
69+
70+convertExport :: D.DeclarationRef -> Maybe ExternDecl
71+convertExport (D.ModuleRef mn) = Just (Export (moduleNameToText mn))
72+convertExport _ = Nothing
73+
74+convertDecl :: PE.ExternsDeclaration -> Maybe ExternDecl
75+convertDecl PE.EDType{..} = Just $
76+ DataDecl
77+ (properNameToText edTypeName)
78+ (packAndStrip (PP.prettyPrintKind edTypeKind))
79+convertDecl PE.EDTypeSynonym{..} = Just $
80+ DataDecl
81+ (properNameToText edTypeSynonymName)
82+ (packAndStrip (PP.prettyPrintType edTypeSynonymType))
83+convertDecl PE.EDDataConstructor{..} = Just $
84+ DataDecl
85+ (properNameToText edDataCtorName)
86+ (packAndStrip (PP.prettyPrintType edDataCtorType))
87+convertDecl PE.EDValue{..} = Just $
88+ FunctionDecl
89+ (identToText edValueName)
90+ (packAndStrip (PP.prettyPrintType edValueType))
91+convertDecl _ = Nothing
92+
93+packAndStrip :: String -> Text
94+packAndStrip = T.unwords . fmap T.strip . T.lines . T.pack
95+
96+unwrapPositioned :: D.Declaration -> D.Declaration
97+unwrapPositioned (D.PositionedDeclaration _ _ x) = x
98+unwrapPositioned x = x
99+
100+unwrapPositionedRef :: D.DeclarationRef -> D.DeclarationRef
101+unwrapPositionedRef (D.PositionedDeclarationRef _ _ x) = x
102+unwrapPositionedRef x = x
src/Language/PureScript/Ide/Filter.hsnew file+110
@@ -0,0 +1,110 @@
1+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
4+module Language.PureScript.Ide.Filter
5+ (Filter, moduleFilter, prefixFilter, equalityFilter, dependencyFilter,
6+ runFilter, applyFilters)
7+ where
8+
9+import Prelude ()
10+import Prelude.Compat
11+
12+import Control.Monad
13+import Data.Aeson
14+import Data.Foldable
15+import Data.Maybe (listToMaybe, mapMaybe)
16+import Data.Monoid
17+import Data.Text (Text, isPrefixOf)
18+import Language.PureScript.Ide.Types
19+
20+newtype Filter = Filter (Endo [Module]) deriving(Monoid)
21+
22+mkFilter :: ([Module] -> [Module]) -> Filter
23+mkFilter = Filter . Endo
24+
25+-- | Only keeps the given Modules
26+moduleFilter :: [ModuleIdent] -> Filter
27+moduleFilter =
28+ mkFilter . moduleFilter'
29+
30+moduleFilter' :: [ModuleIdent] -> [Module] -> [Module]
31+moduleFilter' moduleIdents = filter (flip elem moduleIdents . fst)
32+
33+-- | Only keeps the given Modules and all of their dependencies
34+dependencyFilter :: [ModuleIdent] -> Filter
35+dependencyFilter = mkFilter . dependencyFilter'
36+
37+dependencyFilter' :: [ModuleIdent] -> [Module] -> [Module]
38+dependencyFilter' moduleIdents mods =
39+ moduleFilter' (concatMap (getDepForModule mods) moduleIdents) mods
40+ where
41+ getDepForModule :: [Module] -> ModuleIdent -> [ModuleIdent]
42+ getDepForModule ms moduleIdent =
43+ moduleIdent : maybe [] extractDeps (findModule moduleIdent ms)
44+
45+ findModule :: ModuleIdent -> [Module] -> Maybe Module
46+ findModule i ms = listToMaybe $ filter go ms
47+ where go (mn, _) = i == mn
48+
49+ extractDeps :: Module -> [ModuleIdent]
50+ extractDeps = mapMaybe extractDep . snd
51+ where extractDep (Dependency n _ _) = Just n
52+ extractDep _ = Nothing
53+
54+-- | Only keeps Identifiers that start with the given prefix
55+prefixFilter :: Text -> Filter
56+prefixFilter "" = mkFilter id
57+prefixFilter t = mkFilter $ identFilter prefix t
58+ where
59+ prefix :: ExternDecl -> Text -> Bool
60+ prefix (FunctionDecl name _) search = search `isPrefixOf` name
61+ prefix (DataDecl name _) search = search `isPrefixOf` name
62+ prefix (ModuleDecl name _) search = search `isPrefixOf` name
63+ prefix _ _ = False
64+
65+
66+-- | Only keeps Identifiers that are equal to the search string
67+equalityFilter :: Text -> Filter
68+equalityFilter = mkFilter . identFilter equality
69+ where
70+ equality :: ExternDecl -> Text -> Bool
71+ equality (FunctionDecl name _) prefix = prefix == name
72+ equality (DataDecl name _) prefix = prefix == name
73+ equality _ _ = False
74+
75+
76+identFilter :: (ExternDecl -> Text -> Bool ) -> Text -> [Module] -> [Module]
77+identFilter predicate search =
78+ filter (not . null . snd) . fmap filterModuleDecls
79+ where
80+ filterModuleDecls :: Module -> Module
81+ filterModuleDecls (moduleIdent,decls) =
82+ (moduleIdent, filter (`predicate` search) decls)
83+
84+runFilter :: Filter -> [Module] -> [Module]
85+runFilter (Filter f)= appEndo f
86+
87+applyFilters :: [Filter] -> [Module] -> [Module]
88+applyFilters = runFilter . fold
89+
90+instance FromJSON Filter where
91+ parseJSON = withObject "filter" $ \o -> do
92+ (filter' :: String) <- o .: "filter"
93+ case filter' of
94+ "exact" -> do
95+ params <- o .: "params"
96+ search <- params .: "search"
97+ return $ equalityFilter search
98+ "prefix" -> do
99+ params <- o.: "params"
100+ search <- params .: "search"
101+ return $ prefixFilter search
102+ "modules" -> do
103+ params <- o .: "params"
104+ modules <- params .: "modules"
105+ return $ moduleFilter modules
106+ "dependencies" -> do
107+ params <- o .: "params"
108+ deps <- params .: "modules"
109+ return $ dependencyFilter deps
110+ _ -> mzero
src/Language/PureScript/Ide/Matcher.hsnew file+100
@@ -0,0 +1,100 @@
1+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
4+module Language.PureScript.Ide.Matcher (Matcher, flexMatcher, runMatcher) where
5+
6+import Prelude ()
7+import Prelude.Compat
8+
9+import Control.Monad
10+import Data.Aeson
11+import Data.Function (on)
12+import Data.List (sortBy)
13+import Data.Maybe (mapMaybe)
14+import Data.Monoid
15+import Data.Text (Text)
16+import qualified Data.Text as T
17+import qualified Data.Text.Encoding as TE
18+import Language.PureScript.Ide.Types
19+import Text.EditDistance
20+import Text.Regex.TDFA ((=~))
21+
22+
23+type ScoredCompletion = (Completion, Double)
24+
25+newtype Matcher = Matcher (Endo [Completion]) deriving(Monoid)
26+
27+instance FromJSON Matcher where
28+ parseJSON = withObject "matcher" $ \o -> do
29+ (matcher :: Maybe String) <- o .:? "matcher"
30+ case matcher of
31+ Just "flex" -> do
32+ params <- o .: "params"
33+ search <- params .: "search"
34+ pure $ flexMatcher search
35+ Just "distance" -> do
36+ params <- o .: "params"
37+ search <- params .: "search"
38+ maxDist <- params .: "maximumDistance"
39+ pure $ distanceMatcher search maxDist
40+ Just _ -> mzero
41+ Nothing -> return mempty
42+
43+-- | Matches any occurence of the search string with intersections
44+-- |
45+-- | The scoring measures how far the matches span the string where
46+-- | closer is better.
47+-- | Examples:
48+-- | flMa matches flexMatcher. Score: 14.28
49+-- | sons matches sortCompletions. Score: 6.25
50+flexMatcher :: Text -> Matcher
51+flexMatcher pattern = mkMatcher (flexMatch pattern)
52+
53+distanceMatcher :: Text -> Int -> Matcher
54+distanceMatcher q maxDist = mkMatcher (distanceMatcher' q maxDist)
55+
56+distanceMatcher' :: Text -> Int -> [Completion] -> [ScoredCompletion]
57+distanceMatcher' q maxDist = mapMaybe go
58+ where
59+ go c@(Completion (_, y, _)) = let d = dist (T.unpack y)
60+ in if d <= maxDist
61+ then Just (c, 1 / fromIntegral d)
62+ else Nothing
63+ dist = levenshteinDistance defaultEditCosts (T.unpack q)
64+
65+mkMatcher :: ([Completion] -> [ScoredCompletion]) -> Matcher
66+mkMatcher matcher = Matcher . Endo $ fmap fst . sortCompletions . matcher
67+
68+runMatcher :: Matcher -> [Completion] -> [Completion]
69+runMatcher (Matcher m)= appEndo m
70+
71+sortCompletions :: [ScoredCompletion] -> [ScoredCompletion]
72+sortCompletions = sortBy (flip compare `on` snd)
73+
74+flexMatch :: Text -> [Completion] -> [ScoredCompletion]
75+flexMatch pattern = mapMaybe (flexRate pattern)
76+
77+flexRate :: Text -> Completion -> Maybe ScoredCompletion
78+flexRate pattern c@(Completion (_,ident,_)) = do
79+ score <- flexScore pattern ident
80+ return (c, score)
81+
82+-- FlexMatching ala Sublime.
83+-- Borrowed from: http://cdewaka.com/2013/06/fuzzy-pattern-matching-in-haskell/
84+--
85+-- By string =~ pattern we'll get the start of the match and the length of
86+-- the matchas a (start, length) tuple if there's a match.
87+-- If match fails then it would be (-1,0)
88+flexScore :: Text -> DeclIdent -> Maybe Double
89+flexScore "" _ = Nothing
90+flexScore pat str =
91+ case TE.encodeUtf8 str =~ TE.encodeUtf8 pat' :: (Int, Int) of
92+ (-1,0) -> Nothing
93+ (start,len) -> Just $ calcScore start (start + len)
94+ where
95+ Just (first,pattern) = T.uncons pat
96+ -- This just interleaves the search string with .*
97+ -- abcd -> a.*b.*c.*d
98+ pat' = first `T.cons` T.concatMap (T.snoc ".*") pattern
99+ calcScore start end =
100+ 100.0 / fromIntegral ((1 + start) * (end - start + 1))
src/Language/PureScript/Ide/Pursuit.hsnew file+65
@@ -0,0 +1,65 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+
4+module Language.PureScript.Ide.Pursuit where
5+
6+import Prelude ()
7+import Prelude.Compat
8+
9+import qualified Control.Exception as E
10+import Data.Aeson
11+import Data.ByteString (ByteString)
12+import Data.ByteString.Lazy (fromStrict)
13+import Data.Foldable (toList)
14+import Data.Monoid ((<>))
15+import Data.Maybe (mapMaybe)
16+import Data.String
17+import Data.Text (Text)
18+import qualified Data.Text as T
19+import Language.PureScript.Ide.Types
20+import Network.HTTP.Types.Header (hAccept)
21+import Pipes.HTTP
22+import qualified Pipes.Prelude as P
23+
24+-- We need to remove trailing dots because Pursuit will return a 400 otherwise
25+-- TODO: remove this when the issue is fixed at Pursuit
26+queryPursuit :: Text -> IO ByteString
27+queryPursuit q = do
28+ let qClean = T.dropWhileEnd (== '.') q
29+ req' <- parseUrl "http://pursuit.purescript.org/search"
30+ let req = req'
31+ { queryString=("q=" <> (fromString . T.unpack) qClean)
32+ , requestHeaders=[(hAccept, "application/json")]
33+ }
34+ m <- newManager tlsManagerSettings
35+ withHTTP req m $ \resp ->
36+ P.fold (\x a -> x <> a) "" id $ responseBody resp
37+
38+
39+handler :: HttpException -> IO [a]
40+handler StatusCodeException{} = return []
41+handler _ = return []
42+
43+searchPursuitForDeclarations :: Text -> IO [PursuitResponse]
44+searchPursuitForDeclarations query =
45+ (do r <- queryPursuit query
46+ let results' = decode (fromStrict r) :: Maybe Array
47+ case results' of
48+ Nothing -> pure []
49+ Just results -> pure (mapMaybe isDeclarationResponse (map fromJSON (toList results)))) `E.catch`
50+ handler
51+ where
52+ isDeclarationResponse (Success a@DeclarationResponse{}) = Just a
53+ isDeclarationResponse _ = Nothing
54+
55+findPackagesForModuleIdent :: Text -> IO [PursuitResponse]
56+findPackagesForModuleIdent query =
57+ (do r <- queryPursuit query
58+ let results' = decode (fromStrict r) :: Maybe Array
59+ case results' of
60+ Nothing -> pure []
61+ Just results -> pure (mapMaybe isModuleResponse (map fromJSON (toList results)))) `E.catch`
62+ handler
63+ where
64+ isModuleResponse (Success a@ModuleResponse{}) = Just a
65+ isModuleResponse _ = Nothing
src/Language/PureScript/Ide/Reexports.hsnew file+73
@@ -0,0 +1,73 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE PatternGuards #-}
3+{-# LANGUAGE TupleSections #-}
4+module Language.PureScript.Ide.Reexports where
5+
6+
7+import Prelude ()
8+import Prelude.Compat
9+
10+import Data.List (union)
11+import Data.Map (Map)
12+import qualified Data.Map as Map
13+import Data.Maybe
14+import Language.PureScript.Ide.Types
15+
16+getReexports :: Module -> [ExternDecl]
17+getReexports (mn, decls)= concatMap getExport decls
18+ where getExport d
19+ | (Export mn') <- d
20+ , mn /= mn' = replaceExportWithAliases decls mn'
21+ | otherwise = []
22+
23+dependencyToExport :: ExternDecl -> ExternDecl
24+dependencyToExport (Dependency m _ _) = Export m
25+dependencyToExport decl = decl
26+
27+replaceExportWithAliases :: [ExternDecl] -> ModuleIdent -> [ExternDecl]
28+replaceExportWithAliases decls ident =
29+ case filter isMatch decls of
30+ [] -> [Export ident]
31+ aliases -> map dependencyToExport aliases
32+ where isMatch d
33+ | Dependency _ _ (Just alias) <- d
34+ , alias == ident = True
35+ | otherwise = False
36+
37+replaceReexport :: ExternDecl -> Module -> Module -> Module
38+replaceReexport e@(Export _) (m, decls) (_, newDecls) =
39+ (m, filter (/= e) decls `union` newDecls)
40+replaceReexport _ _ _ = error "Should only get Exports here."
41+
42+emptyModule :: Module
43+emptyModule = ("Empty", [])
44+
45+isExport :: ExternDecl -> Bool
46+isExport (Export _) = True
47+isExport _ = False
48+
49+removeExportDecls :: Module -> Module
50+removeExportDecls = fmap (filter (not . isExport))
51+
52+replaceReexports :: Module -> Map ModuleIdent [ExternDecl] -> Module
53+replaceReexports m db = result
54+ where reexports = getReexports m
55+ result = foldl go (removeExportDecls m) reexports
56+
57+ go :: Module -> ExternDecl -> Module
58+ go m' re@(Export name) = replaceReexport re m' (getModule name)
59+ go _ _ = error "partiality! woohoo"
60+
61+ getModule :: ModuleIdent -> Module
62+ getModule name = clean res
63+ where res = fromMaybe emptyModule $ (name , ) <$> Map.lookup name db
64+ -- we have to do this because keeping self exports in will result in
65+ -- infinite loops
66+ clean (mn, decls) = (mn,) (filter (/= Export mn) decls)
67+
68+resolveReexports :: Map ModuleIdent [ExternDecl] -> Module -> Module
69+resolveReexports modules m = do
70+ let replaced = replaceReexports m modules
71+ if null . getReexports $ replaced
72+ then replaced
73+ else resolveReexports modules replaced
src/Language/PureScript/Ide/SourceFile.hsnew file+106
@@ -0,0 +1,106 @@
1+{-# LANGUAGE FlexibleContexts #-}
2+{-# LANGUAGE MultiParamTypeClasses #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+module Language.PureScript.Ide.SourceFile where
5+
6+import Prelude ()
7+import Prelude.Compat
8+
9+import Control.Monad.Error.Class
10+import Control.Monad.IO.Class
11+import Control.Monad.Trans.Except
12+import Data.Maybe (mapMaybe)
13+import Data.Monoid
14+import qualified Data.Text as T
15+import qualified Language.PureScript.AST.Declarations as D
16+import qualified Language.PureScript.AST.SourcePos as SP
17+import Language.PureScript.Ide.Error
18+import Language.PureScript.Ide.Externs (unwrapPositioned,
19+ unwrapPositionedRef)
20+import Language.PureScript.Ide.Types
21+import qualified Language.PureScript.Names as N
22+import qualified Language.PureScript.Parser as P
23+import System.Directory
24+
25+parseModuleFromFile :: (Applicative m, MonadIO m, MonadError PscIdeError m) =>
26+ FilePath -> m D.Module
27+parseModuleFromFile fp = do
28+ exists <- liftIO (doesFileExist fp)
29+ if exists
30+ then do
31+ content <- liftIO (readFile fp)
32+ let m = do tokens <- P.lex fp content
33+ P.runTokenParser "" P.parseModule tokens
34+ either (throwError . (`ParseError` "File could not be parsed.")) pure m
35+ else throwError (NotFound "File does not exist.")
36+
37+-- data Module = Module SourceSpan [Comment] ModuleName [Declaration] (Maybe [DeclarationRef])
38+
39+getDeclarations :: D.Module -> [D.Declaration]
40+getDeclarations (D.Module _ _ _ declarations _) = declarations
41+
42+getImports :: D.Module -> [D.Declaration]
43+getImports (D.Module _ _ _ declarations _) =
44+ mapMaybe isImport declarations
45+ where
46+ isImport (D.PositionedDeclaration _ _ (i@D.ImportDeclaration{})) = Just i
47+ isImport _ = Nothing
48+
49+getImportsForFile :: (Applicative m, MonadIO m, MonadError PscIdeError m) =>
50+ FilePath -> m [ModuleImport]
51+getImportsForFile fp = do
52+ module' <- parseModuleFromFile fp
53+ let imports = getImports module'
54+ pure (mkModuleImport . unwrapPositionedImport <$> imports)
55+ where mkModuleImport (D.ImportDeclaration mn importType' qualifier _) =
56+ ModuleImport
57+ (T.pack (N.runModuleName mn))
58+ importType'
59+ (T.pack . N.runModuleName <$> qualifier)
60+ mkModuleImport _ = error "Shouldn't have gotten anything but Imports here"
61+ unwrapPositionedImport (D.ImportDeclaration mn importType' qualifier b) =
62+ D.ImportDeclaration mn (unwrapImportType importType') qualifier b
63+ unwrapPositionedImport x = x
64+ unwrapImportType (D.Explicit decls) = D.Explicit (map unwrapPositionedRef decls)
65+ unwrapImportType (D.Hiding decls) = D.Hiding (map unwrapPositionedRef decls)
66+ unwrapImportType D.Implicit = D.Implicit
67+
68+getPositionedImports :: D.Module -> [D.Declaration]
69+getPositionedImports (D.Module _ _ _ declarations _) =
70+ mapMaybe isImport declarations
71+ where
72+ isImport i@(D.PositionedDeclaration _ _ (D.ImportDeclaration{})) = Just i
73+ isImport _ = Nothing
74+
75+getDeclPosition :: D.Module -> String -> Maybe SP.SourceSpan
76+getDeclPosition m ident =
77+ let decls = getDeclarations m
78+ in getFirst (foldMap (match ident) decls)
79+ where match q (D.PositionedDeclaration ss _ decl) = First (if go q decl
80+ then Just ss
81+ else Nothing)
82+ match _ _ = First Nothing
83+
84+ go q (D.DataDeclaration _ name _ constructors) =
85+ properEqual name q || any (\(x,_) -> properEqual x q) constructors
86+ go q (D.DataBindingGroupDeclaration decls) = any (go q) decls
87+ go q (D.TypeSynonymDeclaration name _ _) = properEqual name q
88+ go q (D.TypeDeclaration ident' _) = identEqual ident' q
89+ go q (D.ValueDeclaration ident' _ _ _) = identEqual ident' q
90+ go q (D.ExternDeclaration ident' _) = identEqual ident' q
91+ go q (D.ExternDataDeclaration name _) = properEqual name q
92+ go q (D.TypeClassDeclaration name _ _ members) =
93+ properEqual name q || any (go q . unwrapPositioned) members
94+ go q (D.TypeInstanceDeclaration ident' _ _ _ _) =
95+ identEqual ident' q
96+ go _ _ = False
97+
98+ properEqual x q = N.runProperName x == q
99+ identEqual x q = N.runIdent x == q
100+
101+goToDefinition :: String -> FilePath -> IO (Maybe SP.SourceSpan)
102+goToDefinition q fp = do
103+ m <- runExceptT (parseModuleFromFile fp)
104+ case m of
105+ Right module' -> return $ getDeclPosition module' q
106+ Left _ -> return Nothing
src/Language/PureScript/Ide/State.hsnew file+80
@@ -0,0 +1,80 @@
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE MultiParamTypeClasses #-}
4+{-# LANGUAGE OverloadedStrings #-}
5+{-# LANGUAGE PackageImports #-}
6+{-# LANGUAGE TemplateHaskell #-}
7+{-# LANGUAGE TupleSections #-}
8+
9+module Language.PureScript.Ide.State where
10+
11+import Prelude ()
12+import Prelude.Compat
13+
14+import Control.Concurrent.STM
15+import Control.Monad.IO.Class
16+import "monad-logger" Control.Monad.Logger
17+import Control.Monad.Reader.Class
18+import qualified Data.Map.Lazy as M
19+import Data.Maybe (catMaybes)
20+import Data.Monoid
21+import qualified Data.Text as T
22+import Language.PureScript.Externs
23+import Language.PureScript.Ide.Externs
24+import Language.PureScript.Ide.Reexports
25+import Language.PureScript.Ide.Types
26+import Language.PureScript.Names
27+
28+getPscIdeState :: (PscIde m, Functor m) =>
29+ m (M.Map ModuleIdent [ExternDecl])
30+getPscIdeState = do
31+ stateVar <- envStateVar <$> ask
32+ liftIO $ pscStateModules <$> readTVarIO stateVar
33+
34+getExternFiles :: (PscIde m, Functor m) =>
35+ m (M.Map ModuleName ExternsFile)
36+getExternFiles = do
37+ stateVar <- envStateVar <$> ask
38+ liftIO (externsFiles <$> readTVarIO stateVar)
39+
40+getAllDecls :: (PscIde m, Functor m) => m [ExternDecl]
41+getAllDecls = concat <$> getPscIdeState
42+
43+getAllModules :: (PscIde m, Functor m) => m [Module]
44+getAllModules = M.toList <$> getPscIdeState
45+
46+getAllModulesWithReexports :: (PscIde m, MonadLogger m, Applicative m) =>
47+ m [Module]
48+getAllModulesWithReexports = do
49+ mis <- M.keys <$> getPscIdeState
50+ ms <- traverse getModuleWithReexports mis
51+ pure (catMaybes ms)
52+
53+getModule :: (PscIde m, MonadLogger m, Applicative m) =>
54+ ModuleIdent -> m (Maybe Module)
55+getModule m = do
56+ modules <- getPscIdeState
57+ pure ((m,) <$> M.lookup m modules)
58+
59+getModuleWithReexports :: (PscIde m, MonadLogger m, Applicative m) =>
60+ ModuleIdent -> m (Maybe Module)
61+getModuleWithReexports mi = do
62+ m <- getModule mi
63+ modules <- getPscIdeState
64+ pure $ resolveReexports modules <$> m
65+
66+insertModule ::(PscIde m, MonadLogger m) =>
67+ ExternsFile -> m ()
68+insertModule externsFile = do
69+ env <- ask
70+ let moduleName = efModuleName externsFile
71+ $(logDebug) $ "Inserting Module: " <> (T.pack (runModuleName moduleName))
72+ liftIO . atomically $ insertModule' (envStateVar env) externsFile
73+
74+insertModule' :: TVar PscIdeState -> ExternsFile -> STM ()
75+insertModule' st ef = do
76+ modifyTVar (st) $ \x ->
77+ x { externsFiles = M.insert (efModuleName ef) ef (externsFiles x)
78+ , pscStateModules = let (mn, decls ) = convertExterns ef
79+ in M.insert mn decls (pscStateModules x)
80+ }
src/Language/PureScript/Ide/Types.hsnew file+240
@@ -0,0 +1,240 @@
1+{-# LANGUAGE ConstraintKinds #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4+{-# LANGUAGE OverloadedStrings #-}
5+{-# LANGUAGE RecordWildCards #-}
6+{-# LANGUAGE ScopedTypeVariables #-}
7+
8+module Language.PureScript.Ide.Types where
9+
10+import Prelude ()
11+import Prelude.Compat
12+
13+import Control.Concurrent.STM
14+import Control.Monad
15+import Control.Monad.Reader.Class
16+import Control.Monad.Trans
17+import Data.Aeson
18+import Data.Map.Lazy as M
19+import Data.Maybe (maybeToList)
20+import Data.Text (Text (), pack, unpack)
21+import qualified Language.PureScript.AST.Declarations as D
22+import Language.PureScript.Externs
23+import Language.PureScript.Names
24+import qualified Language.PureScript.Names as N
25+
26+import Text.Parsec
27+import Text.Parsec.Text
28+
29+type ModuleIdent = Text
30+type DeclIdent = Text
31+type Type = Text
32+
33+data Fixity = Infix | Infixl | Infixr deriving(Show, Eq, Ord)
34+
35+data ExternDecl
36+ = FunctionDecl { functionName :: DeclIdent
37+ , functionType :: Type
38+ }
39+ | FixityDeclaration Fixity
40+ Int
41+ DeclIdent
42+ | Dependency { dependencyModule :: ModuleIdent
43+ , dependencyNames :: [Text]
44+ , dependencyAlias :: Maybe Text
45+ }
46+ | ModuleDecl ModuleIdent
47+ [DeclIdent]
48+ | DataDecl DeclIdent
49+ Text
50+ | Export ModuleIdent
51+ deriving (Show,Eq,Ord)
52+
53+instance ToJSON ExternDecl where
54+ toJSON (FunctionDecl n t) = object ["name" .= n, "type" .= t]
55+ toJSON (ModuleDecl n t) = object ["name" .= n, "type" .= t]
56+ toJSON (DataDecl n t) = object ["name" .= n, "type" .= t]
57+ toJSON (Dependency n names _) = object ["module" .= n, "names" .= names]
58+ toJSON (FixityDeclaration f p n) = object ["name" .= n
59+ , "fixity" .= show f
60+ , "precedence" .= p]
61+ toJSON (Export _) = object []
62+
63+type Module = (ModuleIdent, [ExternDecl])
64+
65+data Configuration =
66+ Configuration {
67+ confOutputPath :: FilePath
68+ , confDebug :: Bool
69+ }
70+
71+data PscIdeEnvironment =
72+ PscIdeEnvironment {
73+ envStateVar :: TVar PscIdeState
74+ , envConfiguration :: Configuration
75+ }
76+
77+type PscIde m = (Applicative m, MonadIO m, MonadReader PscIdeEnvironment m)
78+
79+data PscIdeState =
80+ PscIdeState {
81+ pscStateModules :: M.Map Text [ExternDecl]
82+ , externsFiles :: M.Map ModuleName ExternsFile
83+ } deriving Show
84+
85+emptyPscIdeState :: PscIdeState
86+emptyPscIdeState = PscIdeState M.empty M.empty
87+
88+newtype Completion =
89+ Completion (ModuleIdent, DeclIdent, Type)
90+ deriving (Show,Eq)
91+
92+data ModuleImport =
93+ ModuleImport {
94+ importModuleName :: ModuleIdent
95+ , importType :: D.ImportDeclarationType
96+ , importQualifier :: Maybe Text
97+ } deriving(Show)
98+
99+instance Eq ModuleImport where
100+ mi1 == mi2 = importModuleName mi1 == importModuleName mi2
101+ && importQualifier mi1 == importQualifier mi2
102+
103+instance ToJSON ModuleImport where
104+ toJSON (ModuleImport mn D.Implicit qualifier) =
105+ object $ ["module" .= mn
106+ , "importType" .= ("implicit" :: Text)
107+ ] ++ fmap (\x -> "qualifier" .= x) (maybeToList qualifier)
108+ toJSON (ModuleImport mn (D.Explicit refs) _) =
109+ object ["module" .= mn
110+ , "importType" .= ("explicit" :: Text)
111+ , "identifiers" .= (identifierFromDeclarationRef <$> refs)]
112+ toJSON (ModuleImport mn (D.Hiding refs) _) =
113+ object ["module" .= mn
114+ , "importType" .= ("hiding" :: Text)
115+ , "identifiers" .= (identifierFromDeclarationRef <$> refs)]
116+
117+identifierFromDeclarationRef :: D.DeclarationRef -> String
118+identifierFromDeclarationRef (D.TypeRef name _) = N.runProperName name
119+identifierFromDeclarationRef (D.ValueRef ident) = N.runIdent ident
120+identifierFromDeclarationRef (D.TypeClassRef name) = N.runProperName name
121+identifierFromDeclarationRef _ = ""
122+
123+instance FromJSON Completion where
124+ parseJSON (Object o) = do
125+ m <- o .: "module"
126+ d <- o .: "identifier"
127+ t <- o .: "type"
128+ return $ Completion (m, d, t)
129+ parseJSON _ = mzero
130+
131+instance ToJSON Completion where
132+ toJSON (Completion (m,d,t)) =
133+ object ["module" .= m, "identifier" .= d, "type" .= t]
134+
135+data Success =
136+ CompletionResult [Completion]
137+ | TextResult Text
138+ | MultilineTextResult [Text]
139+ | PursuitResult [PursuitResponse]
140+ | ImportList [ModuleImport]
141+ | ModuleList [ModuleIdent]
142+ deriving(Show, Eq)
143+
144+encodeSuccess :: (ToJSON a) => a -> Value
145+encodeSuccess res =
146+ object ["resultType" .= ("success" :: Text), "result" .= res]
147+
148+instance ToJSON Success where
149+ toJSON (CompletionResult cs) = encodeSuccess cs
150+ toJSON (TextResult t) = encodeSuccess t
151+ toJSON (MultilineTextResult ts) = encodeSuccess ts
152+ toJSON (PursuitResult resp) = encodeSuccess resp
153+ toJSON (ImportList decls) = encodeSuccess decls
154+ toJSON (ModuleList modules) = encodeSuccess modules
155+
156+newtype PursuitQuery = PursuitQuery Text
157+ deriving (Show, Eq)
158+
159+data PursuitSearchType = Package | Identifier
160+ deriving (Show, Eq)
161+
162+instance FromJSON PursuitSearchType where
163+ parseJSON (String t) = case t of
164+ "package" -> return Package
165+ "completion" -> return Identifier
166+ _ -> mzero
167+ parseJSON _ = mzero
168+
169+instance FromJSON PursuitQuery where
170+ parseJSON o = fmap PursuitQuery (parseJSON o)
171+
172+data PursuitResponse
173+ = ModuleResponse { moduleResponseName :: Text
174+ , moduleResponsePackage :: Text}
175+ | DeclarationResponse { declarationResponseType :: Text
176+ , declarationResponseModule :: Text
177+ , declarationResponseIdent :: Text
178+ , declarationResponsePackage :: Text
179+ }
180+ deriving (Show,Eq)
181+
182+instance FromJSON PursuitResponse where
183+ parseJSON (Object o) = do
184+ package <- o .: "package"
185+ info <- o .: "info"
186+ (type' :: String) <- info .: "type"
187+ case type' of
188+ "module" -> do
189+ name <- info .: "module"
190+ return
191+ ModuleResponse
192+ { moduleResponseName = name
193+ , moduleResponsePackage = package
194+ }
195+ "declaration" -> do
196+ moduleName <- info .: "module"
197+ Right (ident, declType) <- typeParse <$> o .: "text"
198+ return
199+ DeclarationResponse
200+ { declarationResponseType = declType
201+ , declarationResponseModule = moduleName
202+ , declarationResponseIdent = ident
203+ , declarationResponsePackage = package
204+ }
205+ _ -> mzero
206+ parseJSON _ = mzero
207+
208+
209+typeParse :: Text -> Either Text (Text, Text)
210+typeParse t = case parse parseType "" t of
211+ Right (x,y) -> Right (pack x, pack y)
212+ Left err -> Left (pack (show err))
213+ where
214+ parseType :: Parser (String, String)
215+ parseType = do
216+ name <- identifier
217+ _ <- string "::"
218+ spaces
219+ type' <- many1 anyChar
220+ return (unpack name, type')
221+
222+identifier :: Parser Text
223+identifier = do
224+ spaces
225+ ident <-
226+ -- necessary for being able to parse the following ((++), concat)
227+ between (char '(') (char ')') (many1 (noneOf ", )")) <|>
228+ many1 (noneOf ", )")
229+ spaces
230+ return (pack ident)
231+
232+instance ToJSON PursuitResponse where
233+ toJSON ModuleResponse{..} =
234+ object ["module" .= moduleResponseName, "package" .= moduleResponsePackage]
235+ toJSON DeclarationResponse{..} =
236+ object
237+ [ "module" .= declarationResponseModule
238+ , "ident" .= declarationResponseIdent
239+ , "type" .= declarationResponseType
240+ , "package" .= declarationResponsePackage]
src/Language/PureScript/Ide/Watcher.hsnew file+40
@@ -0,0 +1,40 @@
1+{-# LANGUAGE RecordWildCards #-}
2+module Language.PureScript.Ide.Watcher where
3+
4+import Prelude ()
5+import Prelude.Compat
6+
7+import Control.Concurrent (threadDelay)
8+import Control.Concurrent.STM
9+import Control.Monad
10+import Control.Monad.Trans.Except
11+import qualified Data.Map as M
12+import Data.Maybe (isJust)
13+import Language.PureScript.Externs
14+import Language.PureScript.Ide.Externs
15+import Language.PureScript.Ide.State
16+import Language.PureScript.Ide.Types
17+import System.FilePath
18+import System.FSNotify
19+
20+
21+reloadFile :: TVar PscIdeState -> FilePath -> IO ()
22+reloadFile stateVar fp = do
23+ (Right ef@ExternsFile{..}) <- runExceptT $ readExternFile fp
24+ reloaded <- atomically $ do
25+ st <- readTVar stateVar
26+ if isLoaded efModuleName st
27+ then
28+ insertModule' stateVar ef *> pure True
29+ else
30+ pure False
31+ when reloaded $ putStrLn $ "Reloaded File at: " ++ fp
32+ where
33+ isLoaded name st = isJust (M.lookup name (externsFiles st))
34+
35+watcher :: TVar PscIdeState -> FilePath -> IO ()
36+watcher stateVar fp = withManager $ \mgr -> do
37+ _ <- watchTree mgr fp
38+ (\ev -> takeFileName (eventPath ev) == "externs.json")
39+ (reloadFile stateVar . eventPath)
40+ forever (threadDelay 10000)
src/Language/PureScript/Linter/Imports.hs+14−5
@@ -17,6 +17,7 @@ import Control.Monad.Writer.Class
17import Data.Foldable (forM_)
17import Data.Foldable (forM_)
18import Data.List ((\\), find, intersect, nub)
18import Data.List ((\\), find, intersect, nub)
19import Data.Maybe (mapMaybe)
19import Data.Maybe (mapMaybe)
20+import Data.Monoid (Sum(..))
20import qualified Data.Map as M
21import qualified Data.Map as M
21
22
22import Language.PureScript.AST.Declarations
23import Language.PureScript.AST.Declarations
@@ -78,6 +79,8 @@ lintImports (Module _ _ mn mdecls mexports) env usedImps = do
78
79
79 let scope = maybe nullImports (\(_, imps, _) -> imps) (M.lookup mn env)
80 let scope = maybe nullImports (\(_, imps, _) -> imps) (M.lookup mn env)
80 usedImps' = foldr (elaborateUsed scope) usedImps exportedModules
81 usedImps' = foldr (elaborateUsed scope) usedImps exportedModules
82+ numImplicitImports = getSum $ foldMap (Sum . countImplicitImports) mdecls
83+ allowImplicit = numImplicitImports == 1
81
84
82 imps <- M.toAscList <$> findImports mdecls
85 imps <- M.toAscList <$> findImports mdecls
83
86
@@ -86,7 +89,7 @@ lintImports (Module _ _ mn mdecls mexports) env usedImps = do
86 forM_ decls $ \(ss, declType, qualifierName) ->
89 forM_ decls $ \(ss, declType, qualifierName) ->
87 censor (onErrorMessages $ addModuleLocError ss) $ do
90 censor (onErrorMessages $ addModuleLocError ss) $ do
88 let names = nub $ M.findWithDefault [] mni usedImps'
91 let names = nub $ M.findWithDefault [] mni usedImps'
89− lintImportDecl env mni qualifierName names declType
92+ lintImportDecl env mni qualifierName names declType allowImplicit
90
93
91 forM_ (M.toAscList (byQual imps)) $ \(mnq, entries) -> do
94 forM_ (M.toAscList (byQual imps)) $ \(mnq, entries) -> do
92 let mnis = nub $ map (\(_, _, mni) -> mni) entries
95 let mnis = nub $ map (\(_, _, mni) -> mni) entries
@@ -103,6 +106,11 @@ lintImports (Module _ _ mn mdecls mexports) env usedImps = do
103
106
104 where
107 where
105
108
109+ countImplicitImports :: Declaration -> Int
110+ countImplicitImports (ImportDeclaration mn' Implicit _ _) | not (isPrim mn') = 1
111+ countImplicitImports (PositionedDeclaration _ _ d) = countImplicitImports d
112+ countImplicitImports _ = 0
113+
106 -- Checks whether a module is the Prim module - used to suppress any checks
114 -- Checks whether a module is the Prim module - used to suppress any checks
107 -- made, as Prim is always implicitly imported.
115 -- made, as Prim is always implicitly imported.
108 isPrim :: ModuleName -> Bool
116 isPrim :: ModuleName -> Bool
@@ -148,13 +156,13 @@ lintImports (Module _ _ mn mdecls mexports) env usedImps = do
148 extractByQual
156 extractByQual
149 :: (Eq a)
157 :: (Eq a)
150 => ModuleName
158 => ModuleName
151− -> M.Map (Qualified a) [(Qualified a, ModuleName)]
159+ -> M.Map (Qualified a) [ImportRecord a]
152 -> (Qualified a -> Name)
160 -> (Qualified a -> Name)
153 -> [(ModuleName, Name)]
161 -> [(ModuleName, Name)]
154 extractByQual k m toName = mapMaybe go (M.toList m)
162 extractByQual k m toName = mapMaybe go (M.toList m)
155 where
163 where
156 go (q@(Qualified mnq _), is) | isUnqualified q || isQualifiedWith k q =
164 go (q@(Qualified mnq _), is) | isUnqualified q || isQualifiedWith k q =
157− case fst (head is) of
165+ case importName (head is) of
158 Qualified (Just mn') name -> Just (mn', toName $ Qualified mnq name)
166 Qualified (Just mn') name -> Just (mn', toName $ Qualified mnq name)
159 _ -> internalError "unqualified name in extractByQual"
167 _ -> internalError "unqualified name in extractByQual"
160 go _ = Nothing
168 go _ = Nothing
@@ -167,11 +175,12 @@ lintImportDecl
167 -> Maybe ModuleName
175 -> Maybe ModuleName
168 -> [Name]
176 -> [Name]
169 -> ImportDeclarationType
177 -> ImportDeclarationType
178+ -> Bool
170 -> m ()
179 -> m ()
171−lintImportDecl env mni qualifierName names declType =
180+lintImportDecl env mni qualifierName names declType allowImplicit =
172 case declType of
181 case declType of
173 Implicit -> case qualifierName of
182 Implicit -> case qualifierName of
174− Nothing -> checkImplicit ImplicitImport
183+ Nothing -> unless allowImplicit (checkImplicit ImplicitImport)
175 Just q ->
184 Just q ->
176 let usedModuleNames = mapMaybe extractQualName names
185 let usedModuleNames = mapMaybe extractQualName names
177 in unless (q `elem` usedModuleNames) unused
186 in unless (q `elem` usedModuleNames) unused
src/Language/PureScript/Make.hs+41−6
@@ -31,7 +31,7 @@ import Control.Monad.Writer.Class (MonadWriter(..))
31import Control.Monad.Trans.Class (MonadTrans(..))
31import Control.Monad.Trans.Class (MonadTrans(..))
32import Control.Monad.Trans.Except
32import Control.Monad.Trans.Except
33import Control.Monad.IO.Class
33import Control.Monad.IO.Class
34−import Control.Monad.Reader (MonadReader(..), ReaderT(..))
34+import Control.Monad.Reader (MonadReader(..), ReaderT(..), asks)
35import Control.Monad.Logger
35import Control.Monad.Logger
36import Control.Monad.Supply
36import Control.Monad.Supply
37import Control.Monad.Base (MonadBase(..))
37import Control.Monad.Base (MonadBase(..))
@@ -52,9 +52,12 @@ import qualified Data.ByteString.UTF8 as BU8
52import qualified Data.Set as S
52import qualified Data.Set as S
53import qualified Data.Map as M
53import qualified Data.Map as M
54
54
55+import SourceMap.Types
56+import SourceMap
57+
55import System.Directory
58import System.Directory
56− (doesFileExist, getModificationTime, createDirectoryIfMissing)
59+ (doesFileExist, getModificationTime, createDirectoryIfMissing, getCurrentDirectory)
57−import System.FilePath ((</>), takeDirectory)
60+import System.FilePath ((</>), takeDirectory, makeRelative, splitPath, normalise)
58import System.IO.Error (tryIOError)
61import System.IO.Error (tryIOError)
59import System.IO.UTF8 (readUTF8File, writeUTF8File)
62import System.IO.UTF8 (readUTF8File, writeUTF8File)
60
63
@@ -68,6 +71,7 @@ import Language.PureScript.ModuleDependencies
68import Language.PureScript.Names
71import Language.PureScript.Names
69import Language.PureScript.Options
72import Language.PureScript.Options
70import Language.PureScript.Pretty
73import Language.PureScript.Pretty
74+import Language.PureScript.Pretty.Common(SMap(..))
71import Language.PureScript.Renamer
75import Language.PureScript.Renamer
72import Language.PureScript.Sugar
76import Language.PureScript.Sugar
73import Language.PureScript.TypeChecker
77import Language.PureScript.TypeChecker
@@ -324,20 +328,51 @@ buildMakeActions outputDir filePathMap foreigns usePrefix =
324 | not $ requiresForeign m -> do
328 | not $ requiresForeign m -> do
325 tell $ errorMessage $ UnnecessaryFFIModule mn path
329 tell $ errorMessage $ UnnecessaryFFIModule mn path
326 return Nothing
330 return Nothing
327− | otherwise -> return $ Just $ J.JSApp (J.JSVar "require") [J.JSStringLiteral "./foreign"]
331+ | otherwise -> return $ Just $ J.JSApp Nothing (J.JSVar Nothing "require") [J.JSStringLiteral Nothing "./foreign"]
328 Nothing | requiresForeign m -> throwError . errorMessage $ MissingFFIModule mn
332 Nothing | requiresForeign m -> throwError . errorMessage $ MissingFFIModule mn
329 | otherwise -> return Nothing
333 | otherwise -> return Nothing
330− pjs <- prettyPrintJS <$> J.moduleToJs m foreignInclude
334+ rawJs <- J.moduleToJs m foreignInclude
335+ dir <- lift $ makeIO (const (ErrorMessage [] $ CannotGetFileInfo ".")) getCurrentDirectory
336+ sourceMaps <- lift $ asks optionsSourceMaps
337+ let (pjs, mappings) = if sourceMaps then prettyPrintJSWithSourceMaps rawJs else (prettyPrintJS rawJs, [])
331 let filePath = runModuleName mn
338 let filePath = runModuleName mn
332 jsFile = outputDir </> filePath </> "index.js"
339 jsFile = outputDir </> filePath </> "index.js"
340+ mapFile = outputDir </> filePath </> "index.js.map"
333 externsFile = outputDir </> filePath </> "externs.json"
341 externsFile = outputDir </> filePath </> "externs.json"
334 foreignFile = outputDir </> filePath </> "foreign.js"
342 foreignFile = outputDir </> filePath </> "foreign.js"
335 prefix = ["Generated by psc version " ++ showVersion Paths.version | usePrefix]
343 prefix = ["Generated by psc version " ++ showVersion Paths.version | usePrefix]
336 js = unlines $ map ("// " ++) prefix ++ [pjs]
344 js = unlines $ map ("// " ++) prefix ++ [pjs]
345+ mapRef = if sourceMaps then "//# sourceMappingURL=index.js.map\n" else ""
337 lift $ do
346 lift $ do
338− writeTextFile jsFile (fromString js)
347+ writeTextFile jsFile (fromString $ js ++ mapRef)
339 for_ (mn `M.lookup` foreigns) (readTextFile >=> writeTextFile foreignFile)
348 for_ (mn `M.lookup` foreigns) (readTextFile >=> writeTextFile foreignFile)
340 writeTextFile externsFile exts
349 writeTextFile externsFile exts
350+ lift $ when sourceMaps $ genSourceMap dir mapFile (length prefix) mappings
351+
352+ genSourceMap :: String -> String -> Int -> [SMap] -> Make ()
353+ genSourceMap dir mapFile extraLines mappings = do
354+ let pathToDir = iterate (".." </>) ".." !! length (splitPath $ normalise outputDir)
355+ sourceFile = case mappings of
356+ ((SMap file _ _):_) -> Just $ pathToDir </> makeRelative dir file
357+ _ -> Nothing
358+ let rawMapping = SourceMapping { smFile = "index.js", smSourceRoot = Nothing, smMappings =
359+ map (\(SMap _ orig gen) -> Mapping {
360+ mapOriginal = Just $ convertPos $ add 0 (-1) orig
361+ , mapSourceFile = sourceFile
362+ , mapGenerated = convertPos $ add (extraLines+1) 0 gen
363+ , mapName = Nothing
364+ }) $
365+ mappings
366+ }
367+ let mapping = generate rawMapping
368+ writeTextFile mapFile $ BU8.toString . B.toStrict . encode $ mapping
369+ where
370+ add :: Int -> Int -> SourcePos -> SourcePos
371+ add n m (SourcePos n' m') = SourcePos (n+n') (m+m')
372+
373+ convertPos :: SourcePos -> Pos
374+ convertPos SourcePos { sourcePosLine = l, sourcePosColumn = c } =
375+ Pos { posLine = fromIntegral l, posColumn = fromIntegral c }
341
376
342 requiresForeign :: CF.Module a -> Bool
377 requiresForeign :: CF.Module a -> Bool
343 requiresForeign = not . null . CF.moduleForeign
378 requiresForeign = not . null . CF.moduleForeign
src/Language/PureScript/Options.hs+4−1
@@ -41,9 +41,12 @@ data Options = Options {
41 -- |
41 -- |
42 -- The path to prepend to require statements
42 -- The path to prepend to require statements
43 , optionsRequirePath :: Maybe FilePath
43 , optionsRequirePath :: Maybe FilePath
44+ -- |
45+ -- Generate soure maps
46+ , optionsSourceMaps :: Bool
44 } deriving Show
47 } deriving Show
45
48
46-- |
49-- |
47-- Default make options
50-- Default make options
48defaultOptions :: Options
51defaultOptions :: Options
49−defaultOptions = Options False False Nothing False False False Nothing
52+defaultOptions = Options False False Nothing False False False Nothing False
src/Language/PureScript/Pretty.hs−3
@@ -27,6 +27,3 @@ import Language.PureScript.Pretty.Kinds as P
27import Language.PureScript.Pretty.Values as P
27import Language.PureScript.Pretty.Values as P
28import Language.PureScript.Pretty.Types as P
28import Language.PureScript.Pretty.Types as P
29import Language.PureScript.Pretty.JS as P
29import Language.PureScript.Pretty.JS as P
30−
31−
32−
src/Language/PureScript/Pretty/Common.hs+96−9
@@ -13,12 +13,18 @@
13--
13--
14-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
15
15
16+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
17+
16module Language.PureScript.Pretty.Common where
18module Language.PureScript.Pretty.Common where
17
19
20+import Prelude ()
21+import Prelude.Compat
22+
18−import Control.Monad.State
23+import Control.Monad.State (StateT, modify, get)
19−import Data.List (intercalate)
24+import Data.List (elemIndices, intersperse)
20
25
21import Language.PureScript.Parser.Lexer (reservedPsNames, isSymbolChar)
26import Language.PureScript.Parser.Lexer (reservedPsNames, isSymbolChar)
27+import Language.PureScript.AST (SourcePos(..), SourceSpan(..))
22
28
23import Text.PrettyPrint.Boxes
29import Text.PrettyPrint.Boxes
24
30
@@ -26,9 +32,90 @@ import Text.PrettyPrint.Boxes
26-- Wrap a string in parentheses
32-- Wrap a string in parentheses
27--
33--
28parens :: String -> String
34parens :: String -> String
29−parens s = ('(':s) ++ ")"
35+parens s = '(':s ++ ")"
36+
37+parensPos :: (Emit gen) => gen -> gen
38+parensPos s = emit "(" `mappend` s `mappend` emit ")"
39+
40+-- |
41+-- Generalize intercalate slightly for monoids
42+--
43+intercalate :: Monoid m => m -> [m] -> m
44+intercalate x xs = mconcat (intersperse x xs)
45+
46+class (Monoid gen) => Emit gen where
47+ emit :: String -> gen
48+ addMapping :: SourceSpan -> gen
49+
50+data SMap = SMap String SourcePos SourcePos
51+
52+-- |
53+-- String with length and source-map entries
54+--
55+newtype StrPos = StrPos (SourcePos, String, [SMap])
56+
57+-- |
58+-- Make a monoid where append consists of concatenating the string part, adding the lengths
59+-- appropriately and advancing source mappings on the right hand side to account for
60+-- the length of the left.
61+--
62+instance Monoid StrPos where
63+ mempty = StrPos (SourcePos 0 0, "", [])
64+
65+ StrPos (a,b,c) `mappend` StrPos (a',b',c') = StrPos (a `addPos` a', b ++ b', c ++ (bumpPos a <$> c'))
66+
67+ mconcat ms =
68+ let s' = concatMap (\(StrPos(_, s, _)) -> s) ms
69+ (p, maps) = foldl plus (SourcePos 0 0, []) ms
70+ in
71+ StrPos (p, s', concat $ reverse maps)
72+ where
73+ plus :: (SourcePos, [[SMap]]) -> StrPos -> (SourcePos, [[SMap]])
74+ plus (a, c) (StrPos (a', _, c')) = (a `addPos` a', (bumpPos a <$> c') : c)
75+
76+instance Emit StrPos where
77+ -- |
78+ -- Augment a string with its length (rows/column)
79+ --
80+ emit str =
81+ let newlines = elemIndices '\n' str
82+ index = if null newlines then 0 else last newlines + 1
83+ in
84+ StrPos (SourcePos { sourcePosLine = length newlines, sourcePosColumn = length str - index }, str, [])
85+
86+ -- |
87+ -- Add a new mapping entry for given source position with initially zero generated position
88+ --
89+ addMapping (SourceSpan { spanName = file, spanStart = startPos }) = StrPos (zeroPos, mempty, [mapping])
90+ where
91+ mapping = SMap file startPos zeroPos
92+ zeroPos = SourcePos 0 0
93+
94+newtype PlainString = PlainString String deriving Monoid
95+
96+runPlainString :: PlainString -> String
97+runPlainString (PlainString s) = s
98+
99+instance Emit PlainString where
100+ emit = PlainString
101+ addMapping _ = mempty
102+
103+addMapping' :: (Emit gen) => Maybe SourceSpan -> gen
104+addMapping' (Just ss) = addMapping ss
105+addMapping' Nothing = mempty
106+
107+bumpPos :: SourcePos -> SMap -> SMap
108+bumpPos p (SMap f s g) = SMap f s $ p `addPos` g
109+
110+addPos :: SourcePos -> SourcePos -> SourcePos
111+addPos (SourcePos n m) (SourcePos 0 m') = SourcePos n (m+m')
112+addPos (SourcePos n _) (SourcePos n' m') = SourcePos (n+n') m'
113+
114+
115+data PrinterState = PrinterState { indent :: Int }
30
116
31−newtype PrinterState = PrinterState { indent :: Int } deriving (Show, Read, Eq, Ord)
117+emptyPrinterState :: PrinterState
118+emptyPrinterState = PrinterState { indent = 0 }
32
119
33-- |
120-- |
34-- Number of characters per identation level
121-- Number of characters per identation level
@@ -39,7 +126,7 @@ blockIndent = 4
39-- |
126-- |
40-- Pretty print with a new indentation level
127-- Pretty print with a new indentation level
41--
128--
42−withIndent :: StateT PrinterState Maybe String -> StateT PrinterState Maybe String
129+withIndent :: (Emit gen) => StateT PrinterState Maybe gen -> StateT PrinterState Maybe gen
43withIndent action = do
130withIndent action = do
44 modify $ \st -> st { indent = indent st + blockIndent }
131 modify $ \st -> st { indent = indent st + blockIndent }
45 result <- action
132 result <- action
@@ -49,19 +136,19 @@ withIndent action = do
49-- |
136-- |
50-- Get the current indentation level
137-- Get the current indentation level
51--
138--
52−currentIndent :: StateT PrinterState Maybe String
139+currentIndent :: (Emit gen) => StateT PrinterState Maybe gen
53currentIndent = do
140currentIndent = do
54 current <- get
141 current <- get
55− return $ replicate (indent current) ' '
142+ return $ emit $ replicate (indent current) ' '
56
143
57-- |
144-- |
58-- Print many lines
145-- Print many lines
59--
146--
60−prettyPrintMany :: (a -> StateT PrinterState Maybe String) -> [a] -> StateT PrinterState Maybe String
147+prettyPrintMany :: (Emit gen) => (a -> StateT PrinterState Maybe gen) -> [a] -> StateT PrinterState Maybe gen
61prettyPrintMany f xs = do
148prettyPrintMany f xs = do
62 ss <- mapM f xs
149 ss <- mapM f xs
63 indentString <- currentIndent
150 indentString <- currentIndent
64− return $ intercalate "\n" $ map (indentString ++) ss
151+ return $ intercalate (emit "\n") $ map (\s -> mappend indentString s) ss
65
152
66-- |
153-- |
67-- Prints an object key, escaping reserved names.
154-- Prints an object key, escaping reserved names.
src/Language/PureScript/Pretty/JS.hs+118−105
@@ -14,13 +14,12 @@
14-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
15
15
16module Language.PureScript.Pretty.JS (
16module Language.PureScript.Pretty.JS (
17− prettyPrintJS
17+ prettyPrintJS, prettyPrintJSWithSourceMaps
18) where
18) where
19
19
20import Prelude ()
20import Prelude ()
21import Prelude.Compat
21import Prelude.Compat
22
22
23−import Data.List hiding (concat, concatMap)
24import Data.Maybe (fromMaybe)
23import Data.Maybe (fromMaybe)
25
24
26import Control.Arrow ((<+>))
25import Control.Arrow ((<+>))
@@ -34,103 +33,110 @@ import Language.PureScript.CodeGen.JS.Common
34import Language.PureScript.Pretty.Common
33import Language.PureScript.Pretty.Common
35import Language.PureScript.Comments
34import Language.PureScript.Comments
36
35
36+
37+import Language.PureScript.AST (SourceSpan(..))
38+
37import Numeric
39import Numeric
38
40
41+import Data.Monoid
42+
39−literals :: Pattern PrinterState JS String
43+literals :: (Emit gen) => Pattern PrinterState JS gen
40−literals = mkPattern' match
44+literals = mkPattern' match'
41 where
45 where
46+ match' :: (Emit gen) => JS -> StateT PrinterState Maybe gen
47+ match' js = (addMapping' (getSourceSpan js) <>) <$> match js
48+
42− match :: JS -> StateT PrinterState Maybe String
49+ match :: (Emit gen) => JS -> StateT PrinterState Maybe gen
43− match (JSNumericLiteral n) = return $ either show show n
50+ match (JSNumericLiteral _ n) = return $ emit $ either show show n
44− match (JSStringLiteral s) = return $ string s
51+ match (JSStringLiteral _ s) = return $ string s
45− match (JSBooleanLiteral True) = return "true"
52+ match (JSBooleanLiteral _ True) = return $ emit "true"
46− match (JSBooleanLiteral False) = return "false"
53+ match (JSBooleanLiteral _ False) = return $ emit "false"
47− match (JSArrayLiteral xs) = concat <$> sequence
54+ match (JSArrayLiteral _ xs) = mconcat <$> sequence
48− [ return "[ "
55+ [ return $ emit "[ "
49− , intercalate ", " <$> forM xs prettyPrintJS'
56+ , intercalate (emit ", ") <$> forM xs prettyPrintJS'
50− , return " ]"
57+ , return $ emit " ]"
51 ]
58 ]
52− match (JSObjectLiteral []) = return "{}"
59+ match (JSObjectLiteral _ []) = return $ emit "{}"
53− match (JSObjectLiteral ps) = concat <$> sequence
60+ match (JSObjectLiteral _ ps) = mconcat <$> sequence
54− [ return "{\n"
61+ [ return $ emit "{\n"
55 , withIndent $ do
62 , withIndent $ do
56− jss <- forM ps $ \(key, value) -> fmap ((objectPropertyToString key ++ ": ") ++) . prettyPrintJS' $ value
63+ jss <- forM ps $ \(key, value) -> fmap ((objectPropertyToString key <> emit ": ") <>) . prettyPrintJS' $ value
57 indentString <- currentIndent
64 indentString <- currentIndent
58− return $ intercalate ", \n" $ map (indentString ++) jss
65+ return $ intercalate (emit ", \n") $ map (indentString <>) jss
59− , return "\n"
66+ , return $ emit "\n"
60 , currentIndent
67 , currentIndent
61− , return "}"
68+ , return $ emit "}"
62 ]
69 ]
63 where
70 where
64− objectPropertyToString :: String -> String
71+ objectPropertyToString :: (Emit gen) => String -> gen
65− objectPropertyToString s | identNeedsEscaping s = show s
72+ objectPropertyToString s | identNeedsEscaping s = emit $ show s
66− | otherwise = s
73+ | otherwise = emit s
67− match (JSBlock sts) = concat <$> sequence
74+ match (JSBlock _ sts) = mconcat <$> sequence
68− [ return "{\n"
75+ [ return $ emit "{\n"
69 , withIndent $ prettyStatements sts
76 , withIndent $ prettyStatements sts
70− , return "\n"
77+ , return $ emit "\n"
71 , currentIndent
78 , currentIndent
72− , return "}"
79+ , return $ emit "}"
73 ]
80 ]
74− match (JSVar ident) = return ident
81+ match (JSVar _ ident) = return $ emit ident
75− match (JSVariableIntroduction ident value) = concat <$> sequence
82+ match (JSVariableIntroduction _ ident value) = mconcat <$> sequence
76− [ return "var "
83+ [ return $ emit $ "var " ++ ident
77− , return ident
78− , maybe (return "") (fmap (" = " ++) . prettyPrintJS') value
84+ , maybe (return mempty) (fmap (emit " = " <>) . prettyPrintJS') value
79 ]
85 ]
80− match (JSAssignment target value) = concat <$> sequence
86+ match (JSAssignment _ target value) = mconcat <$> sequence
81 [ prettyPrintJS' target
87 [ prettyPrintJS' target
82− , return " = "
88+ , return $ emit " = "
83 , prettyPrintJS' value
89 , prettyPrintJS' value
84 ]
90 ]
85− match (JSWhile cond sts) = concat <$> sequence
91+ match (JSWhile _ cond sts) = mconcat <$> sequence
86− [ return "while ("
92+ [ return $ emit "while ("
87 , prettyPrintJS' cond
93 , prettyPrintJS' cond
88− , return ") "
94+ , return $ emit ") "
89 , prettyPrintJS' sts
95 , prettyPrintJS' sts
90 ]
96 ]
91− match (JSFor ident start end sts) = concat <$> sequence
97+ match (JSFor _ ident start end sts) = mconcat <$> sequence
92− [ return $ "for (var " ++ ident ++ " = "
98+ [ return $ emit $ "for (var " ++ ident ++ " = "
93 , prettyPrintJS' start
99 , prettyPrintJS' start
94− , return $ "; " ++ ident ++ " < "
100+ , return $ emit $ "; " ++ ident ++ " < "
95 , prettyPrintJS' end
101 , prettyPrintJS' end
96− , return $ "; " ++ ident ++ "++) "
102+ , return $ emit $ "; " ++ ident ++ "++) "
97 , prettyPrintJS' sts
103 , prettyPrintJS' sts
98 ]
104 ]
99− match (JSForIn ident obj sts) = concat <$> sequence
105+ match (JSForIn _ ident obj sts) = mconcat <$> sequence
100− [ return $ "for (var " ++ ident ++ " in "
106+ [ return $ emit $ "for (var " ++ ident ++ " in "
101 , prettyPrintJS' obj
107 , prettyPrintJS' obj
102− , return ") "
108+ , return $ emit ") "
103 , prettyPrintJS' sts
109 , prettyPrintJS' sts
104 ]
110 ]
105− match (JSIfElse cond thens elses) = concat <$> sequence
111+ match (JSIfElse _ cond thens elses) = mconcat <$> sequence
106− [ return "if ("
112+ [ return $ emit "if ("
107 , prettyPrintJS' cond
113 , prettyPrintJS' cond
108− , return ") "
114+ , return $ emit ") "
109 , prettyPrintJS' thens
115 , prettyPrintJS' thens
110− , maybe (return "") (fmap (" else " ++) . prettyPrintJS') elses
116+ , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintJS') elses
111 ]
117 ]
112− match (JSReturn value) = concat <$> sequence
118+ match (JSReturn _ value) = mconcat <$> sequence
113− [ return "return "
119+ [ return $ emit "return "
114 , prettyPrintJS' value
120 , prettyPrintJS' value
115 ]
121 ]
116− match (JSThrow value) = concat <$> sequence
122+ match (JSThrow _ value) = mconcat <$> sequence
117− [ return "throw "
123+ [ return $ emit "throw "
118 , prettyPrintJS' value
124 , prettyPrintJS' value
119 ]
125 ]
120− match (JSBreak lbl) = return $ "break " ++ lbl
126+ match (JSBreak _ lbl) = return $ emit $ "break " ++ lbl
121− match (JSContinue lbl) = return $ "continue " ++ lbl
127+ match (JSContinue _ lbl) = return $ emit $ "continue " ++ lbl
122− match (JSLabel lbl js) = concat <$> sequence
128+ match (JSLabel _ lbl js) = mconcat <$> sequence
123− [ return $ lbl ++ ": "
129+ [ return $ emit $ lbl ++ ": "
124 , prettyPrintJS' js
130 , prettyPrintJS' js
125 ]
131 ]
126− match (JSComment com js) = fmap concat $ sequence $
132+ match (JSComment _ com js) = fmap mconcat $ sequence $
127− [ return "\n"
133+ [ return $ emit "\n"
128 , currentIndent
134 , currentIndent
129− , return "/**\n"
135+ , return $ emit "/**\n"
130 ] ++
136 ] ++
131 map asLine (concatMap commentLines com) ++
137 map asLine (concatMap commentLines com) ++
132 [ currentIndent
138 [ currentIndent
133− , return " */\n"
139+ , return $ emit " */\n"
134 , currentIndent
140 , currentIndent
135 , prettyPrintJS' js
141 , prettyPrintJS' js
136 ]
142 ]
@@ -139,21 +145,21 @@ literals = mkPattern' match
139 commentLines (LineComment s) = [s]
145 commentLines (LineComment s) = [s]
140 commentLines (BlockComment s) = lines s
146 commentLines (BlockComment s) = lines s
141
147
142− asLine :: String -> StateT PrinterState Maybe String
148+ asLine :: (Emit gen) => String -> StateT PrinterState Maybe gen
143 asLine s = do
149 asLine s = do
144 i <- currentIndent
150 i <- currentIndent
145− return $ i ++ " * " ++ removeComments s ++ "\n"
151+ return $ i <> emit " * " <> (emit . removeComments) s <> emit "\n"
146
152
147 removeComments :: String -> String
153 removeComments :: String -> String
148 removeComments ('*' : '/' : s) = removeComments s
154 removeComments ('*' : '/' : s) = removeComments s
149 removeComments (c : s) = c : removeComments s
155 removeComments (c : s) = c : removeComments s
150
156
151 removeComments [] = []
157 removeComments [] = []
152− match (JSRaw js) = return js
158+ match (JSRaw _ js) = return $ emit js
153 match _ = mzero
159 match _ = mzero
154
160
155−string :: String -> String
161+string :: (Emit gen) => String -> gen
156−string s = '"' : concatMap encodeChar s ++ "\""
162+string s = emit $ '"' : concatMap encodeChar s ++ "\""
157 where
163 where
158 encodeChar :: Char -> String
164 encodeChar :: Char -> String
159 encodeChar '\b' = "\\b"
165 encodeChar '\b' = "\\b"
@@ -175,114 +181,121 @@ string s = '"' : concatMap encodeChar s ++ "\""
175 encodeChar c | fromEnum c > 0x7E || fromEnum c < 0x20 = "\\x" ++ showHex (fromEnum c) ""
181 encodeChar c | fromEnum c > 0x7E || fromEnum c < 0x20 = "\\x" ++ showHex (fromEnum c) ""
176 encodeChar c = [c]
182 encodeChar c = [c]
177
183
178−conditional :: Pattern PrinterState JS ((JS, JS), JS)
184+conditional :: Pattern PrinterState JS ((Maybe SourceSpan, JS, JS), JS)
179conditional = mkPattern match
185conditional = mkPattern match
180 where
186 where
181− match (JSConditional cond th el) = Just ((th, el), cond)
187+ match (JSConditional ss cond th el) = Just ((ss, th, el), cond)
182 match _ = Nothing
188 match _ = Nothing
183
189
184−accessor :: Pattern PrinterState JS (String, JS)
190+accessor :: (Emit gen) => Pattern PrinterState JS (gen, JS)
185accessor = mkPattern match
191accessor = mkPattern match
186 where
192 where
187− match (JSAccessor prop val) = Just (prop, val)
193+ match (JSAccessor _ prop val) = Just (emit prop, val)
188 match _ = Nothing
194 match _ = Nothing
189
195
190−indexer :: Pattern PrinterState JS (String, JS)
196+indexer :: (Emit gen) => Pattern PrinterState JS (gen, JS)
191indexer = mkPattern' match
197indexer = mkPattern' match
192 where
198 where
193− match (JSIndexer index val) = (,) <$> prettyPrintJS' index <*> pure val
199+ match (JSIndexer _ index val) = (,) <$> prettyPrintJS' index <*> pure val
200+
194 match _ = mzero
201 match _ = mzero
195
202
196−lam :: Pattern PrinterState JS ((Maybe String, [String]), JS)
203+lam :: Pattern PrinterState JS ((Maybe String, [String], Maybe SourceSpan), JS)
197lam = mkPattern match
204lam = mkPattern match
198 where
205 where
199− match (JSFunction name args ret) = Just ((name, args), ret)
206+ match (JSFunction ss name args ret) = Just ((name, args, ss), ret)
200 match _ = Nothing
207 match _ = Nothing
201
208
202−app :: Pattern PrinterState JS (String, JS)
209+app :: (Emit gen) => Pattern PrinterState JS (gen, JS)
203app = mkPattern' match
210app = mkPattern' match
204 where
211 where
205− match (JSApp val args) = do
212+ match (JSApp _ val args) = do
206 jss <- traverse prettyPrintJS' args
213 jss <- traverse prettyPrintJS' args
207− return (intercalate ", " jss, val)
214+ return (intercalate (emit ", ") jss, val)
208 match _ = mzero
215 match _ = mzero
209
216
210typeOf :: Pattern PrinterState JS ((), JS)
217typeOf :: Pattern PrinterState JS ((), JS)
211typeOf = mkPattern match
218typeOf = mkPattern match
212 where
219 where
213− match (JSTypeOf val) = Just ((), val)
220+ match (JSTypeOf _ val) = Just ((), val)
214 match _ = Nothing
221 match _ = Nothing
215
222
216instanceOf :: Pattern PrinterState JS (JS, JS)
223instanceOf :: Pattern PrinterState JS (JS, JS)
217instanceOf = mkPattern match
224instanceOf = mkPattern match
218 where
225 where
219− match (JSInstanceOf val ty) = Just (val, ty)
226+ match (JSInstanceOf _ val ty) = Just (val, ty)
220 match _ = Nothing
227 match _ = Nothing
221
228
222−unary' :: UnaryOperator -> (JS -> String) -> Operator PrinterState JS String
229+unary' :: (Emit gen) => UnaryOperator -> (JS -> String) -> Operator PrinterState JS gen
223−unary' op mkStr = Wrap match (++)
230+unary' op mkStr = Wrap match (<>)
224 where
231 where
225− match :: Pattern PrinterState JS (String, JS)
232+ match :: (Emit gen) => Pattern PrinterState JS (gen, JS)
226 match = mkPattern match'
233 match = mkPattern match'
227 where
234 where
228− match' (JSUnary op' val) | op' == op = Just (mkStr val, val)
235+ match' (JSUnary _ op' val) | op' == op = Just (emit $ mkStr val, val)
229 match' _ = Nothing
236 match' _ = Nothing
230
237
231−unary :: UnaryOperator -> String -> Operator PrinterState JS String
238+unary :: (Emit gen) => UnaryOperator -> String -> Operator PrinterState JS gen
232unary op str = unary' op (const str)
239unary op str = unary' op (const str)
233
240
234−negateOperator :: Operator PrinterState JS String
241+negateOperator :: (Emit gen) => Operator PrinterState JS gen
235negateOperator = unary' Negate (\v -> if isNegate v then "- " else "-")
242negateOperator = unary' Negate (\v -> if isNegate v then "- " else "-")
236 where
243 where
237− isNegate (JSUnary Negate _) = True
244+ isNegate (JSUnary _ Negate _) = True
238 isNegate _ = False
245 isNegate _ = False
239
246
240−binary :: BinaryOperator -> String -> Operator PrinterState JS String
247+binary :: (Emit gen) => BinaryOperator -> String -> Operator PrinterState JS gen
241−binary op str = AssocL match (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)
248+binary op str = AssocL match (\v1 v2 -> v1 <> emit (" " ++ str ++ " ") <> v2)
242 where
249 where
243 match :: Pattern PrinterState JS (JS, JS)
250 match :: Pattern PrinterState JS (JS, JS)
244 match = mkPattern match'
251 match = mkPattern match'
245 where
252 where
246− match' (JSBinary op' v1 v2) | op' == op = Just (v1, v2)
253+ match' (JSBinary _ op' v1 v2) | op' == op = Just (v1, v2)
247 match' _ = Nothing
254 match' _ = Nothing
248
255
249−prettyStatements :: [JS] -> StateT PrinterState Maybe String
256+prettyStatements :: (Emit gen) => [JS] -> StateT PrinterState Maybe gen
250prettyStatements sts = do
257prettyStatements sts = do
251 jss <- forM sts prettyPrintJS'
258 jss <- forM sts prettyPrintJS'
252 indentString <- currentIndent
259 indentString <- currentIndent
253− return $ intercalate "\n" $ map ((++ ";") . (indentString ++)) jss
260+ return $ intercalate (emit "\n") $ map ((<> emit ";") . (indentString <>)) jss
254
261
255-- |
262-- |
256-- Generate a pretty-printed string representing a Javascript expression
263-- Generate a pretty-printed string representing a Javascript expression
257--
264--
258−prettyPrintJS1 :: JS -> String
265+prettyPrintJS1 :: (Emit gen) => JS -> gen
259prettyPrintJS1 = fromMaybe (internalError "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyPrintJS'
266prettyPrintJS1 = fromMaybe (internalError "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyPrintJS'
260
267
261-- |
268-- |
262-- Generate a pretty-printed string representing a collection of Javascript expressions at the same indentation level
269-- Generate a pretty-printed string representing a collection of Javascript expressions at the same indentation level
263--
270--
271+prettyPrintJSWithSourceMaps :: [JS] -> (String, [SMap])
272+prettyPrintJSWithSourceMaps js =
273+ let StrPos (_, s, mp) = (fromMaybe (internalError "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyStatements) js
274+ in (s, mp)
275+
264prettyPrintJS :: [JS] -> String
276prettyPrintJS :: [JS] -> String
265−prettyPrintJS = fromMaybe (internalError "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyStatements
277+prettyPrintJS = fromMaybe (internalError "Incomplete pattern") . fmap runPlainString . flip evalStateT (PrinterState 0) . prettyStatements
266
278
267-- |
279-- |
268-- Generate an indented, pretty-printed string representing a Javascript expression
280-- Generate an indented, pretty-printed string representing a Javascript expression
269--
281--
270−prettyPrintJS' :: JS -> StateT PrinterState Maybe String
282+prettyPrintJS' :: (Emit gen) => JS -> StateT PrinterState Maybe gen
271prettyPrintJS' = A.runKleisli $ runPattern matchValue
283prettyPrintJS' = A.runKleisli $ runPattern matchValue
272 where
284 where
273− matchValue :: Pattern PrinterState JS String
285+ matchValue :: (Emit gen) => Pattern PrinterState JS gen
274− matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)
286+ matchValue = buildPrettyPrinter operators (literals <+> fmap parensPos matchValue)
275− operators :: OperatorTable PrinterState JS String
287+ operators :: (Emit gen) => OperatorTable PrinterState JS gen
276 operators =
288 operators =
277− OperatorTable [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ]
289+ OperatorTable [ [ Wrap accessor $ \prop val -> val <> emit "." <> prop ]
278− , [ Wrap indexer $ \index val -> val ++ "[" ++ index ++ "]" ]
290+ , [ Wrap indexer $ \index val -> val <> emit "[" <> index <> emit "]" ]
279− , [ Wrap app $ \args val -> val ++ "(" ++ args ++ ")" ]
291+ , [ Wrap app $ \args val -> val <> emit "(" <> args <> emit ")" ]
280 , [ unary JSNew "new " ]
292 , [ unary JSNew "new " ]
281− , [ Wrap lam $ \(name, args) ret -> "function "
293+ , [ Wrap lam $ \(name, args, ss) ret -> addMapping' ss <>
294+ emit ("function "
282 ++ fromMaybe "" name
295 ++ fromMaybe "" name
283− ++ "(" ++ intercalate ", " args ++ ") "
296+ ++ "(" ++ intercalate ", " args ++ ") ")
284− ++ ret ]
297+ <> ret ]
285− , [ Wrap typeOf $ \_ s -> "typeof " ++ s ]
298+ , [ Wrap typeOf $ \_ s -> emit "typeof " <> s ]
286 , [ unary Not "!"
299 , [ unary Not "!"
287 , unary BitwiseNot "~"
300 , unary BitwiseNot "~"
288 , unary Positive "+"
301 , unary Positive "+"
@@ -299,7 +312,7 @@ prettyPrintJS' = A.runKleisli $ runPattern matchValue
299 , binary LessThanOrEqualTo "<="
312 , binary LessThanOrEqualTo "<="
300 , binary GreaterThan ">"
313 , binary GreaterThan ">"
301 , binary GreaterThanOrEqualTo ">="
314 , binary GreaterThanOrEqualTo ">="
302− , AssocR instanceOf $ \v1 v2 -> v1 ++ " instanceof " ++ v2 ]
315+ , AssocR instanceOf $ \v1 v2 -> v1 <> emit " instanceof " <> v2 ]
303 , [ binary EqualTo "==="
316 , [ binary EqualTo "==="
304 , binary NotEqualTo "!==" ]
317 , binary NotEqualTo "!==" ]
305 , [ binary BitwiseAnd "&" ]
318 , [ binary BitwiseAnd "&" ]
@@ -307,5 +320,5 @@ prettyPrintJS' = A.runKleisli $ runPattern matchValue
307 , [ binary BitwiseOr "|" ]
320 , [ binary BitwiseOr "|" ]
308 , [ binary And "&&" ]
321 , [ binary And "&&" ]
309 , [ binary Or "||" ]
322 , [ binary Or "||" ]
310− , [ Wrap conditional $ \(th, el) cond -> cond ++ " ? " ++ prettyPrintJS1 th ++ " : " ++ prettyPrintJS1 el ]
323+ , [ Wrap conditional $ \(ss, th, el) cond -> cond <> addMapping' ss <> emit " ? " <> prettyPrintJS1 th <> addMapping' ss <> emit " : " <> prettyPrintJS1 el ]
311 ]
324 ]
src/Language/PureScript/Pretty/Values.hs−2
@@ -19,8 +19,6 @@ module Language.PureScript.Pretty.Values (
19 prettyPrintBinderAtom
19 prettyPrintBinderAtom
20) where
20) where
21
21
22−import Data.List (intercalate)
23−
24import Control.Arrow (second)
22import Control.Arrow (second)
25
23
26import Language.PureScript.Crash
24import Language.PureScript.Crash
src/Language/PureScript/Renamer.hs+9−9
@@ -105,8 +105,8 @@ lookupIdent name = do
105findDeclIdents :: [Bind Ann] -> [Ident]
105findDeclIdents :: [Bind Ann] -> [Ident]
106findDeclIdents = concatMap go
106findDeclIdents = concatMap go
107 where
107 where
108− go (NonRec ident _) = [ident]
108+ go (NonRec _ ident _) = [ident]
109− go (Rec ds) = map fst ds
109+ go (Rec ds) = map (snd . fst) ds
110
110
111-- |
111-- |
112-- Renames within each declaration in a module.
112-- Renames within each declaration in a module.
@@ -128,19 +128,19 @@ renameInModules = map go
128-- another in the current scope.
128-- another in the current scope.
129--
129--
130renameInDecl :: Bool -> Bind Ann -> Rename (Bind Ann)
130renameInDecl :: Bool -> Bind Ann -> Rename (Bind Ann)
131−renameInDecl isTopLevel (NonRec name val) = do
131+renameInDecl isTopLevel (NonRec a name val) = do
132 name' <- if isTopLevel then return name else updateScope name
132 name' <- if isTopLevel then return name else updateScope name
133− NonRec name' <$> renameInValue val
133+ NonRec a name' <$> renameInValue val
134renameInDecl isTopLevel (Rec ds) = do
134renameInDecl isTopLevel (Rec ds) = do
135 ds' <- traverse updateNames ds
135 ds' <- traverse updateNames ds
136 Rec <$> traverse updateValues ds'
136 Rec <$> traverse updateValues ds'
137 where
137 where
138− updateNames :: (Ident, Expr Ann) -> Rename (Ident, Expr Ann)
138+ updateNames :: ((Ann, Ident), Expr Ann) -> Rename ((Ann, Ident), Expr Ann)
139− updateNames (name, val) = do
139+ updateNames ((a, name), val) = do
140 name' <- if isTopLevel then return name else updateScope name
140 name' <- if isTopLevel then return name else updateScope name
141− return (name', val)
141+ return ((a, name'), val)
142− updateValues :: (Ident, Expr Ann) -> Rename (Ident, Expr Ann)
142+ updateValues :: ((Ann, Ident), Expr Ann) -> Rename ((Ann, Ident), Expr Ann)
143− updateValues (name, val) = (,) name <$> renameInValue val
143+ updateValues (aname, val) = (,) aname <$> renameInValue val
144
144
145-- |
145-- |
146-- Renames within a value.
146-- Renames within a value.
src/Language/PureScript/Sugar/Names.hs+5−4
@@ -7,6 +7,8 @@ module Language.PureScript.Sugar.Names
7 ( desugarImports
7 ( desugarImports
8 , desugarImportsWithEnv
8 , desugarImportsWithEnv
9 , Env
9 , Env
10+ , ImportRecord(..)
11+ , ImportProvenance(..)
10 , Imports(..)
12 , Imports(..)
11 , Exports(..)
13 , Exports(..)
12 ) where
14 ) where
@@ -67,7 +69,7 @@ desugarImportsWithEnv externs modules = do
67 let members = Exports{..}
69 let members = Exports{..}
68 ss = internalModuleSourceSpan "<Externs>"
70 ss = internalModuleSourceSpan "<Externs>"
69 env' = M.insert efModuleName (ss, nullImports, members) env
71 env' = M.insert efModuleName (ss, nullImports, members) env
70− fromEFImport (ExternsImport mn mt qmn) = (mn, [(Nothing, mt, qmn)])
72+ fromEFImport (ExternsImport mn mt qmn) = (mn, [(Nothing, Just mt, qmn)])
71 imps <- foldM (resolveModuleImport env') nullImports (map fromEFImport efImports)
73 imps <- foldM (resolveModuleImport env') nullImports (map fromEFImport efImports)
72 exps <- resolveExports env' efModuleName imps members efExports
74 exps <- resolveExports env' efModuleName imps members efExports
73 return $ M.insert efModuleName (ss, imps, exps) env
75 return $ M.insert efModuleName (ss, imps, exps) env
@@ -284,7 +286,7 @@ renameInModule env imports (Module ss coms mn decls exps) =
284 update
286 update
285 :: (Ord a, Show a)
287 :: (Ord a, Show a)
286 => (Qualified a -> SimpleErrorMessage)
288 => (Qualified a -> SimpleErrorMessage)
287− -> M.Map (Qualified a) [(Qualified a, ModuleName)]
289+ -> M.Map (Qualified a) [ImportRecord a]
288 -> (Exports -> a -> Maybe (Qualified a))
290 -> (Exports -> a -> Maybe (Qualified a))
289 -> (Qualified a -> Name)
291 -> (Qualified a -> Name)
290 -> (a -> String)
292 -> (a -> String)
@@ -300,8 +302,7 @@ renameInModule env imports (Module ss coms mn decls exps) =
300 -- re-exports. If there are multiple options for the name to resolve to
302 -- re-exports. If there are multiple options for the name to resolve to
301 -- in scope, we throw an error.
303 -- in scope, we throw an error.
302 (Just options, _) -> do
304 (Just options, _) -> do
303− checkImportConflicts render options
304− let (Qualified (Just mnNew) _, mnOrig) = head options
305+ (mnNew, mnOrig) <- checkImportConflicts mn render options
305 modify $ \result -> M.insert mnNew (maybe [toName qname] (toName qname :) (mnNew `M.lookup` result)) result
306 modify $ \result -> M.insert mnNew (maybe [toName qname] (toName qname :) (mnNew `M.lookup` result)) result
306 return $ Qualified (Just mnOrig) name
307 return $ Qualified (Just mnOrig) name
307
308
src/Language/PureScript/Sugar/Names/Env.hs+55−15
@@ -2,7 +2,9 @@
2{-# LANGUAGE ScopedTypeVariables #-}
2{-# LANGUAGE ScopedTypeVariables #-}
3
3
4module Language.PureScript.Sugar.Names.Env
4module Language.PureScript.Sugar.Names.Env
5+ ( ImportRecord(..)
6+ , ImportProvenance(..)
5− ( Imports(..)
7+ , Imports(..)
6 , nullImports
8 , nullImports
7 , Exports(..)
9 , Exports(..)
8 , nullExports
10 , nullExports
@@ -19,13 +21,14 @@ module Language.PureScript.Sugar.Names.Env
19 ) where
21 ) where
20
22
21import Data.Function (on)
23import Data.Function (on)
22−import Data.List (groupBy, sortBy, nub)
24+import Data.List (groupBy, sortBy, nub, delete)
23import Data.Maybe (fromJust)
25import Data.Maybe (fromJust)
24import qualified Data.Map as M
26import qualified Data.Map as M
25import qualified Data.Set as S
27import qualified Data.Set as S
26
28
27import Control.Monad
29import Control.Monad
28import Control.Monad.Error.Class (MonadError(..))
30import Control.Monad.Error.Class (MonadError(..))
31+import Control.Monad.Writer.Class (MonadWriter(..))
29
32
30import Language.PureScript.AST
33import Language.PureScript.AST
31import Language.PureScript.Crash
34import Language.PureScript.Crash
@@ -33,6 +36,30 @@ import Language.PureScript.Names
33import Language.PureScript.Environment
36import Language.PureScript.Environment
34import Language.PureScript.Errors
37import Language.PureScript.Errors
35
38
39+-- |
40+-- The details for an import: the name of the thing that is being imported
41+-- (`A.x` if importing from `A`), the module that the thing was originally
42+-- defined in (for re-export resolution), and the import provenance (see below).
43+--
44+data ImportRecord a =
45+ ImportRecord
46+ { importName :: Qualified a
47+ , importSourceModule :: ModuleName
48+ , importProvenance :: ImportProvenance
49+ }
50+ deriving (Eq, Ord, Show, Read)
51+
52+-- |
53+-- Used to track how an import was introduced into scope. This allows us to
54+-- handle the one-open-import special case that allows a name conflict to become
55+-- a warning rather than being an unresolvable situation.
56+--
57+data ImportProvenance
58+ = FromImplicit
59+ | FromExplicit
60+ | Local
61+ deriving (Eq, Ord, Show, Read)
62+
36-- |
63-- |
37-- The imported declarations for a module, including the module's own members.
64-- The imported declarations for a module, including the module's own members.
38--
65--
@@ -41,19 +68,19 @@ data Imports = Imports
41 -- |
68 -- |
42 -- Local names for types within a module mapped to to their qualified names
69 -- Local names for types within a module mapped to to their qualified names
43 --
70 --
44− importedTypes :: M.Map (Qualified (ProperName 'TypeName)) [(Qualified (ProperName 'TypeName), ModuleName)]
71+ importedTypes :: M.Map (Qualified (ProperName 'TypeName)) [ImportRecord (ProperName 'TypeName)]
45 -- |
72 -- |
46 -- Local names for data constructors within a module mapped to to their qualified names
73 -- Local names for data constructors within a module mapped to to their qualified names
47 --
74 --
48− , importedDataConstructors :: M.Map (Qualified (ProperName 'ConstructorName)) [(Qualified (ProperName 'ConstructorName), ModuleName)]
75+ , importedDataConstructors :: M.Map (Qualified (ProperName 'ConstructorName)) [ImportRecord (ProperName 'ConstructorName)]
49 -- |
76 -- |
50 -- Local names for classes within a module mapped to to their qualified names
77 -- Local names for classes within a module mapped to to their qualified names
51 --
78 --
52− , importedTypeClasses :: M.Map (Qualified (ProperName 'ClassName)) [(Qualified (ProperName 'ClassName), ModuleName)]
79+ , importedTypeClasses :: M.Map (Qualified (ProperName 'ClassName)) [ImportRecord (ProperName 'ClassName)]
53 -- |
80 -- |
54 -- Local names for values within a module mapped to to their qualified names
81 -- Local names for values within a module mapped to to their qualified names
55 --
82 --
56− , importedValues :: M.Map (Qualified Ident) [(Qualified Ident, ModuleName)]
83+ , importedValues :: M.Map (Qualified Ident) [ImportRecord Ident]
57 -- |
84 -- |
58 -- The modules that have been imported into the current scope.
85 -- The modules that have been imported into the current scope.
59 --
86 --
@@ -202,16 +229,29 @@ getExports env mn = maybe (throwError . errorMessage $ UnknownModule mn) (return
202--
229--
203checkImportConflicts
230checkImportConflicts
204 :: forall m a
231 :: forall m a
205− . (MonadError MultipleErrors m, Ord a)
232+ . (Show a, MonadError MultipleErrors m, MonadWriter MultipleErrors m, Ord a)
233+ => ModuleName
206− => (a -> String)
234+ -> (a -> String)
207− -> [(Qualified a, ModuleName)]
235+ -> [ImportRecord a]
208− -> m ()
236+ -> m (ModuleName, ModuleName)
209−checkImportConflicts render xs =
237+checkImportConflicts currentModule render xs =
238+ let
210− let byOrig = groupBy ((==) `on` snd) . sortBy (compare `on` snd) $ xs
239+ byOrig = sortBy (compare `on` importSourceModule) xs
240+ groups = groupBy ((==) `on` importSourceModule) byOrig
241+ nonImplicit = filter ((/= FromImplicit) . importProvenance) xs
242+ name = render' (importName . head $ xs)
243+ conflictModules = map (getQual . importName . head) groups
211 in
244 in
212− if length byOrig > 1
245+ if length groups > 1
246+ then case nonImplicit of
247+ [ImportRecord (Qualified (Just mnNew) _) mnOrig _] -> do
248+ let warningModule = if mnNew == currentModule then Nothing else Just mnNew
249+ tell . errorMessage $ ScopeShadowing name warningModule $ delete mnNew conflictModules
250+ return (mnNew, mnOrig)
213− then throwError . errorMessage $ ScopeConflict (render' (fst . head $ xs)) (map (getQual . fst . head) byOrig)
251+ _ -> throwError . errorMessage $ ScopeConflict name conflictModules
252+ else
253+ let ImportRecord (Qualified (Just mnNew) _) mnOrig _ = head byOrig
214− else return ()
254+ in return (mnNew, mnOrig)
215 where
255 where
216 getQual :: Qualified a -> ModuleName
256 getQual :: Qualified a -> ModuleName
217 getQual (Qualified (Just mn) _) = mn
257 getQual (Qualified (Just mn) _) = mn
src/Language/PureScript/Sugar/Names/Exports.hs+5−5
@@ -110,17 +110,17 @@ resolveExports env mn imps exps refs =
110 -- Extracts a list of values for a module based on a lookup table. If the
110 -- Extracts a list of values for a module based on a lookup table. If the
111 -- boolean is true the values are filtered by the qualification
111 -- boolean is true the values are filtered by the qualification
112 extract
112 extract
113− :: (Ord a)
113+ :: (Show a, Ord a)
114 => Bool
114 => Bool
115 -> ModuleName
115 -> ModuleName
116 -> (a -> String)
116 -> (a -> String)
117− -> M.Map (Qualified a) [(Qualified a, ModuleName)]
117+ -> M.Map (Qualified a) [ImportRecord a]
118 -> m [Qualified a]
118 -> m [Qualified a]
119− extract useQual name render = fmap (map (fst . head . snd)) . go . M.toList
119+ extract useQual name render = fmap (map (importName . head . snd)) . go . M.toList
120 where
120 where
121 go = filterM $ \(name', options) -> do
121 go = filterM $ \(name', options) -> do
122− let isMatch = if useQual then eqQual name name' else any (eqQual name . fst) options
122+ let isMatch = if useQual then eqQual name name' else any (eqQual name . importName) options
123− when (isMatch && length options > 1) $ checkImportConflicts render options
123+ when (isMatch && length options > 1) $ void $ checkImportConflicts mn render options
124 return isMatch
124 return isMatch
125
125
126 -- Check whether a module name refers to a "pseudo module" that came into
126 -- Check whether a module name refers to a "pseudo module" that came into
src/Language/PureScript/Sugar/Names/Imports.hs+36−27
@@ -99,7 +99,8 @@ resolveImports env (Module ss coms currentModule decls exps) =
99
99
100 return ()
100 return ()
101
101
102+ let imports' = M.map (map (\(ss', dt, mmn) -> (ss', Just dt, mmn))) imports
102− let scope = M.insert currentModule [(Nothing, Implicit, Nothing)] imports
103+ scope = M.insert currentModule [(Nothing, Nothing, Nothing)] imports'
103 resolved <- foldM (resolveModuleImport env) nullImports (M.toList scope)
104 resolved <- foldM (resolveModuleImport env) nullImports (M.toList scope)
104 return (Module ss coms currentModule decls' exps, resolved)
105 return (Module ss coms currentModule decls' exps, resolved)
105
106
@@ -162,11 +163,13 @@ resolveModuleImport
162 . (Applicative m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
163 . (Applicative m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
163 => Env
164 => Env
164 -> Imports
165 -> Imports
165− -> (ModuleName, [(Maybe SourceSpan, ImportDeclarationType, Maybe ModuleName)])
166+ -> (ModuleName, [(Maybe SourceSpan, Maybe ImportDeclarationType, Maybe ModuleName)])
166 -> m Imports
167 -> m Imports
167resolveModuleImport env ie (mn, imps) = foldM go ie imps
168resolveModuleImport env ie (mn, imps) = foldM go ie imps
168 where
169 where
170+ go :: Imports
169− go :: Imports -> (Maybe SourceSpan, ImportDeclarationType, Maybe ModuleName) -> m Imports
171+ -> (Maybe SourceSpan, Maybe ImportDeclarationType, Maybe ModuleName)
172+ -> m Imports
170 go ie' (pos, typ, impQual) = do
173 go ie' (pos, typ, impQual) = do
171 modExports <- positioned $ maybe (throwError . errorMessage $ UnknownModule mn) (return . envModuleExports) $ mn `M.lookup` env
174 modExports <- positioned $ maybe (throwError . errorMessage $ UnknownModule mn) (return . envModuleExports) $ mn `M.lookup` env
172 let virtualModules = importedVirtualModules ie'
175 let virtualModules = importedVirtualModules ie'
@@ -189,15 +192,16 @@ resolveImport
189 -> Exports
192 -> Exports
190 -> Imports
193 -> Imports
191 -> Maybe ModuleName
194 -> Maybe ModuleName
192− -> ImportDeclarationType
195+ -> Maybe ImportDeclarationType
193 -> m Imports
196 -> m Imports
194resolveImport importModule exps imps impQual = resolveByType
197resolveImport importModule exps imps impQual = resolveByType
195 where
198 where
196
199
197− resolveByType :: ImportDeclarationType -> m Imports
200+ resolveByType :: Maybe ImportDeclarationType -> m Imports
198− resolveByType Implicit = importAll importExplicit
201+ resolveByType Nothing = importAll (importRef Local)
202+ resolveByType (Just Implicit) = importAll (importRef FromImplicit)
199− resolveByType (Explicit refs) = checkRefs False refs >> foldM importExplicit imps refs
203+ resolveByType (Just (Explicit refs)) = checkRefs False refs >> foldM (importRef FromExplicit) imps refs
200− resolveByType (Hiding refs) = do
204+ resolveByType (Just (Hiding refs)) = do
201 imps' <- checkRefs True refs >> importAll (importNonHidden refs)
205 imps' <- checkRefs True refs >> importAll (importNonHidden refs)
202 let isEmptyImport
206 let isEmptyImport
203 = M.null (importedTypes imps')
207 = M.null (importedTypes imps')
@@ -246,7 +250,7 @@ resolveImport importModule exps imps impQual = resolveByType
246
250
247 importNonHidden :: [DeclarationRef] -> Imports -> DeclarationRef -> m Imports
251 importNonHidden :: [DeclarationRef] -> Imports -> DeclarationRef -> m Imports
248 importNonHidden hidden m ref | isHidden ref = return m
252 importNonHidden hidden m ref | isHidden ref = return m
249− | otherwise = importExplicit m ref
253+ | otherwise = importRef FromImplicit m ref
250 where
254 where
251 -- TODO: rework this to be not confusing
255 -- TODO: rework this to be not confusing
252 isHidden :: DeclarationRef -> Bool
256 isHidden :: DeclarationRef -> Bool
@@ -268,27 +272,26 @@ resolveImport importModule exps imps impQual = resolveByType
268 imp'' <- foldM (\m (name, _) -> importer m (ValueRef name)) imp' (exportedValues exps)
272 imp'' <- foldM (\m (name, _) -> importer m (ValueRef name)) imp' (exportedValues exps)
269 foldM (\m (name, _) -> importer m (TypeClassRef name)) imp'' (exportedTypeClasses exps)
273 foldM (\m (name, _) -> importer m (TypeClassRef name)) imp'' (exportedTypeClasses exps)
270
274
271− -- Import something explicitly
272− importExplicit :: Imports -> DeclarationRef -> m Imports
275+ importRef :: ImportProvenance -> Imports -> DeclarationRef -> m Imports
273− importExplicit imp (PositionedDeclarationRef pos _ r) =
276+ importRef prov imp (PositionedDeclarationRef pos _ r) =
274− warnAndRethrowWithPosition pos $ importExplicit imp r
277+ warnAndRethrowWithPosition pos $ importRef prov imp r
275− importExplicit imp (ValueRef name) = do
278+ importRef prov imp (ValueRef name) = do
276− let values' = updateImports (importedValues imp) (exportedValues exps) name
279+ let values' = updateImports (importedValues imp) (exportedValues exps) name prov
277 return $ imp { importedValues = values' }
280 return $ imp { importedValues = values' }
278− importExplicit imp (TypeRef name dctors) = do
281+ importRef prov imp (TypeRef name dctors) = do
279− let types' = updateImports (importedTypes imp) (first fst `map` exportedTypes exps) name
282+ let types' = updateImports (importedTypes imp) (first fst `map` exportedTypes exps) name prov
280 let exportedDctors :: [(ProperName 'ConstructorName, ModuleName)]
283 let exportedDctors :: [(ProperName 'ConstructorName, ModuleName)]
281 exportedDctors = allExportedDataConstructors name
284 exportedDctors = allExportedDataConstructors name
282 dctorNames :: [ProperName 'ConstructorName]
285 dctorNames :: [ProperName 'ConstructorName]
283 dctorNames = fst `map` exportedDctors
286 dctorNames = fst `map` exportedDctors
284 maybe (return ()) (traverse_ $ checkDctorExists name dctorNames) dctors
287 maybe (return ()) (traverse_ $ checkDctorExists name dctorNames) dctors
285 when (null dctorNames && isNothing dctors) . tell . errorMessage $ MisleadingEmptyTypeImport importModule name
288 when (null dctorNames && isNothing dctors) . tell . errorMessage $ MisleadingEmptyTypeImport importModule name
286− let dctors' = foldl (\m -> updateImports m exportedDctors) (importedDataConstructors imp) (fromMaybe dctorNames dctors)
289+ let dctors' = foldl (\m d -> updateImports m exportedDctors d prov) (importedDataConstructors imp) (fromMaybe dctorNames dctors)
287 return $ imp { importedTypes = types', importedDataConstructors = dctors' }
290 return $ imp { importedTypes = types', importedDataConstructors = dctors' }
288− importExplicit imp (TypeClassRef name) = do
291+ importRef prov imp (TypeClassRef name) = do
289− let typeClasses' = updateImports (importedTypeClasses imp) (exportedTypeClasses exps) name
292+ let typeClasses' = updateImports (importedTypeClasses imp) (exportedTypeClasses exps) name prov
290 return $ imp { importedTypeClasses = typeClasses' }
293 return $ imp { importedTypeClasses = typeClasses' }
291− importExplicit _ _ = internalError "Invalid argument to importExplicit"
294+ importRef _ _ _ = internalError "Invalid argument to importRef"
292
295
293 -- Find all exported data constructors for a given type
296 -- Find all exported data constructors for a given type
294 allExportedDataConstructors :: ProperName 'TypeName -> [(ProperName 'ConstructorName, ModuleName)]
297 allExportedDataConstructors :: ProperName 'TypeName -> [(ProperName 'ConstructorName, ModuleName)]
@@ -300,11 +303,17 @@ resolveImport importModule exps imps impQual = resolveByType
300 -- Add something to an import resolution list
303 -- Add something to an import resolution list
301 updateImports
304 updateImports
302 :: (Ord a)
305 :: (Ord a)
303− => M.Map (Qualified a) [(Qualified a, ModuleName)]
306+ => M.Map (Qualified a) [ImportRecord a]
304 -> [(a, ModuleName)]
307 -> [(a, ModuleName)]
305 -> a
308 -> a
309+ -> ImportProvenance
306− -> M.Map (Qualified a) [(Qualified a, ModuleName)]
310+ -> M.Map (Qualified a) [ImportRecord a]
307− updateImports imps' exps' name =
311+ updateImports imps' exps' name prov =
312+ let
308− let mnOrig = fromMaybe (internalError "Invalid state in updateImports") (name `lookup` exps')
313+ mnOrig = fromMaybe (internalError "Invalid state in updateImports") (name `lookup` exps')
309− currNames = fromMaybe [] (M.lookup (Qualified impQual name) imps')
310− in M.insert (Qualified impQual name) ((Qualified (Just importModule) name, mnOrig) : currNames) imps'
314+ rec = ImportRecord (Qualified (Just importModule) name) mnOrig prov
315+ in
316+ M.alter
317+ (\currNames -> Just $ rec : fromMaybe [] currNames)
318+ (Qualified impQual name)
319+ imps'
src/Language/PureScript/TypeChecker/Types.hs+6−3
@@ -297,7 +297,9 @@ infer' (TypedValue checkType val ty) = do
297 ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty
297 ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty
298 val' <- if checkType then withScopedTypeVars moduleName args (check val ty') else return val
298 val' <- if checkType then withScopedTypeVars moduleName args (check val ty') else return val
299 return $ TypedValue True val' ty'
299 return $ TypedValue True val' ty'
300−infer' (PositionedValue pos _ val) = warnAndRethrowWithPosition pos $ infer' val
300+infer' (PositionedValue pos c val) = warnAndRethrowWithPosition pos $ do
301+ TypedValue t v ty <- infer' val
302+ return $ TypedValue t (PositionedValue pos c v) ty
301infer' _ = internalError "Invalid argument to infer"
303infer' _ = internalError "Invalid argument to infer"
302
304
303inferLetBinding ::
305inferLetBinding ::
@@ -623,8 +625,9 @@ check' val kt@(KindedType ty kind) = do
623 checkTypeKind ty kind
625 checkTypeKind ty kind
624 val' <- check' val ty
626 val' <- check' val ty
625 return $ TypedValue True val' kt
627 return $ TypedValue True val' kt
626−check' (PositionedValue pos _ val) ty =
628+check' (PositionedValue pos c val) ty = warnAndRethrowWithPosition pos $ do
627− warnAndRethrowWithPosition pos $ check' val ty
629+ TypedValue t v ty' <- check' val ty
630+ return $ TypedValue t (PositionedValue pos c v) ty'
628check' val ty = do
631check' val ty = do
629 TypedValue _ val' ty' <- infer val
632 TypedValue _ val' ty' <- infer val
630 mt <- subsumes (Just val') ty' ty
633 mt <- subsumes (Just val') ty' ty
stack-lts-2.yaml+6−2
@@ -1,4 +1,4 @@
1−flags: {}
1+resolver: lts-2.22
2packages:
2packages:
3- '.'
3- '.'
4extra-deps:
4extra-deps:
@@ -6,4 +6,8 @@ extra-deps:
6- bower-json-0.7.0.0
6- bower-json-0.7.0.0
7- boxes-0.1.4
7- boxes-0.1.4
8- pattern-arrows-0.0.2
8- pattern-arrows-0.0.2
9−resolver: lts-2.22
9+- sourcemap-0.1.6
10+- fsnotify-0.2.1
11+- hfsevents-0.1.6
12+- pipes-http-1.0.2
13+flags: {}
stack-lts-3.yaml+4−3
@@ -1,5 +1,6 @@
1−flags: {}
1+resolver: lts-3.22
2packages:
2packages:
3- '.'
3- '.'
4−extra-deps: []
4+extra-deps:
5−resolver: lts-3.6
5+- sourcemap-0.1.6
6+flags: {}
stack-lts-5.yamlnew file+5
@@ -0,0 +1,5 @@
1+resolver: lts-5.4
2+packages:
3+- '.'
4+extra-deps: []
5+flags: {}
stack-nightly.yaml+2−2
@@ -1,5 +1,5 @@
1flags: {}
1flags: {}
2packages:
2packages:
3- '.'
3- '.'
4−extra-deps:
4+extra-deps: []
5−resolver: nightly-2015-09-29
5+resolver: nightly-2016-02-25
stack.yaml+1−1
@@ -1 +1 @@
1−stack-lts-3.yaml
1+stack-lts-5.yaml
tests/Language/PureScript/Ide/FilterSpec.hsnew file+59
@@ -0,0 +1,59 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Language.PureScript.Ide.FilterSpec where
3+
4+import Data.Text (Text)
5+import Language.PureScript.Ide.Filter
6+import Language.PureScript.Ide.Types
7+import Test.Hspec
8+
9+modules :: [Module]
10+modules =
11+ [
12+ ("Module.A", [FunctionDecl "function1" ""]),
13+ ("Module.B", [DataDecl "data1" ""]),
14+ ("Module.C", [ModuleDecl "Module.C" []]),
15+ ("Module.D", [Dependency "Module.C" [] Nothing, FunctionDecl "asd" ""])
16+ ]
17+
18+runEq :: Text -> [Module]
19+runEq s = runFilter (equalityFilter s) modules
20+runPrefix :: Text -> [Module]
21+runPrefix s = runFilter (prefixFilter s) modules
22+runModule :: [ModuleIdent] -> [Module]
23+runModule ms = runFilter (moduleFilter ms) modules
24+runDependency :: [ModuleIdent] -> [Module]
25+runDependency ms = runFilter (dependencyFilter ms) modules
26+
27+spec :: Spec
28+spec = do
29+ describe "equality Filter" $ do
30+ it "removes empty modules" $
31+ runEq "test" `shouldBe` []
32+ it "keeps function declarations that are equal" $
33+ runEq "function1" `shouldBe` [head modules]
34+ -- TODO: It would be more sensible to match Constructors
35+ it "keeps data declarations that are equal" $
36+ runEq "data1" `shouldBe` [modules !! 1]
37+ describe "prefixFilter" $ do
38+ it "keeps everything on empty string" $
39+ runPrefix "" `shouldBe` modules
40+ it "keeps functionname prefix matches" $
41+ runPrefix "fun" `shouldBe` [head modules]
42+ it "keeps data decls prefix matches" $
43+ runPrefix "dat" `shouldBe` [modules !! 1]
44+ it "keeps module decl prefix matches" $
45+ runPrefix "Mod" `shouldBe` [modules !! 2]
46+ describe "moduleFilter" $ do
47+ it "removes everything on empty input" $
48+ runModule [] `shouldBe` []
49+ it "only keeps the specified modules" $
50+ runModule ["Module.A", "Module.C"] `shouldBe` [head modules, modules !! 2]
51+ it "ignores modules that are not in scope" $
52+ runModule ["Module.A", "Module.C", "Unknown"] `shouldBe` [head modules, modules !! 2]
53+ describe "dependencyFilter" $ do
54+ it "removes everything on empty input" $
55+ runDependency [] `shouldBe` []
56+ it "only keeps the specified modules if they have no imports" $
57+ runDependency ["Module.A", "Module.B"] `shouldBe` [head modules, modules !! 1]
58+ it "keeps the specified modules and their imports" $
59+ runDependency ["Module.A", "Module.D"] `shouldBe` [head modules, modules !! 2, modules !! 3]
tests/Language/PureScript/Ide/MatcherSpec.hsnew file+31
@@ -0,0 +1,31 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Language.PureScript.Ide.MatcherSpec where
4+
5+import Data.Text (Text)
6+import Language.PureScript.Ide.Matcher
7+import Language.PureScript.Ide.Types
8+import Test.Hspec
9+
10+completions :: [Completion]
11+completions = [
12+ Completion ("", "firstResult", ""),
13+ Completion ("", "secondResult", ""),
14+ Completion ("", "fiult", "")
15+ ]
16+
17+mkResult :: [Int] -> [Completion]
18+mkResult = map (completions !!)
19+
20+runFlex :: Text -> [Completion]
21+runFlex s = runMatcher (flexMatcher s) completions
22+
23+spec :: Spec
24+spec = do
25+ describe "Flex Matcher" $ do
26+ it "doesn't match on an empty string" $
27+ runFlex "" `shouldBe` []
28+ it "matches on equality" $
29+ runFlex "firstResult" `shouldBe` mkResult [0]
30+ it "scores short matches higher and sorts accordingly" $
31+ runFlex "filt" `shouldBe` mkResult [2, 0]
tests/Language/PureScript/Ide/ReexportsSpec.hsnew file+77
@@ -0,0 +1,77 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Language.PureScript.Ide.ReexportsSpec where
3+
4+import Control.Exception (evaluate)
5+import Data.List (sort)
6+import qualified Data.Map as Map
7+import Language.PureScript.Ide.Reexports
8+import Language.PureScript.Ide.Types
9+import Test.Hspec
10+
11+decl1 :: ExternDecl
12+decl1 = FunctionDecl "filter" "asdasd"
13+decl2 :: ExternDecl
14+decl2 = DataDecl "Tree" "* -> *"
15+decl3 :: ExternDecl
16+decl3 = DataDecl "TreeAsd" "* -> *"
17+dep1 :: ExternDecl
18+dep1 = Dependency "Test.Foo" [] (Just "T")
19+dep2 :: ExternDecl
20+dep2 = Dependency "Test.Bar" [] (Just "T")
21+
22+circularModule :: Module
23+circularModule = ("Circular", [Export "Circular"])
24+
25+module1 :: Module
26+module1 = ("Module1", [Export "Module2", Export "Module3", decl1])
27+
28+module2 :: Module
29+module2 = ("Module2", [decl2])
30+
31+module3 :: Module
32+module3 = ("Module3", [decl3])
33+
34+module4 :: Module
35+module4 = ("Module4", [Export "T", decl1, dep1, dep2])
36+
37+result :: Module
38+result = ("Module1", [decl1, decl2, Export "Module3"])
39+
40+db :: Map.Map ModuleIdent [ExternDecl]
41+db = Map.fromList [module1, module2, module3]
42+
43+shouldBeEqualSorted :: Module -> Module -> Expectation
44+shouldBeEqualSorted (n1, d1) (n2, d2) = (n1, sort d1) `shouldBe` (n2, sort d2)
45+
46+spec :: Spec
47+spec = do
48+ describe "Reexports" $ do
49+ it "finds all reexports" $
50+ getReexports module1 `shouldBe` [Export "Module2", Export "Module3"]
51+
52+ it "replaces a reexport with another module" $
53+ replaceReexport (Export "Module2") module1 module2 `shouldBeEqualSorted` result
54+
55+ it "adds another module even if there is no export statement" $
56+ replaceReexport (Export "Module2") ("Module1", [decl1, Export "Module3"]) module2
57+ `shouldBeEqualSorted` result
58+
59+ it "only adds a declaration once" $
60+ let replaced = replaceReexport (Export "Module2") module1 module2
61+ in replaceReexport (Export "Module2") replaced module2 `shouldBeEqualSorted` result
62+
63+ it "should error when given a non-Export to replace" $
64+ evaluate (replaceReexport decl1 module1 module2)
65+ `shouldThrow` errorCall "Should only get Exports here."
66+ it "replaces all Exports with their corresponding declarations" $
67+ replaceReexports module1 db `shouldBe` ("Module1", [decl1, decl2, decl3])
68+
69+ it "does not list itself as a reexport" $
70+ getReexports circularModule `shouldBe` []
71+
72+ it "does not include circular references when replacing reexports" $
73+ replaceReexports circularModule (uncurry Map.singleton circularModule )
74+ `shouldBe` ("Circular", [])
75+
76+ it "replaces exported aliases with imported module" $
77+ getReexports module4 `shouldBe` [Export "Test.Foo", Export "Test.Bar"]
tests/Language/PureScript/IdeSpec.hsnew file+35
@@ -0,0 +1,35 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE PackageImports #-}
3+module Language.PureScript.IdeSpec where
4+
5+import Control.Concurrent.STM
6+import Control.Monad.Reader
7+import Data.List
8+import qualified Data.Map as Map
9+import Language.PureScript.Ide
10+import Language.PureScript.Ide.Types
11+import Test.Hspec
12+
13+testState :: PscIdeState
14+testState = PscIdeState (Map.fromList [("Data.Array", []), ("Control.Monad.Eff", [])]) (Map.empty)
15+
16+defaultConfig :: Configuration
17+defaultConfig =
18+ Configuration
19+ {
20+ confOutputPath = "output/"
21+ , confDebug = False
22+ }
23+
24+spec :: SpecWith ()
25+spec = do
26+ describe "list" $ do
27+ describe "loadedModules" $ do
28+ it "returns an empty list when no modules are loaded" $ do
29+ st <- newTVarIO emptyPscIdeState
30+ result <- runReaderT printModules (PscIdeEnvironment st defaultConfig)
31+ result `shouldBe` ModuleList []
32+ it "returns the list of loaded modules" $ do
33+ st <- newTVarIO testState
34+ ModuleList result <- runReaderT printModules (PscIdeEnvironment st defaultConfig)
35+ sort result `shouldBe` sort ["Data.Array", "Control.Monad.Eff"]
tests/Main.hs+3
@@ -25,6 +25,7 @@ import qualified TestCompiler
25import qualified TestPscPublish
25import qualified TestPscPublish
26import qualified TestDocs
26import qualified TestDocs
27import qualified TestPsci
27import qualified TestPsci
28+import qualified TestPscIde
28
29
29main :: IO ()
30main :: IO ()
30main = do
31main = do
@@ -36,6 +37,8 @@ main = do
36 TestPscPublish.main
37 TestPscPublish.main
37 heading "psci test suite"
38 heading "psci test suite"
38 TestPsci.main
39 TestPsci.main
40+ heading "psc-ide test suite"
41+ TestPscIde.main
39
42
40 where
43 where
41 heading msg = do
44 heading msg = do
tests/PscIdeSpec.hsnew file+1
@@ -0,0 +1 @@
1+{-# OPTIONS_GHC -F -pgmF hspec-discover -optF --module-name=PscIdeSpec #-}
tests/TestPscIde.hsnew file+7
@@ -0,0 +1,7 @@
1+module TestPscIde where
2+
3+import qualified PscIdeSpec
4+import Test.Hspec
5+
6+main :: IO ()
7+main = hspec PscIdeSpec.spec