git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge tag 'v0.8.1' into pure11
commitfa8106b42ddca18202bc922d2d22f239e08b9853 authorAndy Arvanitis <andyarvanitis@gmail.com> dateTue 15 Mar 2016, 19:26 (11 years ago) parentfcc1ad53732373
75 files changed+3524−665
.travis.yml+9−9 CONTRIBUTORS.md+8−8 LICENSE+34 bundle/README+9−6 bundle/build-stack.sh+50 bundle/build.sh+12−8 bundle/winbuild.sh+12−8 examples/failing/ConflictingExports2.purs−13 examples/failing/ConflictingImports2.purs+8−4 examples/passing/ResolvableScopeConflict.purs+25 examples/passing/ResolvableScopeConflict2.purs+22 examples/passing/ResolvableScopeConflict3.purs+15 psc-ide-client/Main.hs+57 psc-ide-server/Main.hs+135 psc-ide-server/PROTOCOL.md+409 psc-ide-server/README.md+40 psc/Main.hs+6 purescript.cabal+69−8 src/Language/PureScript/CodeGen/JS.hs+140−123 src/Language/PureScript/CodeGen/JS/AST.hs+168−97 src/Language/PureScript/CodeGen/JS/Optimizer.hs+5−5 src/Language/PureScript/CodeGen/JS/Optimizer/Blocks.hs+4−4 src/Language/PureScript/CodeGen/JS/Optimizer/Common.hs+18−18 src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs+50−50 src/Language/PureScript/CodeGen/JS/Optimizer/MagicDo.hs+34−34 src/Language/PureScript/CodeGen/JS/Optimizer/TCO.hs+33−31 src/Language/PureScript/CodeGen/JS/Optimizer/Unused.hs+3−3 src/Language/PureScript/CoreFn/Binders.hs+9−2 src/Language/PureScript/CoreFn/Desugar.hs+36−17 src/Language/PureScript/CoreFn/Expr.hs+3−5 src/Language/PureScript/CoreFn/Meta.hs+2−4 src/Language/PureScript/CoreFn/Module.hs+1−1 src/Language/PureScript/CoreFn/Traversals.hs+2−2 src/Language/PureScript/Docs/Convert/ReExports.hs+3−3 src/Language/PureScript/Errors.hs+9 src/Language/PureScript/Ide.hs+199 src/Language/PureScript/Ide/CaseSplit.hs+157 src/Language/PureScript/Ide/CodecJSON.hs+13 src/Language/PureScript/Ide/Command.hs+101 src/Language/PureScript/Ide/Completion.hs+35 src/Language/PureScript/Ide/Error.hs+43 src/Language/PureScript/Ide/Externs.hs+102 src/Language/PureScript/Ide/Filter.hs+110 src/Language/PureScript/Ide/Matcher.hs+100 src/Language/PureScript/Ide/Pursuit.hs+65 src/Language/PureScript/Ide/Reexports.hs+73 src/Language/PureScript/Ide/SourceFile.hs+106 src/Language/PureScript/Ide/State.hs+80 src/Language/PureScript/Ide/Types.hs+240 src/Language/PureScript/Ide/Watcher.hs+40 src/Language/PureScript/Linter/Imports.hs+14−5 src/Language/PureScript/Make.hs+41−6 src/Language/PureScript/Options.hs+4−1 src/Language/PureScript/Pretty.hs−3 src/Language/PureScript/Pretty/Common.hs+96−9 src/Language/PureScript/Pretty/JS.hs+118−105 src/Language/PureScript/Pretty/Values.hs−2 src/Language/PureScript/Renamer.hs+9−9 src/Language/PureScript/Sugar/Names.hs+5−4 src/Language/PureScript/Sugar/Names/Env.hs+55−15 src/Language/PureScript/Sugar/Names/Exports.hs+5−5 src/Language/PureScript/Sugar/Names/Imports.hs+36−27 src/Language/PureScript/TypeChecker/Types.hs+6−3 stack-lts-2.yaml+6−2 stack-lts-3.yaml+4−3 stack-lts-5.yaml+5 stack-nightly.yaml+2−2 stack.yaml+1−1 tests/Language/PureScript/Ide/FilterSpec.hs+59 tests/Language/PureScript/Ide/MatcherSpec.hs+31 tests/Language/PureScript/Ide/ReexportsSpec.hs+77 tests/Language/PureScript/IdeSpec.hs+35 tests/Main.hs+3 tests/PscIdeSpec.hs+1 tests/TestPscIde.hs+7
.travis.yml+9−9
@@ -6,21 +6,21 @@ matrix:
66 compiler: ": #GHC 7.8.4 - tests"
77 # ^ HACK before https://github.com/travis-ci/travis-ci/issues/4393 is resolved
88 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]}}
129 - env: GHCVER=7.6.3 CABALVER=1.22
1310 compiler: ": #GHC 7.6.3"
1411 addons: {apt: {packages: [cabal-install-1.22,ghc-7.6.3,happy-1.19.5,alex-3.1.4], sources: [hvr-ghc]}}
1512 - env: GHCVER=7.10.1 CABALVER=1.22 DEPLOY=yes
1613 compiler: ": #GHC 7.10.1"
1714 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
19− compiler: ": #GHC 7.10.2 lts-3.6"
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"
15+ - env: GHCVER=7.10.2 CABALVER=1.22 STACKAGE=lts-3.22 RUNSDISTTESTS=YES
16+ compiler: ": #GHC 7.10.2 lts-3.22"
2317 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]}}
2424 - env: GHCVER=7.10.3 CABALVER=1.22
2525 compiler: ": #GHC 7.10.3"
2626 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:
5151 - mkdir -p .cabal-sandbox
5252 - cabal sandbox init --sandbox .cabal-sandbox
5353 # 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
5555 - cabal install --only-dependencies --enable-tests
5656 - cabal install hpc-coveralls
5757 # 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
1313- [@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.
1414- [@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).
1515- [@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).
1618- [@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).
1720- [@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).
1821- [@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).
1922- [@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
2225- [@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).
2326- [@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).
2427- [@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).
2529- [@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).
2630- [@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).
2731- [@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
4246- [@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).
4347- [@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.
4448- [@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).
4550- [@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).
4651- [@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).
4752- [@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
5156- [@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).
5257- [@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).
5358- [@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).
5460- [@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).
5562- [@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).
5663- [@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).
5765- [@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).
5866- [@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).
5967- [@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.
6068- [@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).
6969
7070### Companies
7171
LICENSE+34
@@ -63,6 +63,7 @@ PureScript uses the following Haskell library packages. Their license files foll
6363 safe
6464 scientific
6565 semigroups
66+ sourcemap
6667 split
6768 stm
6869 syb
@@ -1589,6 +1590,39 @@ semigroups LICENSE file:
15891590 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
15901591 POSSIBILITY OF SUCH DAMAGE.
15911592
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+
15921626split LICENSE file:
15931627
15941628 Copyright (c) 2008 Brent Yorgey, Louis Wasserman
bundle/README+9−6
@@ -10,12 +10,15 @@ Installation Instructions
1010
1111This bundle contains the following executables:
1212
13−- psc The PureScript compiler
14−- psci The PureScript interactive REPL (requires NodeJS)
15−- psc-docs A Markdown documentation generator for PureScript code
16−- psc-bundle Bundles together CommonJS modules produced by `psc` into a
17− single JavaScript file; useful for running in the browser.
18−- psc-publish Generates documentation packages for uploading to Pursuit
13+- psc The PureScript compiler
14+- psci The PureScript interactive REPL (requires NodeJS)
15+- psc-docs A Markdown documentation generator for PureScript code
16+- psc-bundle Bundles together CommonJS modules produced by `psc` into a
17+ single JavaScript file; useful for running in the browser.
18+- psc-publish Generates documentation packages for uploading to Pursuit
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
1922
2023Copy these files anywhere on your PATH.
2124
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
2121strip ../dist/build/psc-docs/psc-docs
2222strip ../dist/build/psc-publish/psc-publish
2323strip ../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
2426
2527# Copy files to staging directory
26−cp ../dist/build/psc/psc build/purescript/
27−cp ../dist/build/psci/psci build/purescript/
28−cp ../dist/build/psc-docs/psc-docs build/purescript/
29−cp ../dist/build/psc-publish/psc-publish build/purescript/
30−cp ../dist/build/psc-bundle/psc-bundle build/purescript/
31−cp README build/purescript/
32−cp ../LICENSE build/purescript/
33−cp ../INSTALL.md build/purescript/
28+cp ../dist/build/psc/psc build/purescript/
29+cp ../dist/build/psci/psci build/purescript/
30+cp ../dist/build/psc-docs/psc-docs 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/
34+cp ../dist/build/psc-ide-client/psc-ide-client build/purescript/
35+cp README build/purescript/
36+cp ../LICENSE build/purescript/
37+cp ../INSTALL.md build/purescript/
3438
3539# Make the binary bundle
3640pushd build > /dev/null
bundle/winbuild.sh+12−8
@@ -17,16 +17,20 @@ strip ../dist/build/psci/psci.exe
1717strip ../dist/build/psc-docs/psc-docs.exe
1818strip ../dist/build/psc-publish/psc-publish.exe
1919strip ../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
2022
2123# Copy files to staging directory
22−cp ../dist/build/psc/psc.exe build/purescript/
23−cp ../dist/build/psci/psci.exe build/purescript/
24−cp ../dist/build/psc-docs/psc-docs.exe build/purescript/
25−cp ../dist/build/psc-publish/psc-publish.exe build/purescript/
26−cp ../dist/build/psc-bundle/psc-bundle.exe build/purescript/
27−cp README build/purescript/
28−cp ../LICENSE build/purescript/
29−cp ../INSTALL.md build/purescript/
24+cp ../dist/build/psc/psc.exe build/purescript/
25+cp ../dist/build/psci/psci.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/
29+cp ../dist/build/psc-ide-server/psc-ide-server.exe build/purescript/
30+cp ../dist/build/psc-ide-client/psc-ide-client.exe build/purescript/
31+cp README build/purescript/
32+cp ../LICENSE build/purescript/
33+cp ../INSTALL.md build/purescript/
3034
3135# Make the binary bundle
3236pushd 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
44 thing :: Int
55 thing = 1
66
7−module Main where
8−
9− import A
7+module B where
108
119 thing :: Int
1210 thing = 2
1311
14− -- Error due to referencing `thing` which is in scope as A.thing and Main.thing
12+module Main where
13+
14+ import A (thing)
15+ import B (thing)
16+
17+ -- Error due to referencing `thing` which is explicitly in scope as A.thing
18+ -- and B.thing
1519 what :: Int
1620 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
177177jsonErrors = switch $
178178 long "json-errors"
179179 <> help "Print errors to stderr as JSON"
180+sourceMaps :: Parser Bool
181+sourceMaps = switch $
182+ long "source-maps"
183+ <> help "Generate source maps"
184+
180185
181186options :: Parser P.Options
182187options = P.Options <$> noTco
@@ -186,6 +191,7 @@ options = P.Options <$> noTco
186191 <*> verboseErrors
187192 <*> (not <$> comments)
188193 <*> requirePath
194+ <*> sourceMaps
189195
190196pscMakeOptions :: Parser PSCMakeOptions
191197pscMakeOptions = PSCMakeOptions <$> many inputFile
purescript.cabal+69−8
@@ -1,5 +1,5 @@
11name: purescript
2−version: 0.8.0.0
2+version: 0.8.1.0
33cabal-version: >=1.8
44build-type: Simple
55license: MIT
@@ -14,7 +14,8 @@ Homepage: http://www.purescript.org/
1414author: Phil Freeman <paf31@cantab.net>,
1515 Gary Burgess <gary.burgess@gmail.com>,
1616 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>
1819
1920tested-with: GHC==7.8.4, GHC==7.10.3, GHC==8.0.1
2021
@@ -25,15 +26,15 @@ extra-source-files: examples/passing/*.purs
2526 , examples/docs/src/*.purs
2627 , tests/support/setup.js
2728 , 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
2833 , tests/support/bower.json
2934 , tests/support/setup-win.cmd
3035 , tests/support/flattened/*.purs
3136 , tests/support/flattened/*.js
3237 , 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
3738 , stack.yaml
3839 , stack-lts-2.yaml
3940 , stack-lts-3.yaml
@@ -80,7 +81,16 @@ library
8081 process >= 1.2.0 && < 1.5,
8182 safe >= 0.3.9 && < 0.4,
8283 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
8494
8595 exposed-modules: Language.PureScript
8696 Language.PureScript.AST
@@ -203,6 +213,22 @@ library
203213 Language.PureScript.Publish.ErrorsWarnings
204214 Language.PureScript.Publish.BoxesHelpers
205215
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+
206232 Control.Monad.Logger
207233 Control.Monad.Supply
208234 Control.Monad.Supply.Class
@@ -301,6 +327,39 @@ executable psc-bundle
301327 ghc-options: -Wall -O2
302328 hs-source-dirs: psc-bundle
303329
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+
304363executable pcc
305364 build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
306365 file-embed >= 0.0.7 && < 0.0.8,
@@ -319,7 +378,7 @@ test-suite tests
319378 transformers -any, process -any, transformers-compat -any, time -any,
320379 Glob -any, aeson-better-errors -any, bytestring -any, aeson -any,
321380 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
323382 ghc-options: -Wall
324383 type: exitcode-stdio-1.0
325384 main-is: Main.hs
@@ -328,6 +387,8 @@ test-suite tests
328387 TestDocs
329388 TestPscPublish
330389 TestPsci
390+ TestPscIde
391+ PscIdeSpec
331392 buildable: True
332393 hs-source-dirs: tests psci
333394
src/Language/PureScript/CodeGen/JS.hs+140−123
@@ -55,21 +55,21 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
5555 rethrow (addHint (ErrorInModule mn)) $ do
5656 let usedNames = concatMap getNames decls
5757 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
5959 let decls' = renameModules mnLookup decls
6060 jsDecls <- mapM bindToJs decls'
6161 optimized <- T.traverse (T.traverse optimize) jsDecls
6262 F.traverse_ (F.traverse_ checkIntegers) optimized
6363 comments <- not <$> asks optionsNoComments
64− let strict = JSStringLiteral "use strict"
65− let header = if comments && not (null coms) then JSComment coms strict else strict
66− let foreign' = [JSVariableIntroduction "$foreign" foreign_ | not $ null foreigns || isNothing foreign_]
64+ let strict = JSStringLiteral Nothing "use strict"
65+ let header = if comments && not (null coms) then JSComment Nothing coms strict else strict
66+ let foreign' = [JSVariableIntroduction Nothing "$foreign" foreign_ | not $ null foreigns || isNothing foreign_]
6767 let moduleBody = header : foreign' ++ jsImports ++ concat optimized
6868 let foreignExps = exps `intersect` (fst `map` foreigns)
6969 let standardExps = exps \\ foreignExps
70− let exps' = JSObjectLiteral $ map (runIdent &&& JSVar . identToJs) standardExps
70+ let exps' = JSObjectLiteral Nothing $ map (runIdent &&& (JSVar Nothing) . identToJs) standardExps
7171 ++ 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']
7373
7474 where
7575
@@ -77,23 +77,23 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
7777 -- Extracts all declaration names from a binding group.
7878 --
7979 getNames :: Bind Ann -> [Ident]
80− getNames (NonRec ident _) = [ident]
81− getNames (Rec vals) = map fst vals
80+ getNames (NonRec _ ident _) = [ident]
81+ getNames (Rec vals) = map (snd . fst) vals
8282
8383 -- |
8484 -- Creates alternative names for each module to ensure they don't collide
8585 -- with declaration names.
8686 --
87− renameImports :: [Ident] -> [ModuleName] -> M.Map ModuleName ModuleName
87+ renameImports :: [Ident] -> [(Ann, ModuleName)] -> M.Map ModuleName (Ann, ModuleName)
8888 renameImports ids mns = go M.empty ids mns
8989 where
90− go :: M.Map ModuleName ModuleName -> [Ident] -> [ModuleName] -> M.Map ModuleName ModuleName
91− go acc used (mn' : mns') =
90+ go :: M.Map ModuleName (Ann, ModuleName) -> [Ident] -> [(Ann, ModuleName)] -> M.Map ModuleName (Ann, ModuleName)
91+ go acc used ((ann, mn') : mns') =
9292 let mni = Ident $ runModuleName mn'
9393 in if mn' /= mn && mni `elem` used
9494 then let newName = freshModuleName 1 mn' used
95− in go (M.insert mn' newName acc) (Ident (runModuleName newName) : used) mns'
96− else go (M.insert mn' mn' acc) (mni : used) mns'
95+ in go (M.insert mn' (ann, newName) acc) (Ident (runModuleName newName) : used) mns'
96+ else go (M.insert mn' (ann, mn') acc) (mni : used) mns'
9797 go acc _ [] = acc
9898
9999 freshModuleName :: Integer -> ModuleName -> [Ident] -> ModuleName
@@ -107,18 +107,18 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
107107 -- Generates Javascript code for a module import, binding the required module
108108 -- to the alternative
109109 --
110− importToJs :: M.Map ModuleName ModuleName -> ModuleName -> m JS
110+ importToJs :: M.Map ModuleName (Ann, ModuleName) -> ModuleName -> m JS
111111 importToJs mnLookup mn' = do
112112 path <- asks optionsRequirePath
113− let mnSafe = fromMaybe (internalError "Missing value in mnLookup") $ M.lookup mn' mnLookup
114− let moduleBody = JSApp (JSVar "require") [JSStringLiteral (maybe id (</>) path $ runModuleName mn')]
115− return $ JSVariableIntroduction (moduleNameToJs mnSafe) (Just moduleBody)
113+ let ((ss, _, _, _), mnSafe) = fromMaybe (internalError "Missing value in mnLookup") $ M.lookup mn' mnLookup
114+ let moduleBody = JSApp Nothing (JSVar Nothing "require") [JSStringLiteral Nothing (maybe id (</>) path $ runModuleName mn')]
115+ withPos ss $ JSVariableIntroduction Nothing (moduleNameToJs mnSafe) (Just moduleBody)
116116
117117 -- |
118118 -- Replaces the `ModuleName`s in the AST so that the generated code refers to
119119 -- the collision-avoiding renamed module imports.
120120 --
121− renameModules :: M.Map ModuleName ModuleName -> [Bind Ann] -> [Bind Ann]
121+ renameModules :: M.Map ModuleName (Ann, ModuleName) -> [Bind Ann] -> [Bind Ann]
122122 renameModules mnLookup binds =
123123 let (f, _, _) = everywhereOnValues id goExpr goBinder
124124 in map f binds
@@ -131,7 +131,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
131131 goBinder b = b
132132 renameQual :: Qualified a -> Qualified a
133133 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
135135 in Qualified (Just mnSafe) a
136136 renameQual q = q
137137
@@ -139,8 +139,8 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
139139 -- Generate code in the simplified Javascript intermediate representation for a declaration
140140 --
141141 bindToJs :: Bind Ann -> m [JS]
142− bindToJs (NonRec ident val) = return <$> nonRecToJS ident val
143− bindToJs (Rec vals) = forM vals (uncurry nonRecToJS)
142+ bindToJs (NonRec ann ident val) = return <$> nonRecToJS ann ident val
143+ bindToJs (Rec vals) = forM vals (uncurry . uncurry $ nonRecToJS)
144144
145145 -- |
146146 -- 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_ =
148148 --
149149 -- The main purpose of this function is to handle code generation for comments.
150150 --
151− nonRecToJS :: Ident -> Expr Ann -> m JS
152− nonRecToJS i e@(extractAnn -> (_, com, _, _)) | not (null com) = do
151+ nonRecToJS :: Ann -> Ident -> Expr Ann -> m JS
152+ nonRecToJS a i e@(extractAnn -> (_, com, _, _)) | not (null com) = do
153153 withoutComment <- asks optionsNoComments
154154 if withoutComment
155− then nonRecToJS i (modifyAnn removeComments e)
156− else JSComment com <$> nonRecToJS i (modifyAnn removeComments e)
157− nonRecToJS ident val = do
155+ then nonRecToJS a i (modifyAnn removeComments e)
156+ else JSComment Nothing com <$> nonRecToJS a i (modifyAnn removeComments e)
157+ nonRecToJS (ss, _, _, _) ident val = do
158158 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
160168
161169 -- |
162170 -- Generate code in the simplified Javascript intermediate representation for a variable based on a
163171 -- PureScript identifier.
164172 --
165173 var :: Ident -> JS
166− var = JSVar . identToJs
174+ var = JSVar Nothing . identToJs
167175
168176 -- |
169177 -- 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_ =
172180 --
173181 accessor :: Ident -> JS -> JS
174182 accessor (Ident prop) = accessorString prop
175− accessor (Op op) = JSIndexer (JSStringLiteral op)
183+ accessor (Op op) = JSIndexer Nothing (JSStringLiteral Nothing op)
176184 accessor (GenIdent _ _) = internalError "GenIdent in accessor"
177185
178186 accessorString :: String -> JS -> JS
179− accessorString prop | identNeedsEscaping prop = JSIndexer (JSStringLiteral prop)
180− | otherwise = JSAccessor prop
187+ accessorString prop | identNeedsEscaping prop = JSIndexer Nothing (JSStringLiteral Nothing prop)
188+ | otherwise = JSAccessor Nothing prop
181189
182190 -- |
183191 -- Generate code in the simplified Javascript intermediate representation for a value or expression.
184192 --
185193 valueToJs :: Expr Ann -> m JS
186− valueToJs (Literal (pos, _, _, _) l) =
194+ valueToJs e =
195+ let (ss, _, _, _) = extractAnn e in
196+ withPos ss =<< valueToJs' e
197+
198+ valueToJs' :: Expr Ann -> m JS
199+ valueToJs' (Literal (pos, _, _, _) l) =
187200 maybe id rethrowWithPosition pos $ literalToValueJS l
188− valueToJs (Var (_, _, _, Just (IsConstructor _ [])) name) =
189− return $ JSAccessor "value" $ qualifiedToJS id name
190− valueToJs (Var (_, _, _, Just (IsConstructor _ _)) name) =
191− return $ JSAccessor "create" $ qualifiedToJS id name
192− valueToJs (Accessor _ prop val) =
201+ valueToJs' (Var (_, _, _, Just (IsConstructor _ [])) name) =
202+ return $ JSAccessor Nothing "value" $ qualifiedToJS id name
203+ valueToJs' (Var (_, _, _, Just (IsConstructor _ _)) name) =
204+ return $ JSAccessor Nothing "create" $ qualifiedToJS id name
205+ valueToJs' (Accessor _ prop val) =
193206 accessorString prop <$> valueToJs val
194− valueToJs (ObjectUpdate _ o ps) = do
207+ valueToJs' (ObjectUpdate _ o ps) = do
195208 obj <- valueToJs o
196209 sts <- mapM (sndM valueToJs) ps
197210 extendObj obj sts
198− valueToJs e@(Abs (_, _, _, Just IsTypeClassConstructor) _ _) =
211+ valueToJs' e@(Abs (_, _, _, Just IsTypeClassConstructor) _ _) =
199212 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)
201214 where
202215 unAbs :: Expr Ann -> [Ident]
203216 unAbs (Abs _ arg val) = arg : unAbs val
204217 unAbs _ = []
205218 assign :: Ident -> JS
206− assign name = JSAssignment (accessorString (runIdent name) (JSVar "this"))
219+ assign name = JSAssignment Nothing (accessorString (runIdent name) (JSVar Nothing "this"))
207220 (var name)
208− valueToJs (Abs _ arg val) = do
221+ valueToJs' (Abs _ arg val) = do
209222 ret <- valueToJs val
210− return $ JSFunction Nothing [identToJs arg] (JSBlock [JSReturn ret])
211− valueToJs e@App{} = do
223+ return $ JSFunction Nothing Nothing [identToJs arg] (JSBlock Nothing [JSReturn Nothing ret])
224+ valueToJs' e@App{} = do
212225 let (f, args) = unApp e []
213226 args' <- mapM valueToJs args
214227 case f of
215228 Var (_, _, _, Just IsNewtype) _ -> return (head args')
216229 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'
218231 Var (_, _, _, Just IsTypeClassConstructor) name ->
219− return $ JSUnary JSNew $ JSApp (qualifiedToJS id name) args'
220− _ -> flip (foldl (\fn a -> JSApp fn [a])) args' <$> valueToJs f
232+ return $ JSUnary Nothing JSNew $ JSApp Nothing (qualifiedToJS id name) args'
233+ _ -> flip (foldl (\fn a -> JSApp Nothing fn [a])) args' <$> valueToJs f
221234 where
222235 unApp :: Expr Ann -> [Expr Ann] -> (Expr Ann, [Expr Ann])
223236 unApp (App _ val arg) args = unApp val (arg : args)
224237 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)) =
226239 return $ if mn' == mn
227240 then foreignIdent ident
228241 else varToJs qi
229− valueToJs (Var (_, _, _, Just IsForeign) ident) =
242+ valueToJs' (Var (_, _, _, Just IsForeign) ident) =
230243 error $ "Encountered an unqualified reference to a foreign ident " ++ showQualified showIdent ident
231− valueToJs (Var _ ident) =
232− return $ varToJs ident
233− valueToJs (Case (maybeSpan, _, _, _) values binders) = do
244+ valueToJs' (Var _ ident) = return $ varToJs ident
245+ valueToJs' (Case (maybeSpan, _, _, _) values binders) = do
234246 vals <- mapM valueToJs values
235247 bindersToJs maybeSpan binders vals
236− valueToJs (Let _ ds val) = do
248+ valueToJs' (Let _ ds val) = do
237249 ds' <- concat <$> mapM bindToJs ds
238250 ret <- valueToJs val
239− return $ JSApp (JSFunction Nothing [] (JSBlock (ds' ++ [JSReturn ret]))) []
240− valueToJs (Constructor (_, _, _, Just IsNewtype) _ (ProperName ctor) _) =
241− return $ JSVariableIntroduction ctor (Just $
242− JSObjectLiteral [("create",
243− JSFunction Nothing ["value"]
244− (JSBlock [JSReturn $ JSVar "value"]))])
245− valueToJs (Constructor _ _ (ProperName ctor) []) =
246− return $ iife ctor [ JSFunction (Just ctor) [] (JSBlock [])
247− , JSAssignment (JSAccessor "value" (JSVar ctor))
248− (JSUnary JSNew $ JSApp (JSVar ctor) []) ]
249− valueToJs (Constructor _ _ (ProperName ctor) fields) =
251+ return $ JSApp Nothing (JSFunction Nothing Nothing [] (JSBlock Nothing (ds' ++ [JSReturn Nothing ret]))) []
252+ valueToJs' (Constructor (_, _, _, Just IsNewtype) _ (ProperName ctor) _) =
253+ return $ JSVariableIntroduction Nothing ctor (Just $
254+ JSObjectLiteral Nothing [("create",
255+ JSFunction Nothing Nothing ["value"]
256+ (JSBlock Nothing [JSReturn Nothing $ JSVar Nothing "value"]))])
257+ valueToJs' (Constructor _ _ (ProperName ctor) []) =
258+ return $ iife ctor [ JSFunction Nothing (Just ctor) [] (JSBlock Nothing [])
259+ , JSAssignment Nothing (JSAccessor Nothing "value" (JSVar Nothing ctor))
260+ (JSUnary Nothing JSNew $ JSApp Nothing (JSVar Nothing ctor) []) ]
261+ valueToJs' (Constructor _ _ (ProperName ctor) fields) =
250262 let constructor =
251− let body = [ JSAssignment (JSAccessor (identToJs f) (JSVar "this")) (var f) | f <- fields ]
252− in JSFunction (Just ctor) (identToJs `map` fields) (JSBlock body)
263+ let body = [ JSAssignment Nothing (JSAccessor Nothing (identToJs f) (JSVar Nothing "this")) (var f) | f <- fields ]
264+ in JSFunction Nothing (Just ctor) (identToJs `map` fields) (JSBlock Nothing body)
253265 createFn =
254− let body = JSUnary JSNew $ JSApp (JSVar ctor) (var `map` fields)
255− in foldr (\f inner -> JSFunction Nothing [identToJs f] (JSBlock [JSReturn inner])) body fields
266+ let body = JSUnary Nothing JSNew $ JSApp Nothing (JSVar Nothing ctor) (var `map` fields)
267+ in foldr (\f inner -> JSFunction Nothing Nothing [identToJs f] (JSBlock Nothing [JSReturn Nothing inner])) body fields
256268 in return $ iife ctor [ constructor
257− , JSAssignment (JSAccessor "create" (JSVar ctor)) createFn
269+ , JSAssignment Nothing (JSAccessor Nothing "create" (JSVar Nothing ctor)) createFn
258270 ]
259271
260272 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])) []
262274
263275 literalToValueJS :: Literal (Expr Ann) -> m JS
264− literalToValueJS (NumericLiteral (Left i)) = return $ JSNumericLiteral (Left i)
265− literalToValueJS (NumericLiteral (Right n)) = return $ JSNumericLiteral (Right n)
266− literalToValueJS (StringLiteral s) = return $ JSStringLiteral s
267− literalToValueJS (CharLiteral c) = return $ JSStringLiteral [c]
268− literalToValueJS (BooleanLiteral b) = return $ JSBooleanLiteral b
269− literalToValueJS (ArrayLiteral xs) = JSArrayLiteral <$> mapM valueToJs xs
270− literalToValueJS (ObjectLiteral ps) = JSObjectLiteral <$> mapM (sndM valueToJs) ps
276+ literalToValueJS (NumericLiteral (Left i)) = return $ JSNumericLiteral Nothing (Left i)
277+ literalToValueJS (NumericLiteral (Right n)) = return $ JSNumericLiteral Nothing (Right n)
278+ literalToValueJS (StringLiteral s) = return $ JSStringLiteral Nothing s
279+ literalToValueJS (CharLiteral c) = return $ JSStringLiteral Nothing [c]
280+ literalToValueJS (BooleanLiteral b) = return $ JSBooleanLiteral Nothing b
281+ literalToValueJS (ArrayLiteral xs) = JSArrayLiteral Nothing <$> mapM valueToJs xs
282+ literalToValueJS (ObjectLiteral ps) = JSObjectLiteral Nothing <$> mapM (sndM valueToJs) ps
271283
272284 -- |
273285 -- Shallow copy an object.
@@ -277,16 +289,16 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
277289 newObj <- freshName
278290 key <- freshName
279291 let
280− jsKey = JSVar key
281− jsNewObj = JSVar newObj
282− block = JSBlock (objAssign:copy:extend ++ [JSReturn jsNewObj])
283− objAssign = JSVariableIntroduction newObj (Just $ JSObjectLiteral [])
284− copy = JSForIn key obj $ JSBlock [JSIfElse cond assign Nothing]
285− cond = JSApp (JSAccessor "hasOwnProperty" obj) [jsKey]
286− assign = JSBlock [JSAssignment (JSIndexer jsKey jsNewObj) (JSIndexer jsKey obj)]
287− stToAssign (s, js) = JSAssignment (JSAccessor s jsNewObj) js
292+ jsKey = JSVar Nothing key
293+ jsNewObj = JSVar Nothing newObj
294+ block = JSBlock Nothing (objAssign:copy:extend ++ [JSReturn Nothing jsNewObj])
295+ objAssign = JSVariableIntroduction Nothing newObj (Just $ JSObjectLiteral Nothing [])
296+ copy = JSForIn Nothing key obj $ JSBlock Nothing [JSIfElse Nothing cond assign Nothing]
297+ cond = JSApp Nothing (JSAccessor Nothing "hasOwnProperty" obj) [jsKey]
298+ assign = JSBlock Nothing [JSAssignment Nothing (JSIndexer Nothing jsKey jsNewObj) (JSIndexer Nothing jsKey obj)]
299+ stToAssign (s, js) = JSAssignment Nothing (JSAccessor Nothing s jsNewObj) js
288300 extend = map stToAssign sts
289− return $ JSApp (JSFunction Nothing [] block) []
301+ return $ JSApp Nothing (JSFunction Nothing Nothing [] block) []
290302
291303 -- |
292304 -- 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_ =
301313 -- variable that may have a qualified name.
302314 --
303315 qualifiedToJS :: (a -> Ident) -> Qualified a -> JS
304− qualifiedToJS f (Qualified (Just (ModuleName [ProperName mn'])) a) | mn' == C.prim = JSVar . runIdent $ f a
305− qualifiedToJS f (Qualified (Just mn') a) | mn /= mn' = accessor (f a) (JSVar (moduleNameToJs mn'))
306− qualifiedToJS f (Qualified _ a) = JSVar $ identToJs (f a)
316+ qualifiedToJS f (Qualified (Just (ModuleName [ProperName mn'])) a) | mn' == C.prim = JSVar Nothing . runIdent $ f a
317+ qualifiedToJS f (Qualified (Just mn') a) | mn /= mn' = accessor (f a) (JSVar Nothing (moduleNameToJs mn'))
318+ qualifiedToJS f (Qualified _ a) = JSVar Nothing $ identToJs (f a)
307319
308320 foreignIdent :: Ident -> JS
309− foreignIdent ident = accessorString (runIdent ident) (JSVar "$foreign")
321+ foreignIdent ident = accessorString (runIdent ident) (JSVar Nothing "$foreign")
310322
311323 -- |
312324 -- 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_ =
315327 bindersToJs :: Maybe SourceSpan -> [CaseAlternative Ann] -> [JS] -> m JS
316328 bindersToJs maybeSpan binders vals = do
317329 valNames <- replicateM (length vals) freshName
318− let assignments = zipWith JSVariableIntroduction valNames (map Just vals)
330+ let assignments = zipWith (JSVariableIntroduction Nothing) valNames (map Just vals)
319331 jss <- forM binders $ \(CaseAlternative bs result) -> do
320332 ret <- guardsToJs result
321333 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])))
323335 []
324336 where
325337 go :: [String] -> [JS] -> [Binder Ann] -> m [JS]
@@ -330,43 +342,48 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
330342 go _ _ _ = internalError "Invalid arguments to bindersToJs"
331343
332344 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)]
334346
335347 failedPatternMessage :: String
336348 failedPatternMessage = "Failed pattern match" ++ maybe "" (((" at " ++ runModuleName mn ++ " ") ++) . displayStartEndPos) maybeSpan ++ ": "
337349
338350 valueError :: String -> JS -> JS
339− valueError _ l@(JSNumericLiteral _) = l
340− valueError _ l@(JSStringLiteral _) = l
341− valueError _ l@(JSBooleanLiteral _) = l
342− valueError s _ = JSAccessor "name" . JSAccessor "constructor" $ JSVar s
351+ valueError _ l@(JSNumericLiteral _ _) = l
352+ valueError _ l@(JSStringLiteral _ _) = l
353+ valueError _ l@(JSBooleanLiteral _ _) = l
354+ valueError s _ = JSAccessor Nothing "name" . JSAccessor Nothing "constructor" $ JSVar Nothing s
343355
344356 guardsToJs :: Either [(Guard Ann, Expr Ann)] (Expr Ann) -> m [JS]
345357 guardsToJs (Left gs) = forM gs $ \(cond, val) -> do
346358 cond' <- valueToJs cond
347359 done <- valueToJs val
348− return $ JSIfElse cond' (JSBlock [JSReturn done]) Nothing
349− guardsToJs (Right v) = return . JSReturn <$> valueToJs v
360+ return $ JSIfElse Nothing cond' (JSBlock Nothing [JSReturn Nothing done]) Nothing
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
350367
351368 -- |
352369 -- Generate code in the simplified Javascript intermediate representation for a pattern match
353370 -- binder.
354371 --
355− binderToJs :: String -> [JS] -> Binder Ann -> m [JS]
356− binderToJs _ done (NullBinder{}) = return done
357− binderToJs varName done (LiteralBinder _ l) =
372+ binderToJs' :: String -> [JS] -> Binder Ann -> m [JS]
373+ binderToJs' _ done (NullBinder{}) = return done
374+ binderToJs' varName done (LiteralBinder _ l) =
358375 literalToBinderJS varName done l
359− binderToJs varName done (VarBinder _ ident) =
360− return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : done)
361− binderToJs varName done (ConstructorBinder (_, _, _, Just IsNewtype) _ _ [b]) =
376+ binderToJs' varName done (VarBinder _ ident) =
377+ return (JSVariableIntroduction Nothing (identToJs ident) (Just (JSVar Nothing varName)) : done)
378+ binderToJs' varName done (ConstructorBinder (_, _, _, Just IsNewtype) _ _ [b]) =
362379 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
364381 js <- go (zip fields bs) done
365382 return $ case ctorType of
366383 ProductType -> js
367384 SumType ->
368− [JSIfElse (JSInstanceOf (JSVar varName) (qualifiedToJS (Ident . runProperName) ctor))
369− (JSBlock js)
385+ [JSIfElse Nothing (JSInstanceOf Nothing (JSVar Nothing varName) (qualifiedToJS (Ident . runProperName) ctor))
386+ (JSBlock Nothing js)
370387 Nothing]
371388 where
372389 go :: [(Ident, Binder Ann)] -> [JS] -> m [JS]
@@ -375,24 +392,24 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
375392 argVar <- freshName
376393 done'' <- go remain done'
377394 js <- binderToJs argVar done'' binder
378− return (JSVariableIntroduction argVar (Just (JSAccessor (identToJs field) (JSVar varName))) : js)
379− binderToJs _ _ ConstructorBinder{} =
395+ return (JSVariableIntroduction Nothing argVar (Just (JSAccessor Nothing (identToJs field) (JSVar Nothing varName))) : js)
396+ binderToJs' _ _ ConstructorBinder{} =
380397 internalError "binderToJs: Invalid ConstructorBinder in binderToJs"
381− binderToJs varName done (NamedBinder _ ident binder) = do
398+ binderToJs' varName done (NamedBinder _ ident binder) = do
382399 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)
384401
385402 literalToBinderJS :: String -> [JS] -> Literal (Binder Ann) -> m [JS]
386403 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]
388405 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]
390407 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]
392409 literalToBinderJS varName done (BooleanLiteral True) =
393− return [JSIfElse (JSVar varName) (JSBlock done) Nothing]
410+ return [JSIfElse Nothing (JSVar Nothing varName) (JSBlock Nothing done) Nothing]
394411 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]
396413 literalToBinderJS varName done (ObjectLiteral bs) = go done bs
397414 where
398415 go :: [JS] -> [(String, Binder Ann)] -> m [JS]
@@ -401,10 +418,10 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
401418 propVar <- freshName
402419 done'' <- go done' bs'
403420 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)
405422 literalToBinderJS varName done (ArrayLiteral bs) = do
406423 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]
408425 where
409426 go :: [JS] -> Integer -> [Binder Ann] -> m [JS]
410427 go done' _ [] = return done'
@@ -412,21 +429,21 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign_ =
412429 elVar <- freshName
413430 done'' <- go done' (index + 1) bs'
414431 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)
416433
417434 -- Check that all integers fall within the valid int range for JavaScript.
418435 checkIntegers :: JS -> m ()
419436 checkIntegers = void . everywhereOnJSTopDownM go
420437 where
421438 go :: JS -> m JS
422− go (JSUnary Negate (JSNumericLiteral (Left i))) =
439+ go (JSUnary _ Negate (JSNumericLiteral ss (Left i))) =
423440 -- Move the negation inside the literal; since this is a top-down
424441 -- traversal doing this replacement will stop the next case from raising
425442 -- the error when attempting to use -2147483648, as if left unrewritten
426443 -- the value is `JSUnary Negate (JSNumericLiteral (Left 2147483648))`, and
427444 -- 2147483648 is larger than the maximum allowed int.
428− return $ JSNumericLiteral (Left (-i))
429− go js@(JSNumericLiteral (Left i)) =
445+ return $ JSNumericLiteral ss (Left (-i))
446+ go js@(JSNumericLiteral _ (Left i)) =
430447 let minInt = -2147483648
431448 maxInt = 2147483647
432449 in if i < minInt || i > maxInt
src/Language/PureScript/CodeGen/JS/AST.hs+168−97
@@ -10,6 +10,7 @@ import Control.Monad.Identity
1010
1111import Language.PureScript.Comments
1212import Language.PureScript.Traversals
13+import Language.PureScript.AST (SourceSpan(..))
1314
1415-- |
1516-- Built-in unary operators
@@ -126,120 +127,190 @@ data JS
126127 -- |
127128 -- A numeric literal
128129 --
129− = JSNumericLiteral (Either Integer Double)
130+ = JSNumericLiteral (Maybe SourceSpan) (Either Integer Double)
130131 -- |
131132 -- A string literal
132133 --
133− | JSStringLiteral String
134+ | JSStringLiteral (Maybe SourceSpan) String
134135 -- |
135136 -- A boolean literal
136137 --
137− | JSBooleanLiteral Bool
138+ | JSBooleanLiteral (Maybe SourceSpan) Bool
138139 -- |
139140 -- A unary operator application
140141 --
141− | JSUnary UnaryOperator JS
142+ | JSUnary (Maybe SourceSpan) UnaryOperator JS
142143 -- |
143144 -- A binary operator application
144145 --
145− | JSBinary BinaryOperator JS JS
146+ | JSBinary (Maybe SourceSpan) BinaryOperator JS JS
146147 -- |
147148 -- An array literal
148149 --
149− | JSArrayLiteral [JS]
150+ | JSArrayLiteral (Maybe SourceSpan) [JS]
150151 -- |
151152 -- An array indexer expression
152153 --
153− | JSIndexer JS JS
154+ | JSIndexer (Maybe SourceSpan) JS JS
154155 -- |
155156 -- An object literal
156157 --
157− | JSObjectLiteral [(String, JS)]
158+ | JSObjectLiteral (Maybe SourceSpan) [(String, JS)]
158159 -- |
159160 -- An object property accessor expression
160161 --
161− | JSAccessor String JS
162+ | JSAccessor (Maybe SourceSpan) String JS
162163 -- |
163164 -- A function introduction (optional name, arguments, body)
164165 --
165− | JSFunction (Maybe String) [String] JS
166+ | JSFunction (Maybe SourceSpan) (Maybe String) [String] JS
166167 -- |
167168 -- Function application
168169 --
169− | JSApp JS [JS]
170+ | JSApp (Maybe SourceSpan) JS [JS]
170171 -- |
171172 -- Variable
172173 --
173− | JSVar String
174+ | JSVar (Maybe SourceSpan) String
174175 -- |
175176 -- Conditional expression
176177 --
177− | JSConditional JS JS JS
178+ | JSConditional (Maybe SourceSpan) JS JS JS
178179 -- |
179180 -- A block of expressions in braces
180181 --
181− | JSBlock [JS]
182+ | JSBlock (Maybe SourceSpan) [JS]
182183 -- |
183184 -- A variable introduction and optional initialization
184185 --
185− | JSVariableIntroduction String (Maybe JS)
186+ | JSVariableIntroduction (Maybe SourceSpan) String (Maybe JS)
186187 -- |
187188 -- A variable assignment
188189 --
189− | JSAssignment JS JS
190+ | JSAssignment (Maybe SourceSpan) JS JS
190191 -- |
191192 -- While loop
192193 --
193− | JSWhile JS JS
194+ | JSWhile (Maybe SourceSpan) JS JS
194195 -- |
195196 -- For loop
196197 --
197− | JSFor String JS JS JS
198+ | JSFor (Maybe SourceSpan) String JS JS JS
198199 -- |
199200 -- ForIn loop
200201 --
201− | JSForIn String JS JS
202+ | JSForIn (Maybe SourceSpan) String JS JS
202203 -- |
203204 -- If-then-else statement
204205 --
205− | JSIfElse JS JS (Maybe JS)
206+ | JSIfElse (Maybe SourceSpan) JS JS (Maybe JS)
206207 -- |
207208 -- Return statement
208209 --
209− | JSReturn JS
210+ | JSReturn (Maybe SourceSpan) JS
210211 -- |
211212 -- Throw statement
212213 --
213− | JSThrow JS
214+ | JSThrow (Maybe SourceSpan) JS
214215 -- |
215216 -- Type-Of operator
216217 --
217− | JSTypeOf JS
218+ | JSTypeOf (Maybe SourceSpan) JS
218219 -- |
219220 -- InstanceOf test
220221 --
221− | JSInstanceOf JS JS
222+ | JSInstanceOf (Maybe SourceSpan) JS JS
222223 -- |
223224 -- Labelled statement
224225 --
225− | JSLabel String JS
226+ | JSLabel (Maybe SourceSpan) String JS
226227 -- |
227228 -- Break statement
228229 --
229− | JSBreak String
230+ | JSBreak (Maybe SourceSpan) String
230231 -- |
231232 -- Continue statement
232233 --
233− | JSContinue String
234+ | JSContinue (Maybe SourceSpan) String
234235 -- |
235236 -- Raw Javascript (generated when parsing fails for an inline foreign import declaration)
236237 --
237− | JSRaw String
238+ | JSRaw (Maybe SourceSpan) String
238239 -- |
239240 -- Commented Javascript
240241 --
241− | JSComment [Comment] JS
242− deriving (Show, Read, Eq)
242+ | JSComment (Maybe SourceSpan) [Comment] JS 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
243314
244315--
245316-- Traversals
@@ -249,28 +320,28 @@ everywhereOnJS :: (JS -> JS) -> JS -> JS
249320everywhereOnJS f = go
250321 where
251322 go :: JS -> JS
252− go (JSUnary op j) = f (JSUnary op (go j))
253− go (JSBinary op j1 j2) = f (JSBinary op (go j1) (go j2))
254− go (JSArrayLiteral js) = f (JSArrayLiteral (map go js))
255− go (JSIndexer j1 j2) = f (JSIndexer (go j1) (go j2))
256− go (JSObjectLiteral js) = f (JSObjectLiteral (map (fmap go) js))
257− go (JSAccessor prop j) = f (JSAccessor prop (go j))
258− go (JSFunction name args j) = f (JSFunction name args (go j))
259− go (JSApp j js) = f (JSApp (go j) (map go js))
260− go (JSConditional j1 j2 j3) = f (JSConditional (go j1) (go j2) (go j3))
261− go (JSBlock js) = f (JSBlock (map go js))
262− go (JSVariableIntroduction name j) = f (JSVariableIntroduction name (fmap go j))
263− go (JSAssignment j1 j2) = f (JSAssignment (go j1) (go j2))
264− go (JSWhile j1 j2) = f (JSWhile (go j1) (go j2))
265− go (JSFor name j1 j2 j3) = f (JSFor name (go j1) (go j2) (go j3))
266− go (JSForIn name j1 j2) = f (JSForIn name (go j1) (go j2))
267− go (JSIfElse j1 j2 j3) = f (JSIfElse (go j1) (go j2) (fmap go j3))
268− go (JSReturn js) = f (JSReturn (go js))
269− go (JSThrow js) = f (JSThrow (go js))
270− go (JSTypeOf js) = f (JSTypeOf (go js))
271− go (JSLabel name js) = f (JSLabel name (go js))
272− go (JSInstanceOf j1 j2) = f (JSInstanceOf (go j1) (go j2))
273− go (JSComment com j) = f (JSComment com (go j))
323+ go (JSUnary ss op j) = f (JSUnary ss op (go j))
324+ go (JSBinary ss op j1 j2) = f (JSBinary ss op (go j1) (go j2))
325+ go (JSArrayLiteral ss js) = f (JSArrayLiteral ss (map go js))
326+ go (JSIndexer ss j1 j2) = f (JSIndexer ss (go j1) (go j2))
327+ go (JSObjectLiteral ss js) = f (JSObjectLiteral ss (map (fmap go) js))
328+ go (JSAccessor ss prop j) = f (JSAccessor ss prop (go j))
329+ go (JSFunction ss name args j) = f (JSFunction ss name args (go j))
330+ go (JSApp ss j js) = f (JSApp ss (go j) (map go js))
331+ go (JSConditional ss j1 j2 j3) = f (JSConditional ss (go j1) (go j2) (go j3))
332+ go (JSBlock ss js) = f (JSBlock ss (map go js))
333+ go (JSVariableIntroduction ss name j) = f (JSVariableIntroduction ss name (fmap go j))
334+ go (JSAssignment ss j1 j2) = f (JSAssignment ss (go j1) (go j2))
335+ go (JSWhile ss j1 j2) = f (JSWhile ss (go j1) (go j2))
336+ go (JSFor ss name j1 j2 j3) = f (JSFor ss name (go j1) (go j2) (go j3))
337+ go (JSForIn ss name j1 j2) = f (JSForIn ss name (go j1) (go j2))
338+ go (JSIfElse ss j1 j2 j3) = f (JSIfElse ss (go j1) (go j2) (fmap go j3))
339+ go (JSReturn ss js) = f (JSReturn ss (go js))
340+ go (JSThrow ss js) = f (JSThrow ss (go js))
341+ go (JSTypeOf ss js) = f (JSTypeOf ss (go js))
342+ go (JSLabel ss name js) = f (JSLabel ss name (go js))
343+ go (JSInstanceOf ss j1 j2) = f (JSInstanceOf ss (go j1) (go j2))
344+ go (JSComment ss com j) = f (JSComment ss com (go j))
274345 go other = f other
275346
276347everywhereOnJSTopDown :: (JS -> JS) -> JS -> JS
@@ -280,54 +351,54 @@ everywhereOnJSTopDownM :: (Applicative m, Monad m) => (JS -> m JS) -> JS -> m JS
280351everywhereOnJSTopDownM f = f >=> go
281352 where
282353 f' = f >=> go
283− go (JSUnary op j) = JSUnary op <$> f' j
284− go (JSBinary op j1 j2) = JSBinary op <$> f' j1 <*> f' j2
285− go (JSArrayLiteral js) = JSArrayLiteral <$> traverse f' js
286− go (JSIndexer j1 j2) = JSIndexer <$> f' j1 <*> f' j2
287− go (JSObjectLiteral js) = JSObjectLiteral <$> traverse (sndM f') js
288− go (JSAccessor prop j) = JSAccessor prop <$> f' j
289− go (JSFunction name args j) = JSFunction name args <$> f' j
290− go (JSApp j js) = JSApp <$> f' j <*> traverse f' js
291− go (JSConditional j1 j2 j3) = JSConditional <$> f' j1 <*> f' j2 <*> f' j3
292− go (JSBlock js) = JSBlock <$> traverse f' js
293− go (JSVariableIntroduction name j) = JSVariableIntroduction name <$> traverse f' j
294− go (JSAssignment j1 j2) = JSAssignment <$> f' j1 <*> f' j2
295− go (JSWhile j1 j2) = JSWhile <$> f' j1 <*> f' j2
296− go (JSFor name j1 j2 j3) = JSFor name <$> f' j1 <*> f' j2 <*> f' j3
297− go (JSForIn name j1 j2) = JSForIn name <$> f' j1 <*> f' j2
298− go (JSIfElse j1 j2 j3) = JSIfElse <$> f' j1 <*> f' j2 <*> traverse f' j3
299− go (JSReturn j) = JSReturn <$> f' j
300− go (JSThrow j) = JSThrow <$> f' j
301− go (JSTypeOf j) = JSTypeOf <$> f' j
302− go (JSLabel name j) = JSLabel name <$> f' j
303− go (JSInstanceOf j1 j2) = JSInstanceOf <$> f' j1 <*> f' j2
304− go (JSComment com j) = JSComment com <$> f' j
354+ go (JSUnary ss op j) = JSUnary ss op <$> f' j
355+ go (JSBinary ss op j1 j2) = JSBinary ss op <$> f' j1 <*> f' j2
356+ go (JSArrayLiteral ss js) = JSArrayLiteral ss <$> traverse f' js
357+ go (JSIndexer ss j1 j2) = JSIndexer ss <$> f' j1 <*> f' j2
358+ go (JSObjectLiteral ss js) = JSObjectLiteral ss <$> traverse (sndM f') js
359+ go (JSAccessor ss prop j) = JSAccessor ss prop <$> f' j
360+ go (JSFunction ss name args j) = JSFunction ss name args <$> f' j
361+ go (JSApp ss j js) = JSApp ss <$> f' j <*> traverse f' js
362+ go (JSConditional ss j1 j2 j3) = JSConditional ss <$> f' j1 <*> f' j2 <*> f' j3
363+ go (JSBlock ss js) = JSBlock ss <$> traverse f' js
364+ go (JSVariableIntroduction ss name j) = JSVariableIntroduction ss name <$> traverse f' j
365+ go (JSAssignment ss j1 j2) = JSAssignment ss <$> f' j1 <*> f' j2
366+ go (JSWhile ss j1 j2) = JSWhile ss <$> f' j1 <*> f' j2
367+ go (JSFor ss name j1 j2 j3) = JSFor ss name <$> f' j1 <*> f' j2 <*> f' j3
368+ go (JSForIn ss name j1 j2) = JSForIn ss name <$> f' j1 <*> f' j2
369+ go (JSIfElse ss j1 j2 j3) = JSIfElse ss <$> f' j1 <*> f' j2 <*> traverse f' j3
370+ go (JSReturn ss j) = JSReturn ss <$> f' j
371+ go (JSThrow ss j) = JSThrow ss <$> f' j
372+ go (JSTypeOf ss j) = JSTypeOf ss <$> f' j
373+ go (JSLabel ss name j) = JSLabel ss name <$> f' j
374+ go (JSInstanceOf ss j1 j2) = JSInstanceOf ss <$> f' j1 <*> f' j2
375+ go (JSComment ss com j) = JSComment ss com <$> f' j
305376 go other = f other
306377
307378everythingOnJS :: (r -> r -> r) -> (JS -> r) -> JS -> r
308379everythingOnJS (<>) f = go
309380 where
310− go j@(JSUnary _ j1) = f j <> go j1
311− go j@(JSBinary _ j1 j2) = f j <> go j1 <> go j2
312− go j@(JSArrayLiteral js) = foldl (<>) (f j) (map go js)
313− go j@(JSIndexer j1 j2) = f j <> go j1 <> go j2
314− go j@(JSObjectLiteral js) = foldl (<>) (f j) (map (go . snd) js)
315− go j@(JSAccessor _ j1) = f j <> go j1
316− go j@(JSFunction _ _ j1) = f j <> go j1
317− 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
319− go j@(JSBlock js) = foldl (<>) (f j) (map go js)
320− go j@(JSVariableIntroduction _ (Just j1)) = f j <> go j1
321− go j@(JSAssignment j1 j2) = f j <> go j1 <> go j2
322− 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
324− go j@(JSForIn _ j1 j2) = f j <> go j1 <> go j2
325− 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
327− go j@(JSReturn j1) = f j <> go j1
328− go j@(JSThrow j1) = f j <> go j1
329− go j@(JSTypeOf j1) = f j <> go j1
330− go j@(JSLabel _ j1) = f j <> go j1
331− go j@(JSInstanceOf j1 j2) = f j <> go j1 <> go j2
332− go j@(JSComment _ j1) = f j <> go j1
381+ go j@(JSUnary _ _ j1) = f j <> go j1
382+ go j@(JSBinary _ _ j1 j2) = f j <> go j1 <> go j2
383+ go j@(JSArrayLiteral _ js) = foldl (<>) (f j) (map go js)
384+ go j@(JSIndexer _ j1 j2) = f j <> go j1 <> go j2
385+ go j@(JSObjectLiteral _ js) = foldl (<>) (f j) (map (go . snd) js)
386+ go j@(JSAccessor _ _ j1) = f j <> go j1
387+ go j@(JSFunction _ _ _ j1) = f j <> go j1
388+ go j@(JSApp _ j1 js) = foldl (<>) (f j <> go j1) (map go js)
389+ go j@(JSConditional _ j1 j2 j3) = f j <> go j1 <> go j2 <> go j3
390+ go j@(JSBlock _ js) = foldl (<>) (f j) (map go js)
391+ go j@(JSVariableIntroduction _ _ (Just j1)) = f j <> go j1
392+ go j@(JSAssignment _ j1 j2) = f j <> go j1 <> go j2
393+ go j@(JSWhile _ j1 j2) = f j <> go j1 <> go j2
394+ go j@(JSFor _ _ j1 j2 j3) = f j <> go j1 <> go j2 <> go j3
395+ go j@(JSForIn _ _ j1 j2) = f j <> go j1 <> go j2
396+ go j@(JSIfElse _ j1 j2 Nothing) = f j <> go j1 <> go j2
397+ go j@(JSIfElse _ j1 j2 (Just j3)) = f j <> go j1 <> go j2 <> go j3
398+ go j@(JSReturn _ j1) = f j <> go j1
399+ go j@(JSThrow _ j1) = f j <> go j1
400+ go j@(JSTypeOf _ j1) = f j <> go j1
401+ go j@(JSLabel _ _ j1) = f j <> go j1
402+ go j@(JSInstanceOf _ j1 j2) = f j <> go j1 <> go j2
403+ go j@(JSComment _ _ j1) = f j <> go j1
333404 go other = f other
src/Language/PureScript/CodeGen/JS/Optimizer.hs+5−5
@@ -53,11 +53,11 @@ optimize' js = do
5353 opts <- ask
5454 js' <- untilFixedPoint (inlineFnComposition . tidyUp . applyAll
5555 [ inlineCommonValues
56− , inlineOperator (C.prelude, (C.$)) $ \f x -> JSApp f [x]
57− , inlineOperator (C.dataFunction, C.apply) $ \f x -> JSApp f [x]
58− , inlineOperator (C.prelude, (C.#)) $ \x f -> JSApp f [x]
59− , inlineOperator (C.dataFunction, C.applyFlipped) $ \x f -> JSApp f [x]
60− , inlineOperator (C.dataArrayUnsafe, C.unsafeIndex) $ flip JSIndexer
56+ , inlineOperator (C.prelude, (C.$)) $ \f x -> JSApp Nothing f [x]
57+ , inlineOperator (C.dataFunction, C.apply) $ \f x -> JSApp Nothing f [x]
58+ , inlineOperator (C.prelude, (C.#)) $ \x f -> JSApp Nothing f [x]
59+ , inlineOperator (C.dataFunction, C.applyFlipped) $ \x f -> JSApp Nothing f [x]
60+ , inlineOperator (C.dataArrayUnsafe, C.unsafeIndex) $ flip (JSIndexer Nothing)
6161 , inlineCommonOperators
6262 ]) js
6363 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
2727collapseNestedBlocks = everywhereOnJS collapse
2828 where
2929 collapse :: JS -> JS
30− collapse (JSBlock sts) = JSBlock (concatMap go sts)
30+ collapse (JSBlock ss sts) = JSBlock ss (concatMap go sts)
3131 collapse js = js
3232 go :: JS -> [JS]
33− go (JSBlock sts) = sts
33+ go (JSBlock _ sts) = sts
3434 go s = [s]
3535
3636collapseNestedIfs :: JS -> JS
3737collapseNestedIfs = everywhereOnJS collapse
3838 where
3939 collapse :: JS -> JS
40− collapse (JSIfElse cond1 (JSBlock [JSIfElse cond2 body Nothing]) Nothing) =
41− JSIfElse (JSBinary And cond1 cond2) body Nothing
40+ collapse (JSIfElse s1 cond1 (JSBlock _ [JSIfElse s2 cond2 body Nothing]) Nothing) =
41+ JSIfElse s1 (JSBinary s2 And cond1 cond2) body Nothing
4242 collapse js = js
src/Language/PureScript/CodeGen/JS/Optimizer/Common.hs+18−18
@@ -14,67 +14,67 @@ applyAll = foldl1 (.)
1414replaceIdent :: String -> JS -> JS -> JS
1515replaceIdent var1 js = everywhereOnJS replace
1616 where
17− replace (JSVar var2) | var1 == var2 = js
17+ replace (JSVar _ var2) | var1 == var2 = js
1818 replace other = other
1919
2020replaceIdents :: [(String, JS)] -> JS -> JS
2121replaceIdents vars = everywhereOnJS replace
2222 where
23− replace v@(JSVar var) = fromMaybe v $ lookup var vars
23+ replace v@(JSVar _ var) = fromMaybe v $ lookup var vars
2424 replace other = other
2525
2626isReassigned :: String -> JS -> Bool
2727isReassigned var1 = everythingOnJS (||) check
2828 where
2929 check :: JS -> Bool
30− check (JSFunction _ args _) | var1 `elem` args = True
31− check (JSVariableIntroduction arg _) | var1 == arg = True
32− check (JSAssignment (JSVar arg) _) | var1 == arg = True
33− check (JSFor arg _ _ _) | var1 == arg = True
34− check (JSForIn arg _ _) | var1 == arg = True
30+ check (JSFunction _ _ args _) | var1 `elem` args = True
31+ check (JSVariableIntroduction _ arg _) | var1 == arg = True
32+ check (JSAssignment _ (JSVar _ arg) _) | var1 == arg = True
33+ check (JSFor _ arg _ _ _) | var1 == arg = True
34+ check (JSForIn _ arg _ _) | var1 == arg = True
3535 check _ = False
3636
3737isRebound :: JS -> JS -> Bool
3838isRebound js d = any (\v -> isReassigned v d || isUpdated v d) (everythingOnJS (++) variablesOf js)
3939 where
40− variablesOf (JSVar var) = [var]
40+ variablesOf (JSVar _ var) = [var]
4141 variablesOf _ = []
4242
4343isUsed :: String -> JS -> Bool
4444isUsed var1 = everythingOnJS (||) check
4545 where
4646 check :: JS -> Bool
47− check (JSVar var2) | var1 == var2 = True
48− check (JSAssignment target _) | var1 == targetVariable target = True
47+ check (JSVar _ var2) | var1 == var2 = True
48+ check (JSAssignment _ target _) | var1 == targetVariable target = True
4949 check _ = False
5050
5151targetVariable :: JS -> String
52−targetVariable (JSVar var) = var
53−targetVariable (JSAccessor _ tgt) = targetVariable tgt
54−targetVariable (JSIndexer _ tgt) = targetVariable tgt
52+targetVariable (JSVar _ var) = var
53+targetVariable (JSAccessor _ _ tgt) = targetVariable tgt
54+targetVariable (JSIndexer _ _ tgt) = targetVariable tgt
5555targetVariable _ = internalError "Invalid argument to targetVariable"
5656
5757isUpdated :: String -> JS -> Bool
5858isUpdated var1 = everythingOnJS (||) check
5959 where
6060 check :: JS -> Bool
61− check (JSAssignment target _) | var1 == targetVariable target = True
61+ check (JSAssignment _ target _) | var1 == targetVariable target = True
6262 check _ = False
6363
6464removeFromBlock :: ([JS] -> [JS]) -> JS -> JS
65−removeFromBlock go (JSBlock sts) = JSBlock (go sts)
65+removeFromBlock go (JSBlock ss sts) = JSBlock ss (go sts)
6666removeFromBlock _ js = js
6767
6868isFn :: (String, String) -> JS -> Bool
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
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
7171isFn _ _ = False
7272
7373isFn' :: [(String, String)] -> JS -> Bool
7474isFn' xs js = any (`isFn` js) xs
7575
7676isDict :: (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
7878isDict _ _ = False
7979
8080isDict' :: [(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
2929-- Needs to be: { 0..toFixed(10); }
3030-- Probably needs to be fixed in pretty-printer instead.
3131shouldInline :: JS -> Bool
32−shouldInline (JSVar _) = True
33−shouldInline (JSNumericLiteral _) = True
34−shouldInline (JSStringLiteral _) = True
35−shouldInline (JSBooleanLiteral _) = True
36−shouldInline (JSAccessor _ val) = shouldInline val
37−shouldInline (JSIndexer index val) = shouldInline index && shouldInline val
32+shouldInline (JSVar _ _) = True
33+shouldInline (JSNumericLiteral _ _) = True
34+shouldInline (JSStringLiteral _ _) = True
35+shouldInline (JSBooleanLiteral _ _) = True
36+shouldInline (JSAccessor _ _ val) = shouldInline val
37+shouldInline (JSIndexer _ index val) = shouldInline index && shouldInline val
3838shouldInline _ = False
3939
4040etaConvert :: JS -> JS
4141etaConvert = everywhereOnJS convert
4242 where
4343 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)])
4545 | all shouldInline args &&
46− not (any (`isRebound` block) (map JSVar idents)) &&
46+ not (any (`isRebound` block) (map (JSVar Nothing) idents)) &&
4747 not (any (`isRebound` block) args)
48− = JSBlock (map (replaceIdents (zip idents args)) body)
49− convert (JSFunction Nothing [] (JSBlock [JSReturn (JSApp fn [])])) = fn
48+ = JSBlock ss (map (replaceIdents (zip idents args)) body)
49+ convert (JSFunction _ Nothing [] (JSBlock _ [JSReturn _ (JSApp _ fn [])])) = fn
5050 convert js = js
5151
5252unThunk :: JS -> JS
5353unThunk = everywhereOnJS convert
5454 where
5555 convert :: JS -> JS
56− convert (JSBlock []) = JSBlock []
57− convert (JSBlock jss) =
56+ convert (JSBlock ss []) = JSBlock ss []
57+ convert (JSBlock ss jss) =
5858 case last jss of
59− JSReturn (JSApp (JSFunction Nothing [] (JSBlock body)) []) -> JSBlock $ init jss ++ body
60− _ -> JSBlock jss
59+ JSReturn _ (JSApp _ (JSFunction _ Nothing [] (JSBlock _ body)) []) -> JSBlock ss $ init jss ++ body
60+ _ -> JSBlock ss jss
6161 convert js = js
6262
6363evaluateIifes :: JS -> JS
6464evaluateIifes = everywhereOnJS convert
6565 where
6666 convert :: JS -> JS
67− convert (JSApp (JSFunction Nothing [] (JSBlock [JSReturn ret])) []) = ret
67+ convert (JSApp _ (JSFunction _ Nothing [] (JSBlock _ [JSReturn _ ret])) []) = ret
6868 convert js = js
6969
7070inlineVariables :: JS -> JS
@@ -72,7 +72,7 @@ inlineVariables = everywhereOnJS $ removeFromBlock go
7272 where
7373 go :: [JS] -> [JS]
7474 go [] = []
75− go (JSVariableIntroduction var (Just js) : sts)
75+ go (JSVariableIntroduction _ var (Just js) : sts)
7676 | shouldInline js && not (any (isReassigned var) sts) && not (any (isRebound js) sts) && not (any (isUpdated var) sts) =
7777 go (map (replaceIdent var js) sts)
7878 go (s:sts) = s : go sts
@@ -81,16 +81,16 @@ inlineCommonValues :: JS -> JS
8181inlineCommonValues = everywhereOnJS convert
8282 where
8383 convert :: JS -> JS
84− convert (JSApp fn [dict])
85− | isDict' (semiringNumber ++ semiringInt) dict && isFn' fnZero fn = JSNumericLiteral (Left 0)
86− | isDict' (semiringNumber ++ semiringInt) dict && isFn' fnOne fn = JSNumericLiteral (Left 1)
87− | isDict' boundedBoolean dict && isFn' fnBottom fn = JSBooleanLiteral False
88− | isDict' boundedBoolean dict && isFn' fnTop fn = JSBooleanLiteral True
89− convert (JSApp (JSApp (JSApp fn [dict]) [x]) [y])
90− | isDict' semiringInt dict && isFn' fnAdd fn = intOp Add x y
91− | isDict' semiringInt dict && isFn' fnMultiply fn = intOp Multiply x y
92− | isDict' moduloSemiringInt dict && isFn' fnDivide fn = intOp Divide x y
93− | isDict' ringInt dict && isFn' fnSubtract fn = intOp Subtract x y
84+ convert (JSApp ss fn [dict])
85+ | isDict' (semiringNumber ++ semiringInt) dict && isFn' fnZero fn = JSNumericLiteral ss (Left 0)
86+ | isDict' (semiringNumber ++ semiringInt) dict && isFn' fnOne fn = JSNumericLiteral ss (Left 1)
87+ | isDict' boundedBoolean dict && isFn' fnBottom fn = JSBooleanLiteral ss False
88+ | isDict' boundedBoolean dict && isFn' fnTop fn = JSBooleanLiteral ss True
89+ convert (JSApp ss (JSApp _ (JSApp _ fn [dict]) [x]) [y])
90+ | isDict' semiringInt dict && isFn' fnAdd fn = intOp ss Add x y
91+ | isDict' semiringInt dict && isFn' fnMultiply fn = intOp ss Multiply x y
92+ | isDict' moduloSemiringInt dict && isFn' fnDivide fn = intOp ss Divide x y
93+ | isDict' ringInt dict && isFn' fnSubtract fn = intOp ss Subtract x y
9494 convert other = other
9595 fnZero = [(C.prelude, C.zero), (C.dataSemiring, C.zero)]
9696 fnOne = [(C.prelude, C.one), (C.dataSemiring, C.one)]
@@ -100,16 +100,16 @@ inlineCommonValues = everywhereOnJS convert
100100 fnDivide = [(C.prelude, (C./)), (C.prelude, (C.div)), (C.dataModuloSemiring, C.div)]
101101 fnMultiply = [(C.prelude, (C.*)), (C.prelude, (C.mul)), (C.dataSemiring, (C.*)), (C.dataSemiring, (C.mul))]
102102 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))
104104
105105inlineOperator :: (String, String) -> (JS -> JS -> JS) -> JS -> JS
106106inlineOperator (m, op) f = everywhereOnJS convert
107107 where
108108 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
110110 convert other = other
111− isOp (JSAccessor longForm (JSVar m')) = m == m' && longForm == identToJs (Op op)
112− isOp (JSIndexer (JSStringLiteral op') (JSVar m')) = m == m' && 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'
113113 isOp _ = False
114114
115115inlineCommonOperators :: JS -> JS
@@ -177,49 +177,49 @@ inlineCommonOperators = applyAll $
177177 binary dict fns op = everywhereOnJS convert
178178 where
179179 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
181181 convert other = other
182182 binary' :: String -> String -> BinaryOperator -> JS -> JS
183183 binary' moduleName opString op = everywhereOnJS convert
184184 where
185185 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
187187 convert other = other
188188 unary :: [(String, String)] -> [(String, String)] -> UnaryOperator -> JS -> JS
189189 unary dicts fns op = everywhereOnJS convert
190190 where
191191 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
193193 convert other = other
194194 unary' :: String -> String -> UnaryOperator -> JS -> JS
195195 unary' moduleName fnName op = everywhereOnJS convert
196196 where
197197 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
199199 convert other = other
200200 mkFn :: Int -> JS -> JS
201201 mkFn 0 = everywhereOnJS convert
202202 where
203203 convert :: JS -> JS
204− convert (JSApp mkFnN [JSFunction Nothing [_] (JSBlock js)]) | isNFn C.mkFn 0 mkFnN =
205− JSFunction Nothing [] (JSBlock js)
204+ convert (JSApp _ mkFnN [JSFunction s1 Nothing [_] (JSBlock s2 js)]) | isNFn C.mkFn 0 mkFnN =
205+ JSFunction s1 Nothing [] (JSBlock s2 js)
206206 convert other = other
207207 mkFn n = everywhereOnJS convert
208208 where
209209 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 =
211211 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)
213213 Nothing -> orig
214214 convert other = other
215215 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)
217− collectArgs m acc (JSFunction Nothing [oneArg] (JSBlock [JSReturn ret])) = collectArgs (m - 1) (oneArg : acc) ret
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
218218 collectArgs _ _ _ = Nothing
219219
220220 isNFn :: String -> Int -> JS -> Bool
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)
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)
223223 isNFn _ _ _ = False
224224
225225 runFn :: Int -> JS -> JS
@@ -229,8 +229,8 @@ inlineCommonOperators = applyAll $
229229 convert js = fromMaybe js $ go n [] js
230230
231231 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)
233− go m acc (JSApp lhs [arg]) = go (m - 1) (arg : acc) lhs
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
234234 go _ _ _ = Nothing
235235
236236-- (f <<< g $ x) = f (g x)
@@ -239,16 +239,16 @@ inlineFnComposition :: (Applicative m, MonadSupply m) => JS -> m JS
239239inlineFnComposition = everywhereOnJSTopDownM convert
240240 where
241241 convert :: (MonadSupply m) => JS -> m JS
242− convert (JSApp (JSApp (JSApp (JSApp fn [dict']) [x]) [y]) [z])
243− | isFnCompose dict' fn = return $ JSApp x [JSApp y [z]]
244− | isFnComposeFlipped dict' fn = return $ JSApp y [JSApp x [z]]
245− convert (JSApp (JSApp (JSApp fn [dict']) [x]) [y])
242+ convert (JSApp s1 (JSApp s2 (JSApp _ (JSApp _ fn [dict']) [x]) [y]) [z])
243+ | isFnCompose dict' fn = return $ JSApp s1 x [JSApp s2 y [z]]
244+ | isFnComposeFlipped dict' fn = return $ JSApp s2 y [JSApp s1 x [z]]
245+ convert (JSApp ss (JSApp _ (JSApp _ fn [dict']) [x]) [y])
246246 | isFnCompose dict' fn = do
247247 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]]])
249249 | isFnComposeFlipped dict' fn = do
250250 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]]])
252252 convert other = return other
253253 isFnCompose :: JS -> JS -> Bool
254254 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
4040 -- Desugar monomorphic calls to >>= and return for the Eff monad
4141 convert :: JS -> JS
4242 -- Desugar pure & return
43− convert (JSApp (JSApp pure' [val]) []) | isPure pure' = val
43+ convert (JSApp _ (JSApp _ pure' [val]) []) | isPure pure' = val
4444 -- Desugar >>
45− convert (JSApp (JSApp bind [m]) [JSFunction Nothing [] (JSBlock js)]) | isBind bind =
46− JSFunction (Just fnName) [] $ JSBlock (JSApp m [] : map applyReturns js )
45+ convert (JSApp _ (JSApp _ bind [m]) [JSFunction s1 Nothing [] (JSBlock s2 js)]) | isBind bind =
46+ JSFunction s1 (Just fnName) [] $ JSBlock s2 (JSApp s2 m [] : map applyReturns js )
4747 -- Desugar >>=
48− convert (JSApp (JSApp bind [m]) [JSFunction Nothing [arg] (JSBlock js)]) | isBind bind =
49− JSFunction (Just fnName) [] $ JSBlock (JSVariableIntroduction arg (Just (JSApp m [])) : map applyReturns js)
48+ convert (JSApp _ (JSApp _ bind [m]) [JSFunction s1 Nothing [arg] (JSBlock s2 js)]) | isBind bind =
49+ JSFunction s1 (Just fnName) [] $ JSBlock s2 (JSVariableIntroduction s2 arg (Just (JSApp s2 m [])) : map applyReturns js)
5050 -- Desugar untilE
51− convert (JSApp (JSApp f [arg]) []) | isEffFunc C.untilE f =
52− JSApp (JSFunction Nothing [] (JSBlock [ JSWhile (JSUnary Not (JSApp arg [])) (JSBlock []), JSReturn $ JSObjectLiteral []])) []
51+ convert (JSApp s1 (JSApp _ f [arg]) []) | isEffFunc C.untilE f =
52+ JSApp s1 (JSFunction s1 Nothing [] (JSBlock s1 [ JSWhile s1 (JSUnary s1 Not (JSApp s1 arg [])) (JSBlock s1 []), JSReturn s1 $ JSObjectLiteral s1 []])) []
5353 -- Desugar whileE
54− convert (JSApp (JSApp (JSApp f [arg1]) [arg2]) []) | isEffFunc C.whileE f =
55− JSApp (JSFunction Nothing [] (JSBlock [ JSWhile (JSApp arg1 []) (JSBlock [ JSApp arg2 [] ]), JSReturn $ JSObjectLiteral []])) []
54+ convert (JSApp _ (JSApp _ (JSApp s1 f [arg1]) [arg2]) []) | isEffFunc C.whileE f =
55+ JSApp s1 (JSFunction s1 Nothing [] (JSBlock s1 [ JSWhile s1 (JSApp s1 arg1 []) (JSBlock s1 [ JSApp s1 arg2 [] ]), JSReturn s1 $ JSObjectLiteral s1 []])) []
5656 convert other = other
5757 -- 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
5959 isBind _ = False
6060 -- 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
6262 isPure _ = False
6363 -- Check if an expression represents the polymorphic >>= function
6464 isBindPoly = isFn' [(C.prelude, C.bind), (C.prelude, (C.>>=)), (C.controlBind, C.bind)]
6565 -- Check if an expression represents the polymorphic pure or return function
6666 isPurePoly = isFn' [(C.prelude, C.pure'), (C.prelude, C.return), (C.controlApplicative, C.pure')]
6767 -- 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'
6969 isEffFunc _ _ = False
7070
7171 -- Remove __do function applications which remain after desugaring
7272 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
7474 undo other = other
7575
7676 applyReturns :: JS -> JS
77− applyReturns (JSReturn ret) = JSReturn (JSApp ret [])
78− applyReturns (JSBlock jss) = JSBlock (map applyReturns jss)
79− applyReturns (JSWhile cond js) = JSWhile cond (applyReturns js)
80− applyReturns (JSFor v lo hi js) = JSFor v lo hi (applyReturns js)
81− applyReturns (JSForIn v xs js) = JSForIn v xs (applyReturns js)
82− applyReturns (JSIfElse cond t f) = JSIfElse cond (applyReturns t) (applyReturns `fmap` f)
77+ applyReturns (JSReturn ss ret) = JSReturn ss (JSApp ss ret [])
78+ applyReturns (JSBlock ss jss) = JSBlock ss (map applyReturns jss)
79+ applyReturns (JSWhile ss cond js) = JSWhile ss cond (applyReturns js)
80+ applyReturns (JSFor ss v lo hi js) = JSFor ss v lo hi (applyReturns js)
81+ applyReturns (JSForIn ss v xs js) = JSForIn ss v xs (applyReturns js)
82+ applyReturns (JSIfElse ss cond t f) = JSIfElse ss cond (applyReturns t) (applyReturns `fmap` f)
8383 applyReturns other = other
8484
8585-- |
@@ -91,7 +91,7 @@ inlineST = everywhereOnJS convertBlock
9191 -- Look for runST blocks and inline the STRefs there.
9292 -- If all STRefs are used in the scope of the same runST, only using { read, write, modify }STRef then
9393 -- 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 =
9595 let refs = nub . findSTRefsIn $ arg
9696 usages = findAllSTUsagesIn arg
9797 allUsagesAreLocalVars = all (\u -> let v = toVar u in isJust v && fromJust v `elem` refs) usages
@@ -101,34 +101,34 @@ inlineST = everywhereOnJS convertBlock
101101 -- Convert a block in a safe way, preserving object wrappers of references,
102102 -- or in a more aggressive way, turning wrappers into local variables depending on the
103103 -- agg(ressive) parameter.
104− convert agg (JSApp f [arg]) | isSTFunc C.newSTRef f =
105− JSFunction Nothing [] (JSBlock [JSReturn $ if agg then arg else JSObjectLiteral [(C.stRefValue, arg)]])
106− convert agg (JSApp (JSApp f [ref]) []) | isSTFunc C.readSTRef f =
107− if agg then ref else JSAccessor C.stRefValue ref
108− convert agg (JSApp (JSApp (JSApp f [ref]) [arg]) []) | isSTFunc C.writeSTRef f =
109− if agg then JSAssignment ref arg else JSAssignment (JSAccessor C.stRefValue ref) arg
110− convert agg (JSApp (JSApp (JSApp 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])
104+ convert agg (JSApp s1 f [arg]) | isSTFunc C.newSTRef f =
105+ JSFunction s1 Nothing [] (JSBlock s1 [JSReturn s1 $ if agg then arg else JSObjectLiteral s1 [(C.stRefValue, arg)]])
106+ convert agg (JSApp _ (JSApp s1 f [ref]) []) | isSTFunc C.readSTRef f =
107+ if agg then ref else JSAccessor s1 C.stRefValue ref
108+ convert agg (JSApp _ (JSApp _ (JSApp s1 f [ref]) [arg]) []) | isSTFunc C.writeSTRef f =
109+ if agg then JSAssignment s1 ref arg else JSAssignment s1 (JSAccessor s1 C.stRefValue ref) arg
110+ convert agg (JSApp _ (JSApp _ (JSApp s1 f [ref]) [func]) []) | isSTFunc C.modifySTRef f =
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])
112112 convert _ other = other
113113 -- 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'
115115 isSTFunc _ _ = False
116116 -- Find all ST Refs initialized in this block
117117 findSTRefsIn = everythingOnJS (++) isSTRef
118118 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]
120120 isSTRef _ = []
121121 -- Find all STRefs used as arguments to readSTRef, writeSTRef, modifySTRef
122122 findAllSTUsagesIn = everythingOnJS (++) isSTUsage
123123 where
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]
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]
126126 isSTUsage _ = []
127127 -- Find all uses of a variable
128128 appearingIn ref = everythingOnJS (++) isVar
129129 where
130− isVar e@(JSVar v) | v == ref = [e]
130+ isVar e@(JSVar _ v) | v == ref = [e]
131131 isVar _ = []
132132 -- Convert a JS value to a String if it is a JSVar
133− toVar (JSVar v) = Just v
133+ toVar (JSVar _ v) = Just v
134134 toVar _ = Nothing
src/Language/PureScript/CodeGen/JS/Optimizer/TCO.hs+33−31
@@ -40,7 +40,7 @@ tco' = everywhereOnJS convert
4040 copyVar arg = "__copy_" ++ arg
4141
4242 convert :: JS -> JS
43− convert js@(JSVariableIntroduction name (Just fn@JSFunction {})) =
43+ convert js@(JSVariableIntroduction ss name (Just fn@JSFunction {})) =
4444 let
4545 (argss, body', replace) = collectAllFunctionArgs [] id fn
4646 in case () of
@@ -48,19 +48,19 @@ tco' = everywhereOnJS convert
4848 let
4949 allArgs = concat $ reverse argss
5050 in
51− JSVariableIntroduction name (Just (replace (toLoop name allArgs body')))
51+ JSVariableIntroduction ss name (Just (replace (toLoop name allArgs body')))
5252 | otherwise -> js
5353 convert js = js
5454
5555 collectAllFunctionArgs :: [[String]] -> (JS -> JS) -> JS -> ([[String]], JS, JS -> JS)
56− collectAllFunctionArgs allArgs f (JSFunction ident args (JSBlock (body@(JSReturn _):_))) =
57− collectAllFunctionArgs (args : allArgs) (\b -> f (JSFunction ident (map copyVar args) (JSBlock [b]))) body
58− collectAllFunctionArgs allArgs f (JSFunction ident args body@(JSBlock _)) =
59− (args : allArgs, body, f . JSFunction ident (map copyVar args))
60− collectAllFunctionArgs allArgs f (JSReturn (JSFunction ident args (JSBlock [body]))) =
61− collectAllFunctionArgs (args : allArgs) (\b -> f (JSReturn (JSFunction ident (map copyVar args) (JSBlock [b])))) body
62− collectAllFunctionArgs allArgs f (JSReturn (JSFunction ident args body@(JSBlock _))) =
63− (args : allArgs, body, f . JSReturn . JSFunction ident (map copyVar args))
56+ collectAllFunctionArgs allArgs f (JSFunction s1 ident args (JSBlock s2 (body@(JSReturn _ _):_))) =
57+ collectAllFunctionArgs (args : allArgs) (\b -> f (JSFunction s1 ident (map copyVar args) (JSBlock s2 [b]))) body
58+ collectAllFunctionArgs allArgs f (JSFunction ss ident args body@(JSBlock _ _)) =
59+ (args : allArgs, body, f . JSFunction ss ident (map copyVar args))
60+ collectAllFunctionArgs allArgs f (JSReturn s1 (JSFunction s2 ident args (JSBlock s3 [body]))) =
61+ collectAllFunctionArgs (args : allArgs) (\b -> f (JSReturn s1 (JSFunction s2 ident (map copyVar args) (JSBlock s3 [b])))) body
62+ collectAllFunctionArgs allArgs f (JSReturn s1 (JSFunction s2 ident args body@(JSBlock _ _))) =
63+ (args : allArgs, body, f . JSReturn s1 . JSFunction s2 ident (map copyVar args))
6464 collectAllFunctionArgs allArgs f body = (allArgs, body, f)
6565
6666 isTailCall :: String -> JS -> Bool
@@ -77,51 +77,53 @@ tco' = everywhereOnJS convert
7777 && numSelfCallWithFnArgs == 0
7878 where
7979 countSelfCalls :: JS -> Int
80− countSelfCalls (JSApp (JSVar ident') _) | ident == ident' = 1
80+ countSelfCalls (JSApp _ (JSVar _ ident') _) | ident == ident' = 1
8181 countSelfCalls _ = 0
82−
82+
8383 countSelfCallsInTailPosition :: JS -> Int
84− countSelfCallsInTailPosition (JSReturn ret) | isSelfCall ident ret = 1
84+ countSelfCallsInTailPosition (JSReturn _ ret) | isSelfCall ident ret = 1
8585 countSelfCallsInTailPosition _ = 0
86−
86+
8787 countSelfCallsUnderFunctions :: JS -> Int
88− countSelfCallsUnderFunctions (JSFunction _ _ js') = everythingOnJS (+) countSelfCalls js'
88+ countSelfCallsUnderFunctions (JSFunction _ _ _ js') = everythingOnJS (+) countSelfCalls js'
8989 countSelfCallsUnderFunctions _ = 0
90−
90+
9191 countSelfCallsWithFnArgs :: JS -> Int
9292 countSelfCallsWithFnArgs ret = if isSelfCallWithFnArgs ident ret [] then 1 else 0
9393
9494 toLoop :: String -> [String] -> JS -> JS
95− toLoop ident allArgs js = JSBlock $
96− map (\arg -> JSVariableIntroduction arg (Just (JSVar (copyVar arg)))) allArgs ++
97− [ JSLabel tcoLabel $ JSWhile (JSBooleanLiteral True) (JSBlock [ everywhereOnJS loopify js ]) ]
95+ toLoop ident allArgs js = JSBlock rootSS $
96+ map (\arg -> JSVariableIntroduction rootSS arg (Just (JSVar rootSS (copyVar arg)))) allArgs ++
97+ [ JSLabel rootSS tcoLabel $ JSWhile rootSS (JSBooleanLiteral rootSS True) (JSBlock rootSS [ everywhereOnJS loopify js ]) ]
9898 where
99+ rootSS = Nothing
100+
99101 loopify :: JS -> JS
100− loopify (JSReturn ret) | isSelfCall ident ret =
102+ loopify (JSReturn ss ret) | isSelfCall ident ret =
101103 let
102104 allArgumentValues = concat $ collectSelfCallArgs [] ret
103105 in
104− JSBlock $ zipWith (\val arg ->
105− JSVariableIntroduction (tcoVar arg) (Just val)) allArgumentValues allArgs
106+ JSBlock ss $ zipWith (\val arg ->
107+ JSVariableIntroduction ss (tcoVar arg) (Just val)) allArgumentValues allArgs
106108 ++ map (\arg ->
107− JSAssignment (JSVar arg) (JSVar (tcoVar arg))) allArgs
108− ++ [ JSContinue tcoLabel ]
109+ JSAssignment ss (JSVar ss arg) (JSVar ss (tcoVar arg))) allArgs
110+ ++ [ JSContinue ss tcoLabel ]
109111 loopify other = other
110112 collectSelfCallArgs :: [[JS]] -> JS -> [[JS]]
111− collectSelfCallArgs allArgumentValues (JSApp fn args') = collectSelfCallArgs (args' : allArgumentValues) fn
113+ collectSelfCallArgs allArgumentValues (JSApp _ fn args') = collectSelfCallArgs (args' : allArgumentValues) fn
112114 collectSelfCallArgs allArgumentValues _ = allArgumentValues
113115
114116 isSelfCall :: String -> JS -> Bool
115− isSelfCall ident (JSApp (JSVar ident') _) = ident == ident'
116− isSelfCall ident (JSApp fn _) = isSelfCall ident fn
117+ isSelfCall ident (JSApp _ (JSVar _ ident') _) = ident == ident'
118+ isSelfCall ident (JSApp _ fn _) = isSelfCall ident fn
117119 isSelfCall _ _ = False
118120
119121 isSelfCallWithFnArgs :: String -> JS -> [JS] -> Bool
120− isSelfCallWithFnArgs ident (JSVar ident') args | ident == ident' && any hasFunction args = True
121− isSelfCallWithFnArgs ident (JSApp fn args) acc = isSelfCallWithFnArgs ident fn (args ++ acc)
122+ isSelfCallWithFnArgs ident (JSVar _ ident') args | ident == ident' && any hasFunction args = True
123+ isSelfCallWithFnArgs ident (JSApp _ fn args) acc = isSelfCallWithFnArgs ident fn (args ++ acc)
122124 isSelfCallWithFnArgs _ _ _ = False
123−
124− hasFunction :: JS -> Bool
125+
126+ hasFunction :: JS -> Bool
125127 hasFunction = getAny . everythingOnJS mappend (Any . isFunction)
126128 where
127129 isFunction JSFunction{} = True
src/Language/PureScript/CodeGen/JS/Optimizer/Unused.hs+3−3
@@ -30,17 +30,17 @@ removeCodeAfterReturnStatements = everywhereOnJS (removeFromBlock go)
3030 go :: [JS] -> [JS]
3131 go jss | not (any isJSReturn jss) = jss
3232 | otherwise = let (body, ret : _) = break isJSReturn jss in body ++ [ret]
33− isJSReturn (JSReturn _) = True
33+ isJSReturn (JSReturn _ _) = True
3434 isJSReturn _ = False
3535
3636removeUnusedArg :: JS -> JS
3737removeUnusedArg = everywhereOnJS convert
3838 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
4040 convert js = js
4141
4242removeUndefinedApp :: JS -> JS
4343removeUndefinedApp = everywhereOnJS convert
4444 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 []
4646 convert js = js
src/Language/PureScript/CoreFn/Binders.hs+9−2
@@ -31,5 +31,12 @@ data Binder a
3131 -- |
3232 -- A binder which binds its input to an identifier
3333 --
34− | NamedBinder a Ident (Binder a)
35− deriving (Show, Read, Functor)
34+ | NamedBinder a Ident (Binder a) 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 @@
11module Language.PureScript.CoreFn.Desugar (moduleToCoreFn) where
22
3+import Prelude ()
4+import Prelude.Compat
5+
6+
37import Data.Function (on)
48import Data.List (sort, sortBy, nub)
59import Data.Maybe (mapMaybe)
@@ -30,38 +34,52 @@ moduleToCoreFn :: Environment -> A.Module -> Module Ann
3034moduleToCoreFn _ (A.Module _ _ _ _ Nothing) =
3135 internalError "Module exports were not elaborated before moduleToCoreFn"
3236moduleToCoreFn 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
3439 exps' = nub $ concatMap exportToCoreFn exps
3540 externs = nub $ mapMaybe externToCoreFn decls
3641 decls' = concatMap (declToCoreFn Nothing []) decls
37− in Module coms mn imports exps' externs decls'
42+ in Module coms mn imports' exps' externs decls'
3843
3944 where
4045
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+
4159 -- |
4260 -- Desugars member declarations from AST to CoreFn representation.
4361 --
4462 declToCoreFn :: Maybe SourceSpan -> [Comment] -> A.Declaration -> [Bind Ann]
4563 declToCoreFn ss com (A.DataDeclaration Newtype _ _ [(ctor, _)]) =
46− [NonRec (properToIdent ctor) $
64+ [NonRec (ssA ss) (properToIdent ctor) $
4765 Abs (ss, com, Nothing, Just IsNewtype) (Ident "x") (Var nullAnn $ Qualified Nothing (Ident "x"))]
4866 declToCoreFn _ _ d@(A.DataDeclaration Newtype _ _ _) =
4967 error $ "Found newtype with multiple constructors: " ++ show d
5068 declToCoreFn ss com (A.DataDeclaration Data tyName _ ctors) =
5169 flip map ctors $ \(ctor, _) ->
5270 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
5472 declToCoreFn ss _ (A.DataBindingGroupDeclaration ds) = concatMap (declToCoreFn ss []) ds
5573 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)]
5775 declToCoreFn ss com (A.FixityDeclaration _ name (Just alias)) =
5876 let meta = either getValueMeta (Just . getConstructorMeta) alias
5977 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')]
6179 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]
6381 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]
6583 declToCoreFn _ com (A.PositionedDeclaration ss com1 d) =
6684 declToCoreFn (Just ss) (com ++ com1) d
6785 declToCoreFn _ _ _ = []
@@ -203,35 +221,36 @@ moduleToCoreFn env (A.Module _ coms mn decls (Just exps)) =
203221-- ensure instances are imported from any module that is referenced by the
204222-- current module, not just from those that are imported explicitly (#667).
205223--
206−findQualModules :: [A.Declaration] -> [ModuleName]
224+findQualModules :: [A.Declaration] -> [(Ann, ModuleName)]
207225findQualModules decls =
208226 let (f, _, _, _, _) = everythingOnValues (++) fqDecls fqValues fqBinders (const []) (const [])
209227 in f `concatMap` decls
210228 where
211− fqDecls :: A.Declaration -> [ModuleName]
229+ fqDecls :: A.Declaration -> [(Ann, ModuleName)]
212230 fqDecls (A.TypeInstanceDeclaration _ _ q _ _) = getQual q
213231 fqDecls (A.FixityDeclaration _ _ (Just eq)) = either getQual getQual eq
214232 fqDecls _ = []
215233
216− fqValues :: A.Expr -> [ModuleName]
234+ fqValues :: A.Expr -> [(Ann, ModuleName)]
217235 fqValues (A.Var q) = getQual q
218236 fqValues (A.Constructor q) = getQual q
219237 fqValues _ = []
220238
221− fqBinders :: A.Binder -> [ModuleName]
239+ fqBinders :: A.Binder -> [(Ann, ModuleName)]
222240 fqBinders (A.ConstructorBinder q _) = getQual q
223241 fqBinders _ = []
224242
225− getQual :: Qualified a -> [ModuleName]
226− getQual (Qualified (Just mn) _) = [mn]
243+ getQual :: Qualified a -> [(Ann, ModuleName)]
244+ getQual (Qualified (Just mn) _) = [(nullAnn, mn)]
227245 getQual _ = []
228246
229247-- |
230248-- Desugars import declarations from AST to CoreFn representation.
231249--
232−importToCoreFn :: A.Declaration -> Maybe ModuleName
233−importToCoreFn (A.ImportDeclaration name _ _ _) = Just name
234−importToCoreFn (A.PositionedDeclaration _ _ d) = importToCoreFn d
250+importToCoreFn :: A.Declaration -> Maybe (Ann, ModuleName)
251+importToCoreFn (A.ImportDeclaration name _ _ _) = Just (nullAnn, name)
252+importToCoreFn (A.PositionedDeclaration ss _ d) =
253+ ((,) (Just ss, [], Nothing, Nothing) . snd) <$> importToCoreFn d
235254importToCoreFn _ = Nothing
236255
237256-- |
src/Language/PureScript/CoreFn/Expr.hs+3−5
@@ -60,12 +60,11 @@ data Bind a
6060 -- |
6161 -- Non-recursive binding for a single value
6262 --
63− = NonRec Ident (Expr a)
63+ = NonRec a Ident (Expr a)
6464 -- |
6565 -- Mutually recursive binding group for several values
6666 --
67− | Rec [(Ident, Expr a)]
68− deriving (Show, Read, Functor)
67+ | Rec [((a, Ident), Expr a)] deriving (Show, Read, Functor)
6968
7069-- |
7170-- A guard is just a boolean-valued expression that appears alongside a set of binders
@@ -84,8 +83,7 @@ data CaseAlternative a = CaseAlternative
8483 -- The result expression or a collect of guarded expressions
8584 --
8685 , caseAlternativeResult :: Either [(Guard a, Expr a)] (Expr a)
87− }
88− deriving (Show, Read)
86+ } deriving (Show, Read)
8987
9088instance Functor CaseAlternative where
9189
src/Language/PureScript/CoreFn/Meta.hs+2−4
@@ -24,8 +24,7 @@ data Meta
2424 -- |
2525 -- The contained reference is for a foreign member
2626 --
27− | IsForeign
28− deriving (Show, Read)
27+ | IsForeign deriving (Show, Read, Eq)
2928
3029-- |
3130-- Data constructor metadata
@@ -38,5 +37,4 @@ data ConstructorType
3837 -- |
3938 -- The constructor is for a type with multiple construcors
4039 --
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
2222data Module a = Module
2323 { moduleComments :: [Comment]
2424 , moduleName :: ModuleName
25− , moduleImports :: [ModuleName]
25+ , moduleImports :: [(a, ModuleName)]
2626 , moduleExports :: [Ident]
2727 , moduleForeign :: [ForeignDecl]
2828 , moduleDecls :: [Bind a]
src/Language/PureScript/CoreFn/Traversals.hs+2−2
@@ -26,7 +26,7 @@ everywhereOnValues :: (Bind a -> Bind a) ->
2626 (Bind a -> Bind a, Expr a -> Expr a, Binder a -> Binder a)
2727everywhereOnValues f g h = (f', g', h')
2828 where
29− f' (NonRec name e) = f (NonRec name (g' e))
29+ f' (NonRec a name e) = f (NonRec a name (g' e))
3030 f' (Rec es) = f (Rec (map (second g') es))
3131
3232 g' (Literal ann e) = g (Literal ann (handleLiteral g' e))
@@ -61,7 +61,7 @@ everythingOnValues :: (r -> r -> r) ->
6161 (Bind a -> r, Expr a -> r, Binder a -> r, CaseAlternative a -> r)
6262everythingOnValues (<>) f g h i = (f', g', h', i')
6363 where
64− f' b@(NonRec _ e) = f b <> g' e
64+ f' b@(NonRec _ _ e) = f b <> g' e
6565 f' b@(Rec es) = foldl (<>) (f b) (map (g' . snd) es)
6666
6767 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
155155--
156156findImport ::
157157 (Show name, Eq name, Applicative m, MonadReader P.ModuleName m) =>
158− [(P.Qualified name, P.ModuleName)] ->
158+ [P.ImportRecord name] ->
159159 (name, P.ModuleName) ->
160160 m (P.ModuleName, name)
161161findImport imps (name, orig) =
162162 let
163− matches (qual, mn) = P.disqualify qual == name && mn == orig
163+ matches (P.ImportRecord qual mn _) = P.disqualify qual == name && mn == orig
164164 matching = filter matches imps
165165 getQualified (P.Qualified mname _) = mname
166166 in
167− case mapMaybe (getQualified . fst) matching of
167+ case mapMaybe (getQualified . P.importName) matching of
168168 -- A value can occur more than once if it is imported twice (eg, if it is
169169 -- exported by A, re-exported from A by B, and C imports it from both A
170170 -- and B). In this case, we just take its first appearance.
src/Language/PureScript/Errors.hs+9
@@ -69,6 +69,7 @@ data SimpleErrorMessage
6969 | UnknownImportDataConstructor ModuleName (ProperName 'TypeName) (ProperName 'ConstructorName)
7070 | UnknownExportDataConstructor (ProperName 'TypeName) (ProperName 'ConstructorName)
7171 | ScopeConflict String [ModuleName]
72+ | ScopeShadowing String (Maybe ModuleName) [ModuleName]
7273 | ConflictingTypeDecls (ProperName 'TypeName)
7374 | ConflictingCtorDecls (ProperName 'ConstructorName)
7475 | TypeConflictsWithClass (ProperName 'TypeName)
@@ -248,6 +249,7 @@ errorCode em = case unwrapErrorMessage em of
248249 UnknownImportDataConstructor{} -> "UnknownImportDataConstructor"
249250 UnknownExportDataConstructor{} -> "UnknownExportDataConstructor"
250251 ScopeConflict{} -> "ScopeConflict"
252+ ScopeShadowing{} -> "ScopeShadowing"
251253 ConflictingTypeDecls{} -> "ConflictingTypeDecls"
252254 ConflictingCtorDecls{} -> "ConflictingCtorDecls"
253255 TypeConflictsWithClass{} -> "TypeConflictsWithClass"
@@ -604,6 +606,13 @@ prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap
604606 paras [ line $ "Conflicting definitions are in scope for " ++ nm ++ " from the following modules:"
605607 , indent $ paras $ map (line . runModuleName) ms
606608 ]
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+ ]
607616 renderSimpleErrorMessage (ConflictingTypeDecls nm) =
608617 line $ "Conflicting type declarations for " ++ runProperName nm
609618 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
1717import Data.Foldable (forM_)
1818import Data.List ((\\), find, intersect, nub)
1919import Data.Maybe (mapMaybe)
20+import Data.Monoid (Sum(..))
2021import qualified Data.Map as M
2122
2223import Language.PureScript.AST.Declarations
@@ -78,6 +79,8 @@ lintImports (Module _ _ mn mdecls mexports) env usedImps = do
7879
7980 let scope = maybe nullImports (\(_, imps, _) -> imps) (M.lookup mn env)
8081 usedImps' = foldr (elaborateUsed scope) usedImps exportedModules
82+ numImplicitImports = getSum $ foldMap (Sum . countImplicitImports) mdecls
83+ allowImplicit = numImplicitImports == 1
8184
8285 imps <- M.toAscList <$> findImports mdecls
8386
@@ -86,7 +89,7 @@ lintImports (Module _ _ mn mdecls mexports) env usedImps = do
8689 forM_ decls $ \(ss, declType, qualifierName) ->
8790 censor (onErrorMessages $ addModuleLocError ss) $ do
8891 let names = nub $ M.findWithDefault [] mni usedImps'
89− lintImportDecl env mni qualifierName names declType
92+ lintImportDecl env mni qualifierName names declType allowImplicit
9093
9194 forM_ (M.toAscList (byQual imps)) $ \(mnq, entries) -> do
9295 let mnis = nub $ map (\(_, _, mni) -> mni) entries
@@ -103,6 +106,11 @@ lintImports (Module _ _ mn mdecls mexports) env usedImps = do
103106
104107 where
105108
109+ countImplicitImports :: Declaration -> Int
110+ countImplicitImports (ImportDeclaration mn' Implicit _ _) | not (isPrim mn') = 1
111+ countImplicitImports (PositionedDeclaration _ _ d) = countImplicitImports d
112+ countImplicitImports _ = 0
113+
106114 -- Checks whether a module is the Prim module - used to suppress any checks
107115 -- made, as Prim is always implicitly imported.
108116 isPrim :: ModuleName -> Bool
@@ -148,13 +156,13 @@ lintImports (Module _ _ mn mdecls mexports) env usedImps = do
148156 extractByQual
149157 :: (Eq a)
150158 => ModuleName
151− -> M.Map (Qualified a) [(Qualified a, ModuleName)]
159+ -> M.Map (Qualified a) [ImportRecord a]
152160 -> (Qualified a -> Name)
153161 -> [(ModuleName, Name)]
154162 extractByQual k m toName = mapMaybe go (M.toList m)
155163 where
156164 go (q@(Qualified mnq _), is) | isUnqualified q || isQualifiedWith k q =
157− case fst (head is) of
165+ case importName (head is) of
158166 Qualified (Just mn') name -> Just (mn', toName $ Qualified mnq name)
159167 _ -> internalError "unqualified name in extractByQual"
160168 go _ = Nothing
@@ -167,11 +175,12 @@ lintImportDecl
167175 -> Maybe ModuleName
168176 -> [Name]
169177 -> ImportDeclarationType
178+ -> Bool
170179 -> m ()
171−lintImportDecl env mni qualifierName names declType =
180+lintImportDecl env mni qualifierName names declType allowImplicit =
172181 case declType of
173182 Implicit -> case qualifierName of
174− Nothing -> checkImplicit ImplicitImport
183+ Nothing -> unless allowImplicit (checkImplicit ImplicitImport)
175184 Just q ->
176185 let usedModuleNames = mapMaybe extractQualName names
177186 in unless (q `elem` usedModuleNames) unused
src/Language/PureScript/Make.hs+41−6
@@ -31,7 +31,7 @@ import Control.Monad.Writer.Class (MonadWriter(..))
3131import Control.Monad.Trans.Class (MonadTrans(..))
3232import Control.Monad.Trans.Except
3333import Control.Monad.IO.Class
34−import Control.Monad.Reader (MonadReader(..), ReaderT(..))
34+import Control.Monad.Reader (MonadReader(..), ReaderT(..), asks)
3535import Control.Monad.Logger
3636import Control.Monad.Supply
3737import Control.Monad.Base (MonadBase(..))
@@ -52,9 +52,12 @@ import qualified Data.ByteString.UTF8 as BU8
5252import qualified Data.Set as S
5353import qualified Data.Map as M
5454
55+import SourceMap.Types
56+import SourceMap
57+
5558import System.Directory
56− (doesFileExist, getModificationTime, createDirectoryIfMissing)
57−import System.FilePath ((</>), takeDirectory)
59+ (doesFileExist, getModificationTime, createDirectoryIfMissing, getCurrentDirectory)
60+import System.FilePath ((</>), takeDirectory, makeRelative, splitPath, normalise)
5861import System.IO.Error (tryIOError)
5962import System.IO.UTF8 (readUTF8File, writeUTF8File)
6063
@@ -68,6 +71,7 @@ import Language.PureScript.ModuleDependencies
6871import Language.PureScript.Names
6972import Language.PureScript.Options
7073import Language.PureScript.Pretty
74+import Language.PureScript.Pretty.Common(SMap(..))
7175import Language.PureScript.Renamer
7276import Language.PureScript.Sugar
7377import Language.PureScript.TypeChecker
@@ -324,20 +328,51 @@ buildMakeActions outputDir filePathMap foreigns usePrefix =
324328 | not $ requiresForeign m -> do
325329 tell $ errorMessage $ UnnecessaryFFIModule mn path
326330 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"]
328332 Nothing | requiresForeign m -> throwError . errorMessage $ MissingFFIModule mn
329333 | 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, [])
331338 let filePath = runModuleName mn
332339 jsFile = outputDir </> filePath </> "index.js"
340+ mapFile = outputDir </> filePath </> "index.js.map"
333341 externsFile = outputDir </> filePath </> "externs.json"
334342 foreignFile = outputDir </> filePath </> "foreign.js"
335343 prefix = ["Generated by psc version " ++ showVersion Paths.version | usePrefix]
336344 js = unlines $ map ("// " ++) prefix ++ [pjs]
345+ mapRef = if sourceMaps then "//# sourceMappingURL=index.js.map\n" else ""
337346 lift $ do
338− writeTextFile jsFile (fromString js)
347+ writeTextFile jsFile (fromString $ js ++ mapRef)
339348 for_ (mn `M.lookup` foreigns) (readTextFile >=> writeTextFile foreignFile)
340349 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 }
341376
342377 requiresForeign :: CF.Module a -> Bool
343378 requiresForeign = not . null . CF.moduleForeign
src/Language/PureScript/Options.hs+4−1
@@ -41,9 +41,12 @@ data Options = Options {
4141 -- |
4242 -- The path to prepend to require statements
4343 , optionsRequirePath :: Maybe FilePath
44+ -- |
45+ -- Generate soure maps
46+ , optionsSourceMaps :: Bool
4447 } deriving Show
4548
4649-- |
4750-- Default make options
4851defaultOptions :: 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
2727import Language.PureScript.Pretty.Values as P
2828import Language.PureScript.Pretty.Types as P
2929import Language.PureScript.Pretty.JS as P
30−
31−
32−
src/Language/PureScript/Pretty/Common.hs+96−9
@@ -13,12 +13,18 @@
1313--
1414-----------------------------------------------------------------------------
1515
16+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
17+
1618module Language.PureScript.Pretty.Common where
1719
18−import Control.Monad.State
19−import Data.List (intercalate)
20+import Prelude ()
21+import Prelude.Compat
22+
23+import Control.Monad.State (StateT, modify, get)
24+import Data.List (elemIndices, intersperse)
2025
2126import Language.PureScript.Parser.Lexer (reservedPsNames, isSymbolChar)
27+import Language.PureScript.AST (SourcePos(..), SourceSpan(..))
2228
2329import Text.PrettyPrint.Boxes
2430
@@ -26,9 +32,90 @@ import Text.PrettyPrint.Boxes
2632-- Wrap a string in parentheses
2733--
2834parens :: 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 }
30116
31−newtype PrinterState = PrinterState { indent :: Int } deriving (Show, Read, Eq, Ord)
117+emptyPrinterState :: PrinterState
118+emptyPrinterState = PrinterState { indent = 0 }
32119
33120-- |
34121-- Number of characters per identation level
@@ -39,7 +126,7 @@ blockIndent = 4
39126-- |
40127-- Pretty print with a new indentation level
41128--
42−withIndent :: StateT PrinterState Maybe String -> StateT PrinterState Maybe String
129+withIndent :: (Emit gen) => StateT PrinterState Maybe gen -> StateT PrinterState Maybe gen
43130withIndent action = do
44131 modify $ \st -> st { indent = indent st + blockIndent }
45132 result <- action
@@ -49,19 +136,19 @@ withIndent action = do
49136-- |
50137-- Get the current indentation level
51138--
52−currentIndent :: StateT PrinterState Maybe String
139+currentIndent :: (Emit gen) => StateT PrinterState Maybe gen
53140currentIndent = do
54141 current <- get
55− return $ replicate (indent current) ' '
142+ return $ emit $ replicate (indent current) ' '
56143
57144-- |
58145-- Print many lines
59146--
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
61148prettyPrintMany f xs = do
62149 ss <- mapM f xs
63150 indentString <- currentIndent
64− return $ intercalate "\n" $ map (indentString ++) ss
151+ return $ intercalate (emit "\n") $ map (\s -> mappend indentString s) ss
65152
66153-- |
67154-- Prints an object key, escaping reserved names.
src/Language/PureScript/Pretty/JS.hs+118−105
@@ -14,13 +14,12 @@
1414-----------------------------------------------------------------------------
1515
1616module Language.PureScript.Pretty.JS (
17− prettyPrintJS
17+ prettyPrintJS, prettyPrintJSWithSourceMaps
1818) where
1919
2020import Prelude ()
2121import Prelude.Compat
2222
23−import Data.List hiding (concat, concatMap)
2423import Data.Maybe (fromMaybe)
2524
2625import Control.Arrow ((<+>))
@@ -34,103 +33,110 @@ import Language.PureScript.CodeGen.JS.Common
3433import Language.PureScript.Pretty.Common
3534import Language.PureScript.Comments
3635
36+
37+import Language.PureScript.AST (SourceSpan(..))
38+
3739import Numeric
3840
39−literals :: Pattern PrinterState JS String
40−literals = mkPattern' match
41+import Data.Monoid
42+
43+literals :: (Emit gen) => Pattern PrinterState JS gen
44+literals = mkPattern' match'
4145 where
42− match :: JS -> StateT PrinterState Maybe String
43− match (JSNumericLiteral n) = return $ either show show n
44− match (JSStringLiteral s) = return $ string s
45− match (JSBooleanLiteral True) = return "true"
46− match (JSBooleanLiteral False) = return "false"
47− match (JSArrayLiteral xs) = concat <$> sequence
48− [ return "[ "
49− , intercalate ", " <$> forM xs prettyPrintJS'
50− , return " ]"
46+ match' :: (Emit gen) => JS -> StateT PrinterState Maybe gen
47+ match' js = (addMapping' (getSourceSpan js) <>) <$> match js
48+
49+ match :: (Emit gen) => JS -> StateT PrinterState Maybe gen
50+ match (JSNumericLiteral _ n) = return $ emit $ either show show n
51+ match (JSStringLiteral _ s) = return $ string s
52+ match (JSBooleanLiteral _ True) = return $ emit "true"
53+ match (JSBooleanLiteral _ False) = return $ emit "false"
54+ match (JSArrayLiteral _ xs) = mconcat <$> sequence
55+ [ return $ emit "[ "
56+ , intercalate (emit ", ") <$> forM xs prettyPrintJS'
57+ , return $ emit " ]"
5158 ]
52− match (JSObjectLiteral []) = return "{}"
53− match (JSObjectLiteral ps) = concat <$> sequence
54− [ return "{\n"
59+ match (JSObjectLiteral _ []) = return $ emit "{}"
60+ match (JSObjectLiteral _ ps) = mconcat <$> sequence
61+ [ return $ emit "{\n"
5562 , 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
5764 indentString <- currentIndent
58− return $ intercalate ", \n" $ map (indentString ++) jss
59− , return "\n"
65+ return $ intercalate (emit ", \n") $ map (indentString <>) jss
66+ , return $ emit "\n"
6067 , currentIndent
61− , return "}"
68+ , return $ emit "}"
6269 ]
6370 where
64− objectPropertyToString :: String -> String
65− objectPropertyToString s | identNeedsEscaping s = show s
66− | otherwise = s
67− match (JSBlock sts) = concat <$> sequence
68− [ return "{\n"
71+ objectPropertyToString :: (Emit gen) => String -> gen
72+ objectPropertyToString s | identNeedsEscaping s = emit $ show s
73+ | otherwise = emit s
74+ match (JSBlock _ sts) = mconcat <$> sequence
75+ [ return $ emit "{\n"
6976 , withIndent $ prettyStatements sts
70− , return "\n"
77+ , return $ emit "\n"
7178 , currentIndent
72− , return "}"
79+ , return $ emit "}"
7380 ]
74− match (JSVar ident) = return ident
75− match (JSVariableIntroduction ident value) = concat <$> sequence
76− [ return "var "
77− , return ident
78− , maybe (return "") (fmap (" = " ++) . prettyPrintJS') value
81+ match (JSVar _ ident) = return $ emit ident
82+ match (JSVariableIntroduction _ ident value) = mconcat <$> sequence
83+ [ return $ emit $ "var " ++ ident
84+ , maybe (return mempty) (fmap (emit " = " <>) . prettyPrintJS') value
7985 ]
80− match (JSAssignment target value) = concat <$> sequence
86+ match (JSAssignment _ target value) = mconcat <$> sequence
8187 [ prettyPrintJS' target
82− , return " = "
88+ , return $ emit " = "
8389 , prettyPrintJS' value
8490 ]
85− match (JSWhile cond sts) = concat <$> sequence
86− [ return "while ("
91+ match (JSWhile _ cond sts) = mconcat <$> sequence
92+ [ return $ emit "while ("
8793 , prettyPrintJS' cond
88− , return ") "
94+ , return $ emit ") "
8995 , prettyPrintJS' sts
9096 ]
91− match (JSFor ident start end sts) = concat <$> sequence
92− [ return $ "for (var " ++ ident ++ " = "
97+ match (JSFor _ ident start end sts) = mconcat <$> sequence
98+ [ return $ emit $ "for (var " ++ ident ++ " = "
9399 , prettyPrintJS' start
94− , return $ "; " ++ ident ++ " < "
100+ , return $ emit $ "; " ++ ident ++ " < "
95101 , prettyPrintJS' end
96− , return $ "; " ++ ident ++ "++) "
102+ , return $ emit $ "; " ++ ident ++ "++) "
97103 , prettyPrintJS' sts
98104 ]
99− match (JSForIn ident obj sts) = concat <$> sequence
100− [ return $ "for (var " ++ ident ++ " in "
105+ match (JSForIn _ ident obj sts) = mconcat <$> sequence
106+ [ return $ emit $ "for (var " ++ ident ++ " in "
101107 , prettyPrintJS' obj
102− , return ") "
108+ , return $ emit ") "
103109 , prettyPrintJS' sts
104110 ]
105− match (JSIfElse cond thens elses) = concat <$> sequence
106− [ return "if ("
111+ match (JSIfElse _ cond thens elses) = mconcat <$> sequence
112+ [ return $ emit "if ("
107113 , prettyPrintJS' cond
108− , return ") "
114+ , return $ emit ") "
109115 , prettyPrintJS' thens
110− , maybe (return "") (fmap (" else " ++) . prettyPrintJS') elses
116+ , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintJS') elses
111117 ]
112− match (JSReturn value) = concat <$> sequence
113− [ return "return "
118+ match (JSReturn _ value) = mconcat <$> sequence
119+ [ return $ emit "return "
114120 , prettyPrintJS' value
115121 ]
116− match (JSThrow value) = concat <$> sequence
117− [ return "throw "
122+ match (JSThrow _ value) = mconcat <$> sequence
123+ [ return $ emit "throw "
118124 , prettyPrintJS' value
119125 ]
120− match (JSBreak lbl) = return $ "break " ++ lbl
121− match (JSContinue lbl) = return $ "continue " ++ lbl
122− match (JSLabel lbl js) = concat <$> sequence
123− [ return $ lbl ++ ": "
126+ match (JSBreak _ lbl) = return $ emit $ "break " ++ lbl
127+ match (JSContinue _ lbl) = return $ emit $ "continue " ++ lbl
128+ match (JSLabel _ lbl js) = mconcat <$> sequence
129+ [ return $ emit $ lbl ++ ": "
124130 , prettyPrintJS' js
125131 ]
126− match (JSComment com js) = fmap concat $ sequence $
127− [ return "\n"
132+ match (JSComment _ com js) = fmap mconcat $ sequence $
133+ [ return $ emit "\n"
128134 , currentIndent
129− , return "/**\n"
135+ , return $ emit "/**\n"
130136 ] ++
131137 map asLine (concatMap commentLines com) ++
132138 [ currentIndent
133− , return " */\n"
139+ , return $ emit " */\n"
134140 , currentIndent
135141 , prettyPrintJS' js
136142 ]
@@ -139,21 +145,21 @@ literals = mkPattern' match
139145 commentLines (LineComment s) = [s]
140146 commentLines (BlockComment s) = lines s
141147
142− asLine :: String -> StateT PrinterState Maybe String
148+ asLine :: (Emit gen) => String -> StateT PrinterState Maybe gen
143149 asLine s = do
144150 i <- currentIndent
145− return $ i ++ " * " ++ removeComments s ++ "\n"
151+ return $ i <> emit " * " <> (emit . removeComments) s <> emit "\n"
146152
147153 removeComments :: String -> String
148154 removeComments ('*' : '/' : s) = removeComments s
149155 removeComments (c : s) = c : removeComments s
150156
151157 removeComments [] = []
152− match (JSRaw js) = return js
158+ match (JSRaw _ js) = return $ emit js
153159 match _ = mzero
154160
155−string :: String -> String
156−string s = '"' : concatMap encodeChar s ++ "\""
161+string :: (Emit gen) => String -> gen
162+string s = emit $ '"' : concatMap encodeChar s ++ "\""
157163 where
158164 encodeChar :: Char -> String
159165 encodeChar '\b' = "\\b"
@@ -175,114 +181,121 @@ string s = '"' : concatMap encodeChar s ++ "\""
175181 encodeChar c | fromEnum c > 0x7E || fromEnum c < 0x20 = "\\x" ++ showHex (fromEnum c) ""
176182 encodeChar c = [c]
177183
178−conditional :: Pattern PrinterState JS ((JS, JS), JS)
184+conditional :: Pattern PrinterState JS ((Maybe SourceSpan, JS, JS), JS)
179185conditional = mkPattern match
180186 where
181− match (JSConditional cond th el) = Just ((th, el), cond)
187+ match (JSConditional ss cond th el) = Just ((ss, th, el), cond)
182188 match _ = Nothing
183189
184−accessor :: Pattern PrinterState JS (String, JS)
190+accessor :: (Emit gen) => Pattern PrinterState JS (gen, JS)
185191accessor = mkPattern match
186192 where
187− match (JSAccessor prop val) = Just (prop, val)
193+ match (JSAccessor _ prop val) = Just (emit prop, val)
188194 match _ = Nothing
189195
190−indexer :: Pattern PrinterState JS (String, JS)
196+indexer :: (Emit gen) => Pattern PrinterState JS (gen, JS)
191197indexer = mkPattern' match
192198 where
193− match (JSIndexer index val) = (,) <$> prettyPrintJS' index <*> pure val
199+ match (JSIndexer _ index val) = (,) <$> prettyPrintJS' index <*> pure val
200+
194201 match _ = mzero
195202
196−lam :: Pattern PrinterState JS ((Maybe String, [String]), JS)
203+lam :: Pattern PrinterState JS ((Maybe String, [String], Maybe SourceSpan), JS)
197204lam = mkPattern match
198205 where
199− match (JSFunction name args ret) = Just ((name, args), ret)
206+ match (JSFunction ss name args ret) = Just ((name, args, ss), ret)
200207 match _ = Nothing
201208
202−app :: Pattern PrinterState JS (String, JS)
209+app :: (Emit gen) => Pattern PrinterState JS (gen, JS)
203210app = mkPattern' match
204211 where
205− match (JSApp val args) = do
212+ match (JSApp _ val args) = do
206213 jss <- traverse prettyPrintJS' args
207− return (intercalate ", " jss, val)
214+ return (intercalate (emit ", ") jss, val)
208215 match _ = mzero
209216
210217typeOf :: Pattern PrinterState JS ((), JS)
211218typeOf = mkPattern match
212219 where
213− match (JSTypeOf val) = Just ((), val)
220+ match (JSTypeOf _ val) = Just ((), val)
214221 match _ = Nothing
215222
216223instanceOf :: Pattern PrinterState JS (JS, JS)
217224instanceOf = mkPattern match
218225 where
219− match (JSInstanceOf val ty) = Just (val, ty)
226+ match (JSInstanceOf _ val ty) = Just (val, ty)
220227 match _ = Nothing
221228
222−unary' :: UnaryOperator -> (JS -> String) -> Operator PrinterState JS String
223−unary' op mkStr = Wrap match (++)
229+unary' :: (Emit gen) => UnaryOperator -> (JS -> String) -> Operator PrinterState JS gen
230+unary' op mkStr = Wrap match (<>)
224231 where
225− match :: Pattern PrinterState JS (String, JS)
232+ match :: (Emit gen) => Pattern PrinterState JS (gen, JS)
226233 match = mkPattern match'
227234 where
228− match' (JSUnary op' val) | op' == op = Just (mkStr val, val)
235+ match' (JSUnary _ op' val) | op' == op = Just (emit $ mkStr val, val)
229236 match' _ = Nothing
230237
231−unary :: UnaryOperator -> String -> Operator PrinterState JS String
238+unary :: (Emit gen) => UnaryOperator -> String -> Operator PrinterState JS gen
232239unary op str = unary' op (const str)
233240
234−negateOperator :: Operator PrinterState JS String
241+negateOperator :: (Emit gen) => Operator PrinterState JS gen
235242negateOperator = unary' Negate (\v -> if isNegate v then "- " else "-")
236243 where
237− isNegate (JSUnary Negate _) = True
244+ isNegate (JSUnary _ Negate _) = True
238245 isNegate _ = False
239246
240−binary :: BinaryOperator -> String -> Operator PrinterState JS String
241−binary op str = AssocL match (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)
247+binary :: (Emit gen) => BinaryOperator -> String -> Operator PrinterState JS gen
248+binary op str = AssocL match (\v1 v2 -> v1 <> emit (" " ++ str ++ " ") <> v2)
242249 where
243250 match :: Pattern PrinterState JS (JS, JS)
244251 match = mkPattern match'
245252 where
246− match' (JSBinary op' v1 v2) | op' == op = Just (v1, v2)
253+ match' (JSBinary _ op' v1 v2) | op' == op = Just (v1, v2)
247254 match' _ = Nothing
248255
249−prettyStatements :: [JS] -> StateT PrinterState Maybe String
256+prettyStatements :: (Emit gen) => [JS] -> StateT PrinterState Maybe gen
250257prettyStatements sts = do
251258 jss <- forM sts prettyPrintJS'
252259 indentString <- currentIndent
253− return $ intercalate "\n" $ map ((++ ";") . (indentString ++)) jss
260+ return $ intercalate (emit "\n") $ map ((<> emit ";") . (indentString <>)) jss
254261
255262-- |
256263-- Generate a pretty-printed string representing a Javascript expression
257264--
258−prettyPrintJS1 :: JS -> String
265+prettyPrintJS1 :: (Emit gen) => JS -> gen
259266prettyPrintJS1 = fromMaybe (internalError "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyPrintJS'
260267
261268-- |
262269-- Generate a pretty-printed string representing a collection of Javascript expressions at the same indentation level
263270--
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+
264276prettyPrintJS :: [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
266278
267279-- |
268280-- Generate an indented, pretty-printed string representing a Javascript expression
269281--
270−prettyPrintJS' :: JS -> StateT PrinterState Maybe String
282+prettyPrintJS' :: (Emit gen) => JS -> StateT PrinterState Maybe gen
271283prettyPrintJS' = A.runKleisli $ runPattern matchValue
272284 where
273− matchValue :: Pattern PrinterState JS String
274− matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)
275− operators :: OperatorTable PrinterState JS String
285+ matchValue :: (Emit gen) => Pattern PrinterState JS gen
286+ matchValue = buildPrettyPrinter operators (literals <+> fmap parensPos matchValue)
287+ operators :: (Emit gen) => OperatorTable PrinterState JS gen
276288 operators =
277− OperatorTable [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ]
278− , [ Wrap indexer $ \index val -> val ++ "[" ++ index ++ "]" ]
279− , [ Wrap app $ \args val -> val ++ "(" ++ args ++ ")" ]
289+ OperatorTable [ [ Wrap accessor $ \prop val -> val <> emit "." <> prop ]
290+ , [ Wrap indexer $ \index val -> val <> emit "[" <> index <> emit "]" ]
291+ , [ Wrap app $ \args val -> val <> emit "(" <> args <> emit ")" ]
280292 , [ unary JSNew "new " ]
281− , [ Wrap lam $ \(name, args) ret -> "function "
293+ , [ Wrap lam $ \(name, args, ss) ret -> addMapping' ss <>
294+ emit ("function "
282295 ++ fromMaybe "" name
283− ++ "(" ++ intercalate ", " args ++ ") "
284− ++ ret ]
285− , [ Wrap typeOf $ \_ s -> "typeof " ++ s ]
296+ ++ "(" ++ intercalate ", " args ++ ") ")
297+ <> ret ]
298+ , [ Wrap typeOf $ \_ s -> emit "typeof " <> s ]
286299 , [ unary Not "!"
287300 , unary BitwiseNot "~"
288301 , unary Positive "+"
@@ -299,7 +312,7 @@ prettyPrintJS' = A.runKleisli $ runPattern matchValue
299312 , binary LessThanOrEqualTo "<="
300313 , binary GreaterThan ">"
301314 , binary GreaterThanOrEqualTo ">="
302− , AssocR instanceOf $ \v1 v2 -> v1 ++ " instanceof " ++ v2 ]
315+ , AssocR instanceOf $ \v1 v2 -> v1 <> emit " instanceof " <> v2 ]
303316 , [ binary EqualTo "==="
304317 , binary NotEqualTo "!==" ]
305318 , [ binary BitwiseAnd "&" ]
@@ -307,5 +320,5 @@ prettyPrintJS' = A.runKleisli $ runPattern matchValue
307320 , [ binary BitwiseOr "|" ]
308321 , [ binary And "&&" ]
309322 , [ 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 ]
311324 ]
src/Language/PureScript/Pretty/Values.hs−2
@@ -19,8 +19,6 @@ module Language.PureScript.Pretty.Values (
1919 prettyPrintBinderAtom
2020) where
2121
22−import Data.List (intercalate)
23−
2422import Control.Arrow (second)
2523
2624import Language.PureScript.Crash
src/Language/PureScript/Renamer.hs+9−9
@@ -105,8 +105,8 @@ lookupIdent name = do
105105findDeclIdents :: [Bind Ann] -> [Ident]
106106findDeclIdents = concatMap go
107107 where
108− go (NonRec ident _) = [ident]
109− go (Rec ds) = map fst ds
108+ go (NonRec _ ident _) = [ident]
109+ go (Rec ds) = map (snd . fst) ds
110110
111111-- |
112112-- Renames within each declaration in a module.
@@ -128,19 +128,19 @@ renameInModules = map go
128128-- another in the current scope.
129129--
130130renameInDecl :: Bool -> Bind Ann -> Rename (Bind Ann)
131−renameInDecl isTopLevel (NonRec name val) = do
131+renameInDecl isTopLevel (NonRec a name val) = do
132132 name' <- if isTopLevel then return name else updateScope name
133− NonRec name' <$> renameInValue val
133+ NonRec a name' <$> renameInValue val
134134renameInDecl isTopLevel (Rec ds) = do
135135 ds' <- traverse updateNames ds
136136 Rec <$> traverse updateValues ds'
137137 where
138− updateNames :: (Ident, Expr Ann) -> Rename (Ident, Expr Ann)
139− updateNames (name, val) = do
138+ updateNames :: ((Ann, Ident), Expr Ann) -> Rename ((Ann, Ident), Expr Ann)
139+ updateNames ((a, name), val) = do
140140 name' <- if isTopLevel then return name else updateScope name
141− return (name', val)
142− updateValues :: (Ident, Expr Ann) -> Rename (Ident, Expr Ann)
143− updateValues (name, val) = (,) name <$> renameInValue val
141+ return ((a, name'), val)
142+ updateValues :: ((Ann, Ident), Expr Ann) -> Rename ((Ann, Ident), Expr Ann)
143+ updateValues (aname, val) = (,) aname <$> renameInValue val
144144
145145-- |
146146-- Renames within a value.
src/Language/PureScript/Sugar/Names.hs+5−4
@@ -7,6 +7,8 @@ module Language.PureScript.Sugar.Names
77 ( desugarImports
88 , desugarImportsWithEnv
99 , Env
10+ , ImportRecord(..)
11+ , ImportProvenance(..)
1012 , Imports(..)
1113 , Exports(..)
1214 ) where
@@ -67,7 +69,7 @@ desugarImportsWithEnv externs modules = do
6769 let members = Exports{..}
6870 ss = internalModuleSourceSpan "<Externs>"
6971 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)])
7173 imps <- foldM (resolveModuleImport env') nullImports (map fromEFImport efImports)
7274 exps <- resolveExports env' efModuleName imps members efExports
7375 return $ M.insert efModuleName (ss, imps, exps) env
@@ -284,7 +286,7 @@ renameInModule env imports (Module ss coms mn decls exps) =
284286 update
285287 :: (Ord a, Show a)
286288 => (Qualified a -> SimpleErrorMessage)
287− -> M.Map (Qualified a) [(Qualified a, ModuleName)]
289+ -> M.Map (Qualified a) [ImportRecord a]
288290 -> (Exports -> a -> Maybe (Qualified a))
289291 -> (Qualified a -> Name)
290292 -> (a -> String)
@@ -300,8 +302,7 @@ renameInModule env imports (Module ss coms mn decls exps) =
300302 -- re-exports. If there are multiple options for the name to resolve to
301303 -- in scope, we throw an error.
302304 (Just options, _) -> do
303− checkImportConflicts render options
304− let (Qualified (Just mnNew) _, mnOrig) = head options
305+ (mnNew, mnOrig) <- checkImportConflicts mn render options
305306 modify $ \result -> M.insert mnNew (maybe [toName qname] (toName qname :) (mnNew `M.lookup` result)) result
306307 return $ Qualified (Just mnOrig) name
307308
src/Language/PureScript/Sugar/Names/Env.hs+55−15
@@ -2,7 +2,9 @@
22{-# LANGUAGE ScopedTypeVariables #-}
33
44module Language.PureScript.Sugar.Names.Env
5− ( Imports(..)
5+ ( ImportRecord(..)
6+ , ImportProvenance(..)
7+ , Imports(..)
68 , nullImports
79 , Exports(..)
810 , nullExports
@@ -19,13 +21,14 @@ module Language.PureScript.Sugar.Names.Env
1921 ) where
2022
2123import Data.Function (on)
22−import Data.List (groupBy, sortBy, nub)
24+import Data.List (groupBy, sortBy, nub, delete)
2325import Data.Maybe (fromJust)
2426import qualified Data.Map as M
2527import qualified Data.Set as S
2628
2729import Control.Monad
2830import Control.Monad.Error.Class (MonadError(..))
31+import Control.Monad.Writer.Class (MonadWriter(..))
2932
3033import Language.PureScript.AST
3134import Language.PureScript.Crash
@@ -33,6 +36,30 @@ import Language.PureScript.Names
3336import Language.PureScript.Environment
3437import Language.PureScript.Errors
3538
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+
3663-- |
3764-- The imported declarations for a module, including the module's own members.
3865--
@@ -41,19 +68,19 @@ data Imports = Imports
4168 -- |
4269 -- Local names for types within a module mapped to to their qualified names
4370 --
44− importedTypes :: M.Map (Qualified (ProperName 'TypeName)) [(Qualified (ProperName 'TypeName), ModuleName)]
71+ importedTypes :: M.Map (Qualified (ProperName 'TypeName)) [ImportRecord (ProperName 'TypeName)]
4572 -- |
4673 -- Local names for data constructors within a module mapped to to their qualified names
4774 --
48− , importedDataConstructors :: M.Map (Qualified (ProperName 'ConstructorName)) [(Qualified (ProperName 'ConstructorName), ModuleName)]
75+ , importedDataConstructors :: M.Map (Qualified (ProperName 'ConstructorName)) [ImportRecord (ProperName 'ConstructorName)]
4976 -- |
5077 -- Local names for classes within a module mapped to to their qualified names
5178 --
52− , importedTypeClasses :: M.Map (Qualified (ProperName 'ClassName)) [(Qualified (ProperName 'ClassName), ModuleName)]
79+ , importedTypeClasses :: M.Map (Qualified (ProperName 'ClassName)) [ImportRecord (ProperName 'ClassName)]
5380 -- |
5481 -- Local names for values within a module mapped to to their qualified names
5582 --
56− , importedValues :: M.Map (Qualified Ident) [(Qualified Ident, ModuleName)]
83+ , importedValues :: M.Map (Qualified Ident) [ImportRecord Ident]
5784 -- |
5885 -- The modules that have been imported into the current scope.
5986 --
@@ -202,16 +229,29 @@ getExports env mn = maybe (throwError . errorMessage $ UnknownModule mn) (return
202229--
203230checkImportConflicts
204231 :: forall m a
205− . (MonadError MultipleErrors m, Ord a)
206− => (a -> String)
207− -> [(Qualified a, ModuleName)]
208− -> m ()
209−checkImportConflicts render xs =
210− let byOrig = groupBy ((==) `on` snd) . sortBy (compare `on` snd) $ xs
232+ . (Show a, MonadError MultipleErrors m, MonadWriter MultipleErrors m, Ord a)
233+ => ModuleName
234+ -> (a -> String)
235+ -> [ImportRecord a]
236+ -> m (ModuleName, ModuleName)
237+checkImportConflicts currentModule render xs =
238+ let
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
211244 in
212− if length byOrig > 1
213− then throwError . errorMessage $ ScopeConflict (render' (fst . head $ xs)) (map (getQual . fst . head) byOrig)
214− else return ()
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)
251+ _ -> throwError . errorMessage $ ScopeConflict name conflictModules
252+ else
253+ let ImportRecord (Qualified (Just mnNew) _) mnOrig _ = head byOrig
254+ in return (mnNew, mnOrig)
215255 where
216256 getQual :: Qualified a -> ModuleName
217257 getQual (Qualified (Just mn) _) = mn
src/Language/PureScript/Sugar/Names/Exports.hs+5−5
@@ -110,17 +110,17 @@ resolveExports env mn imps exps refs =
110110 -- Extracts a list of values for a module based on a lookup table. If the
111111 -- boolean is true the values are filtered by the qualification
112112 extract
113− :: (Ord a)
113+ :: (Show a, Ord a)
114114 => Bool
115115 -> ModuleName
116116 -> (a -> String)
117− -> M.Map (Qualified a) [(Qualified a, ModuleName)]
117+ -> M.Map (Qualified a) [ImportRecord a]
118118 -> 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
120120 where
121121 go = filterM $ \(name', options) -> do
122− let isMatch = if useQual then eqQual name name' else any (eqQual name . fst) options
123− when (isMatch && length options > 1) $ checkImportConflicts render options
122+ let isMatch = if useQual then eqQual name name' else any (eqQual name . importName) options
123+ when (isMatch && length options > 1) $ void $ checkImportConflicts mn render options
124124 return isMatch
125125
126126 -- 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) =
9999
100100 return ()
101101
102− let scope = M.insert currentModule [(Nothing, Implicit, Nothing)] imports
102+ let imports' = M.map (map (\(ss', dt, mmn) -> (ss', Just dt, mmn))) imports
103+ scope = M.insert currentModule [(Nothing, Nothing, Nothing)] imports'
103104 resolved <- foldM (resolveModuleImport env) nullImports (M.toList scope)
104105 return (Module ss coms currentModule decls' exps, resolved)
105106
@@ -162,11 +163,13 @@ resolveModuleImport
162163 . (Applicative m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
163164 => Env
164165 -> Imports
165− -> (ModuleName, [(Maybe SourceSpan, ImportDeclarationType, Maybe ModuleName)])
166+ -> (ModuleName, [(Maybe SourceSpan, Maybe ImportDeclarationType, Maybe ModuleName)])
166167 -> m Imports
167168resolveModuleImport env ie (mn, imps) = foldM go ie imps
168169 where
169− go :: Imports -> (Maybe SourceSpan, ImportDeclarationType, Maybe ModuleName) -> m Imports
170+ go :: Imports
171+ -> (Maybe SourceSpan, Maybe ImportDeclarationType, Maybe ModuleName)
172+ -> m Imports
170173 go ie' (pos, typ, impQual) = do
171174 modExports <- positioned $ maybe (throwError . errorMessage $ UnknownModule mn) (return . envModuleExports) $ mn `M.lookup` env
172175 let virtualModules = importedVirtualModules ie'
@@ -189,15 +192,16 @@ resolveImport
189192 -> Exports
190193 -> Imports
191194 -> Maybe ModuleName
192− -> ImportDeclarationType
195+ -> Maybe ImportDeclarationType
193196 -> m Imports
194197resolveImport importModule exps imps impQual = resolveByType
195198 where
196199
197− resolveByType :: ImportDeclarationType -> m Imports
198− resolveByType Implicit = importAll importExplicit
199− resolveByType (Explicit refs) = checkRefs False refs >> foldM importExplicit imps refs
200− resolveByType (Hiding refs) = do
200+ resolveByType :: Maybe ImportDeclarationType -> m Imports
201+ resolveByType Nothing = importAll (importRef Local)
202+ resolveByType (Just Implicit) = importAll (importRef FromImplicit)
203+ resolveByType (Just (Explicit refs)) = checkRefs False refs >> foldM (importRef FromExplicit) imps refs
204+ resolveByType (Just (Hiding refs)) = do
201205 imps' <- checkRefs True refs >> importAll (importNonHidden refs)
202206 let isEmptyImport
203207 = M.null (importedTypes imps')
@@ -246,7 +250,7 @@ resolveImport importModule exps imps impQual = resolveByType
246250
247251 importNonHidden :: [DeclarationRef] -> Imports -> DeclarationRef -> m Imports
248252 importNonHidden hidden m ref | isHidden ref = return m
249− | otherwise = importExplicit m ref
253+ | otherwise = importRef FromImplicit m ref
250254 where
251255 -- TODO: rework this to be not confusing
252256 isHidden :: DeclarationRef -> Bool
@@ -268,27 +272,26 @@ resolveImport importModule exps imps impQual = resolveByType
268272 imp'' <- foldM (\m (name, _) -> importer m (ValueRef name)) imp' (exportedValues exps)
269273 foldM (\m (name, _) -> importer m (TypeClassRef name)) imp'' (exportedTypeClasses exps)
270274
271− -- Import something explicitly
272− importExplicit :: Imports -> DeclarationRef -> m Imports
273− importExplicit imp (PositionedDeclarationRef pos _ r) =
274− warnAndRethrowWithPosition pos $ importExplicit imp r
275− importExplicit imp (ValueRef name) = do
276− let values' = updateImports (importedValues imp) (exportedValues exps) name
275+ importRef :: ImportProvenance -> Imports -> DeclarationRef -> m Imports
276+ importRef prov imp (PositionedDeclarationRef pos _ r) =
277+ warnAndRethrowWithPosition pos $ importRef prov imp r
278+ importRef prov imp (ValueRef name) = do
279+ let values' = updateImports (importedValues imp) (exportedValues exps) name prov
277280 return $ imp { importedValues = values' }
278− importExplicit imp (TypeRef name dctors) = do
279− let types' = updateImports (importedTypes imp) (first fst `map` exportedTypes exps) name
281+ importRef prov imp (TypeRef name dctors) = do
282+ let types' = updateImports (importedTypes imp) (first fst `map` exportedTypes exps) name prov
280283 let exportedDctors :: [(ProperName 'ConstructorName, ModuleName)]
281284 exportedDctors = allExportedDataConstructors name
282285 dctorNames :: [ProperName 'ConstructorName]
283286 dctorNames = fst `map` exportedDctors
284287 maybe (return ()) (traverse_ $ checkDctorExists name dctorNames) dctors
285288 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)
287290 return $ imp { importedTypes = types', importedDataConstructors = dctors' }
288− importExplicit imp (TypeClassRef name) = do
289− let typeClasses' = updateImports (importedTypeClasses imp) (exportedTypeClasses exps) name
291+ importRef prov imp (TypeClassRef name) = do
292+ let typeClasses' = updateImports (importedTypeClasses imp) (exportedTypeClasses exps) name prov
290293 return $ imp { importedTypeClasses = typeClasses' }
291− importExplicit _ _ = internalError "Invalid argument to importExplicit"
294+ importRef _ _ _ = internalError "Invalid argument to importRef"
292295
293296 -- Find all exported data constructors for a given type
294297 allExportedDataConstructors :: ProperName 'TypeName -> [(ProperName 'ConstructorName, ModuleName)]
@@ -300,11 +303,17 @@ resolveImport importModule exps imps impQual = resolveByType
300303 -- Add something to an import resolution list
301304 updateImports
302305 :: (Ord a)
303− => M.Map (Qualified a) [(Qualified a, ModuleName)]
306+ => M.Map (Qualified a) [ImportRecord a]
304307 -> [(a, ModuleName)]
305308 -> a
306− -> M.Map (Qualified a) [(Qualified a, ModuleName)]
307− updateImports imps' exps' name =
308− let 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'
309+ -> ImportProvenance
310+ -> M.Map (Qualified a) [ImportRecord a]
311+ updateImports imps' exps' name prov =
312+ let
313+ mnOrig = fromMaybe (internalError "Invalid state in updateImports") (name `lookup` exps')
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
297297 ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< replaceTypeWildcards $ ty
298298 val' <- if checkType then withScopedTypeVars moduleName args (check val ty') else return val
299299 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
301303infer' _ = internalError "Invalid argument to infer"
302304
303305inferLetBinding ::
@@ -623,8 +625,9 @@ check' val kt@(KindedType ty kind) = do
623625 checkTypeKind ty kind
624626 val' <- check' val ty
625627 return $ TypedValue True val' kt
626−check' (PositionedValue pos _ val) ty =
627− warnAndRethrowWithPosition pos $ check' val ty
628+check' (PositionedValue pos c val) ty = warnAndRethrowWithPosition pos $ do
629+ TypedValue t v ty' <- check' val ty
630+ return $ TypedValue t (PositionedValue pos c v) ty'
628631check' val ty = do
629632 TypedValue _ val' ty' <- infer val
630633 mt <- subsumes (Just val') ty' ty
stack-lts-2.yaml+6−2
@@ -1,4 +1,4 @@
1−flags: {}
1+resolver: lts-2.22
22packages:
33- '.'
44extra-deps:
@@ -6,4 +6,8 @@ extra-deps:
66- bower-json-0.7.0.0
77- boxes-0.1.4
88- 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
22packages:
33- '.'
4−extra-deps: []
5−resolver: lts-3.6
4+extra-deps:
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 @@
11flags: {}
22packages:
33- '.'
4−extra-deps:
5−resolver: nightly-2015-09-29
4+extra-deps: []
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
2525import qualified TestPscPublish
2626import qualified TestDocs
2727import qualified TestPsci
28+import qualified TestPscIde
2829
2930main :: IO ()
3031main = do
@@ -36,6 +37,8 @@ main = do
3637 TestPscPublish.main
3738 heading "psci test suite"
3839 TestPsci.main
40+ heading "psc-ide test suite"
41+ TestPscIde.main
3942
4043 where
4144 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