git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge branch 'master' of github.com:purescript/purescript into deriving-generic-patch
commitfd8259119112df77b530c166b0fd1a8b0a2fdade authorU-CIQDEV\gbazerman <gbazerman@GBAZERMAN-T35.ciqdev.com> dateMon 10 Aug 2015, 16:23 (11 years ago) parentd84e2c1f0ed783
301 files changed+4382−3690
.gitignore+3 .travis.yml+47−9 CONTRIBUTING.md+15−7 INSTALL.md+47 LICENSE+218−89 README.md+1−1 bundle/README+6−5 bundle/build.sh+3−2 bundle/winbuild.sh+3−2 core-tests/test-everything.sh+6−3 examples/failing/365.purs+1 examples/failing/438.purs+6−2 examples/failing/ArrayType.purs+3−1 examples/failing/Arrays.purs+3 examples/failing/CaseDoesNotMatchAllConstructorArgs.purs+15 examples/failing/Do.purs+2 examples/failing/DoNotSuggestComposition.purs+13 examples/failing/DoNotSuggestComposition2.purs+7 examples/failing/DuplicateDeclarationsInLet.purs+1 examples/failing/DuplicateProperties1.purs+1 examples/failing/DuplicateProperties2.purs+1 examples/failing/DuplicateTypeVars.purs+1 examples/failing/Eff.purs+3−2 examples/failing/ExtraRecordField.purs+10 examples/failing/Foldable.purs+1 examples/failing/InfiniteKind.purs+5 examples/failing/InfiniteType.purs+5 examples/failing/InstanceExport.purs+2 examples/failing/KindError.purs+1 examples/failing/LeadingZeros1.purs+1 examples/failing/LeadingZeros2.purs+1 examples/failing/Let.purs+1 examples/failing/MPTCs.purs+1 examples/failing/MissingClassExport.purs+1 examples/failing/MissingClassMemberExport.purs+1 examples/failing/MissingRecordField.purs+11 examples/failing/MultipleErrors.purs+4−2 examples/failing/MultipleErrors2.purs+2 examples/failing/MutRec.purs+1 examples/failing/MutRec2.purs+1 examples/failing/NewtypeMultiArgs.purs+1 examples/failing/NewtypeMultiCtor.purs+1 examples/failing/NoOverlap.purs−13 examples/failing/NullaryAbs.purs+1 examples/failing/Object.purs+1 examples/failing/OverlappingArguments.purs+1 examples/failing/OverlappingBinders.purs+1 examples/failing/OverlappingInstances.purs+2−1 examples/failing/OverlappingInstances2.purs+6−7 examples/failing/OverlappingVars.purs+1 examples/failing/Rank2Types.purs+1 examples/failing/Reserved.purs+1 examples/failing/RowConstructors1.purs+2−1 examples/failing/RowConstructors2.purs+2−1 examples/failing/RowConstructors3.purs+2−1 examples/failing/SkolemEscape.purs+1 examples/failing/SkolemEscape2.purs+1 examples/failing/SuggestComposition.purs+7 examples/failing/Superclasses1.purs+1 examples/failing/Superclasses2.purs+2 examples/failing/Superclasses3.purs+1 examples/failing/Superclasses4.purs+2−1 examples/failing/TopLevelCaseNoArgs.purs+1 examples/failing/TypeClassInstances.purs+1 examples/failing/TypeClasses2.purs+1 examples/failing/TypeError.purs+1 examples/failing/TypeSynonyms.purs+1 examples/failing/TypeSynonyms2.purs+1 examples/failing/TypeSynonyms3.purs+1 examples/failing/TypeSynonyms4.purs+1 examples/failing/TypeSynonyms5.purs+1 examples/failing/TypeWildcards1.purs+1 examples/failing/TypeWildcards2.purs+1 examples/failing/TypeWildcards3.purs+1 examples/failing/UnderscoreModuleName.purs+2−1 examples/failing/UnifyInTypeInstanceLookup.purs+3 examples/failing/UnknownType.purs+1 examples/manual/QualifiedNames.purs+1−1 examples/manual/failing/ExportExplicit1.purs+1−1 examples/manual/failing/ExportExplicit3.purs+1−1 examples/manual/passing/ExportExplicit.purs+1−1 examples/manual/passing/ExportExplicit2.purs+1−1 examples/manual/passing/Import.purs+1−1 examples/manual/passing/ImportExplicit.purs+1−1 examples/manual/passing/ImportQualified.purs+3−3 examples/manual/passing/Module.purs+1−1 examples/manual/passing/ModuleDeps.purs+1−1 examples/manual/passing/RedefinedFixity.purs+1−1 examples/manual/passing/ShadowedName.purs+2−2 examples/manual/passing/TransitiveImport.purs+1−1 examples/manual/passing/WildcardType.purs+2−2 examples/passing/652.purs+1−1 examples/passing/810.purs+1−1 examples/passing/Applicative.purs+4−4 examples/passing/ArrayType.purs+1−1 examples/passing/Auto.purs+1−1 examples/passing/AutoPrelude.purs+2−2 examples/passing/AutoPrelude2.purs+2−2 examples/passing/BindersInFunctions.purs+5−6 examples/passing/BindingGroups.purs+1−1 examples/passing/BlockString.purs+1−1 examples/passing/CaseInDo.purs+3−3 examples/passing/CaseStatement.purs+1−1 examples/passing/CheckFunction.purs+1−1 examples/passing/CheckSynonymBug.purs+4−1 examples/passing/CheckTypeClass.purs+1−1 examples/passing/Church.purs+1−1 examples/passing/Collatz.purs+6−6 examples/passing/Comparisons.purs+3−3 examples/passing/Conditional.purs+1−1 examples/passing/Console.purs+2−2 examples/passing/DataAndType.purs+1−1 examples/passing/DeepArrayBinder.purs+5−4 examples/passing/DeepCase.purs+1−1 examples/passing/Do.purs+7−7 examples/passing/Dollar.purs+1−1 examples/passing/Eff.purs+5−5 examples/passing/EmptyDataDecls.purs+4−4 examples/passing/EmptyRow.purs+1−1 examples/passing/EmptyTypeClass.purs+1−1 examples/passing/EqOrd.purs+2−3 examples/passing/ExtendedInfixOperators.purs+1−1 examples/passing/Fib.purs+1−1 examples/passing/FinalTagless.purs+2−2 examples/passing/FunctionScope.purs+3−4 examples/passing/Functions.purs+1−1 examples/passing/Functions2.purs+3−4 examples/passing/Guards.purs+2−2 examples/passing/HoistError.purs+3−3 examples/passing/IfThenElseMaybe.purs+1−1 examples/passing/ImplicitEmptyImport.purs+3−3 examples/passing/ImportHiding.purs+1−1 examples/passing/InferRecFunWithConstrainedArgument.purs+1−1 examples/passing/InstanceBeforeClass.purs+1−1 examples/passing/IntAndChar.purs+2−2 examples/passing/JSReserved.purs+1−1 examples/passing/KindedType.purs+1−1 examples/passing/Let.purs+7−7 examples/passing/Let2.purs+1−1 examples/passing/LetInInstance.purs+1−1 examples/passing/LiberalTypeSynonyms.purs+1−1 examples/passing/MPTCs.purs+1−1 examples/passing/Match.purs+1−1 examples/passing/ModuleExport.purs+9 examples/passing/ModuleExportDupes.purs+19 examples/passing/ModuleExportExcluded.purs+14 examples/passing/ModuleExportHiding.purs+11 examples/passing/ModuleExportQualified.purs+9 examples/passing/ModuleExportSelf.purs+14 examples/passing/Monad.purs+1−1 examples/passing/MonadState.purs+4−4 examples/passing/MultiArgFunctions.purs+13−13 examples/passing/MutRec.purs+1−1 examples/passing/MutRec2.purs+1−1 examples/passing/MutRec3.purs+1−1 examples/passing/NamedPatterns.purs+1−1 examples/passing/NegativeBinder.purs+1−1 examples/passing/Nested.purs+1−1 examples/passing/NestedTypeSynonyms.purs+1−1 examples/passing/NestedWhere.purs+1−1 examples/passing/Newtype.purs+3−3 examples/passing/NewtypeEff.purs+9−9 examples/passing/NewtypeWithRecordUpdate.purs+2−2 examples/passing/ObjectGetter.purs+4−4 examples/passing/ObjectSynonym.purs+1−1 examples/passing/ObjectUpdate.purs+1−1 examples/passing/ObjectUpdate2.purs+1−1 examples/passing/ObjectUpdater.purs+2−2 examples/passing/ObjectWildcards.purs+3−3 examples/passing/Objects.purs+2−2 examples/passing/OneConstructor.purs+1−1 examples/passing/OperatorAssociativity.purs+3−3 examples/passing/OperatorInlining.purs+1−1 examples/passing/OperatorSections.purs+2−2 examples/passing/Operators.purs+2−2 examples/passing/OptimizerBug.purs+1−1 examples/passing/PartialFunction.purs+2−2 examples/passing/Patterns.purs+1−1 examples/passing/Person.purs+1−1 examples/passing/Rank2Data.purs+2−2 examples/passing/Rank2Object.purs+2−2 examples/passing/Rank2TypeSynonym.purs+1−1 examples/passing/Rank2Types.purs+1−1 examples/passing/RebindableSyntax.purs+6−6 examples/passing/Recursion.purs+1−1 examples/passing/ReservedWords.purs+1−1 examples/passing/RowConstructors.purs+1−1 examples/passing/RowPolyInstanceContext.purs+1−1 examples/passing/RuntimeScopeIssue.purs+1−1 examples/passing/ScopedTypeVariables.purs+1−1 examples/passing/Sequence.purs+1−1 examples/passing/SequenceDesugared.purs+4−4 examples/passing/ShadowedRename.purs+3−3 examples/passing/ShadowedTCO.purs+2−2 examples/passing/ShadowedTCOLet.purs+1−1 examples/passing/SignedNumericLiterals.purs+1−1 examples/passing/Superclasses1.purs+1−1 examples/passing/Superclasses2.purs+1−2 examples/passing/Superclasses3.purs+7−7 examples/passing/TCOCase.purs+1−1 examples/passing/TailCall.purs+1−1 examples/passing/Tick.purs+1−1 examples/passing/TopLevelCase.purs+3−3 examples/passing/TypeClassMemberOrderChange.purs+1−1 examples/passing/TypeClasses.purs+8−8 examples/passing/TypeClassesInOrder.purs+1−1 examples/passing/TypeClassesWithOverlappingTypeVariables.purs+3−3 examples/passing/TypeDecl.purs+1−1 examples/passing/TypeSynonymInData.purs+1−1 examples/passing/TypeSynonyms.purs+1−1 examples/passing/TypeWildcards.purs+1−1 examples/passing/TypeWildcardsRecordExtension.purs+1−1 examples/passing/TypedWhere.purs+1−1 examples/passing/UnderscoreIdent.purs+1−1 examples/passing/Unit.purs+1−1 examples/passing/UnknownInTypeClassLookup.purs+1−1 examples/passing/Where.purs+7−7 examples/passing/iota.purs+1−1 examples/passing/s.purs+1−1 hierarchy/Main.hs+9−5 license-generator/generate+1−1 psc-bundle/Main.hs+138 psc-bundle/README.md+18 psc-docs/Main.hs+3−1 psc-make/Main.hs−164 psc-make/Make.hs−138 psc-publish/Main.hs+29−271 psc-publish/Utils.hs−22 psc-publish/tests/Test.hs+13−10 psc/Main.hs+78−130 psci/Completion.hs+9−6 psci/Make.hs−127 psci/PSCi.hs+56−23 psci/tests/Main.hs+35−29 purescript.cabal+52−35 src/Language/PureScript.hs+1−244 src/Language/PureScript/AST/Binders.hs+1−1 src/Language/PureScript/AST/Declarations.hs+7−1 src/Language/PureScript/AST/Exported.hs+12−8 src/Language/PureScript/AST/Operators.hs+14−2 src/Language/PureScript/AST/SourcePos.hs+6−2 src/Language/PureScript/Bundle.hs+545 src/Language/PureScript/CodeGen/Externs.hs+17−2 src/Language/PureScript/CodeGen/JS.hs+7−17 src/Language/PureScript/CodeGen/JS/AST.hs+2−1 src/Language/PureScript/CodeGen/JS/Optimizer.hs+2−2 src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs+12−15 src/Language/PureScript/CodeGen/JS/Optimizer/MagicDo.hs+3−3 src/Language/PureScript/CodeGen/JS/Optimizer/TCO.hs+1−1 src/Language/PureScript/Constants.hs+9−12 src/Language/PureScript/DeadCodeElimination.hs−102 src/Language/PureScript/Docs.hs+1 src/Language/PureScript/Docs/AsMarkdown.hs+45−22 src/Language/PureScript/Docs/Convert.hs+228 src/Language/PureScript/Docs/ParseAndDesugar.hs+33−12 src/Language/PureScript/Docs/Render.hs+100−212 src/Language/PureScript/Docs/RenderedCode/Render.hs+26−12 src/Language/PureScript/Docs/Types.hs+274−98 src/Language/PureScript/Environment.hs+25−4 src/Language/PureScript/Errors.hs+70−37 src/Language/PureScript/Kinds.hs+5−1 src/Language/PureScript/Linter.hs+8−2 src/Language/PureScript/Linter/Exhaustive.hs+285 src/Language/PureScript/Make.hs+318 src/Language/PureScript/Names.hs+18−1 src/Language/PureScript/Options.hs+5−44 src/Language/PureScript/Parser/Declarations.hs+9−1 src/Language/PureScript/Pretty/JS.hs+1 src/Language/PureScript/Pretty/Values.hs+40−64 src/Language/PureScript/Publish.hs+361 psc-publish/BoxesHelpers.hs → src/Language/PureScript/Publish/BoxesHelpers.hs+2−2 psc-publish/ErrorsWarnings.hs → src/Language/PureScript/Publish/ErrorsWarnings.hs+100−33 src/Language/PureScript/Publish/Utils.hs+38 src/Language/PureScript/Sugar/DoNotation.hs+3−3 src/Language/PureScript/Sugar/Names.hs+74−7 src/Language/PureScript/Sugar/TypeClasses.hs+1−1 src/Language/PureScript/TypeChecker.hs+49−62 src/Language/PureScript/TypeChecker/Entailment.hs+9−14 src/Language/PureScript/TypeChecker/Monad.hs+11−5 src/Language/PureScript/TypeChecker/Synonyms.hs+10−17 src/Language/PureScript/TypeChecker/Types.hs+7−4 src/Language/PureScript/Types.hs+8−2 stack.yaml+9 tests/Main.hs+175−65 tests/prelude/Prelude.purs−628 tests/prelude/js/Assert.js−19 tests/prelude/js/Control.Monad.Eff.js−40 tests/prelude/js/Control.Monad.ST.js−38 tests/prelude/js/Data.Function.js−233 tests/prelude/js/Debug.Trace.js−11 tests/prelude/js/Prelude.Unsafe.js−10 tests/prelude/js/Prelude.js−150 tests/support/.gitignore+2 tests/support/bower.json+11 tests/support/package.json+7 tests/support/setup.js+22 travis-after-script.sh−21 travis-script.sh−17 travis/after.sh+25 travis/configure.sh+17 travis/test-install.sh+12
.gitignore+3
@@ -9,5 +9,8 @@ cabal.sandbox.config
99*.lksh*
1010.virthualenv
1111.psci_modules/
12+.test_modules/
1213bower_components/
1314tmp/
15+.stack-work/
16+tests/support/flattened/
.travis.yml+47−9
@@ -1,20 +1,43 @@
1+sudo: false
12env:
2− - CABALVER=1.22 GHCVER=7.8.3 SUITE=tests
3− - CABALVER=1.22 GHCVER=7.8.3 SUITE=psci-tests
3+ - GHCVER=7.8.4 COVERAGE_SUITE=tests
4+ - GHCVER=7.8.4 COVERAGE_SUITE=psci-tests
5+ - GHCVER=7.6.3
6+ - GHCVER=7.10.1
7+ - GHCVER=7.8.4 STACKAGE=lts-2.22
8+ # 7.10.2 Pending https://github.com/travis-ci/apt-package-whitelist/pull/686
9+ - GHCVER=7.10.1 STACKAGE-nightly-2015-08-09
410before_install:
5− - travis_retry sudo add-apt-repository -y ppa:hvr/ghc
6− - travis_retry sudo apt-get update
7− - travis_retry sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER
8− - export PATH="/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$HOME/.cabal/bin:$PATH"
11+ - export PATH="/opt/ghc/$GHCVER/bin:$PATH"
12+ - export PATH="/opt/cabal/1.22/bin:$PATH"
13+ - export PATH="$HOME/.cabal/bin:$PATH"
14+ - export PATH="/opt/happy/1.19.5/bin:/$PATH"
15+ - export PATH="/opt/alex/3.1.4/bin:/$PATH"
916install:
1017 - cabal --version
1118 - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
1219 - travis_retry cabal update
13− - cabal install --only-dependencies --enable-tests --enable-benchmarks
20+ - cabal sandbox init
21+ # Download stackage cabal.config
22+ # Not sure whether filtering out purescript is necessary
23+ - if [ -n "$STACKAGE" ]; then curl http://www.stackage.org/$STACKAGE/cabal.config | grep -v purescript > cabal.config; fi
24+ # Run with limited concurrency
25+ # Travis container infrastructure seems to expose all host CPUs (16?), thus
26+ # cabal and ghc tries to use them all. Which is bad idea on a shared box.
27+ # See also: https://ghc.haskell.org/trac/ghc/ticket/9221
28+ #
29+ # We probably want to be running with larger heap sizes when there are lots
30+ # of cores, to counteract the synchronization overhead of stop-the-world GC
31+ # across many cores. e.g. +RTS -A32m at least.
32+ - cabal install --only-dependencies --enable-tests -j2 --ghc-options='+RTS -A32m -RTS'
33+ - cabal install hpc-coveralls -j2
1434script:
15− - ./travis-script.sh
35+ - ./travis/configure.sh
36+ - cabal build -j2 --ghc-options='+RTS -A32m -RTS'
37+ - cabal test
38+ - ./travis/test-install.sh
1639after_script:
17− - ./travis-after-script.sh
40+ - ./travis/after.sh
1841notifications:
1942 email: true
2043before_deploy: "./bundle/build.sh linux64"
@@ -28,3 +51,18 @@ deploy:
2851 on:
2952 all_branches: true
3053 tags: true
54+addons:
55+ apt:
56+ sources:
57+ - hvr-ghc
58+ packages:
59+ - cabal-install-1.22
60+ - ghc-7.6.3
61+ - ghc-7.8.4
62+ - ghc-7.10.1
63+ - happy-1.19.5
64+ - alex-3.1.4
65+cache:
66+ directories:
67+ - .cabal-sandbox
68+ - ../install-test/.cabal-sandbox
CONTRIBUTING.md+15−7
@@ -2,22 +2,25 @@ An introductory overview of the compiler is available [here](https://www.youtube
22
33Pull requests are encouraged.
44
5+## Finding Issues to Work On
6+
7+If you would like to contribute, please consider the issues in the current milestone first. If you are a new contributor, you may want to have a go at the ["easy" issues](https://github.com/purescript/purescript/labels/easy) to get started.
8+
9+## Pull Requests
10+
511Please follow the following guidelines:
612
713- Add at least a test to `examples/passing/` and possibly to `examples/failing`.
814- Build the binaries and libs with `cabal build`
915- Install the binaries and libs with `cabal install`.
10−- Run `cabal configure --enable-tests && cabal build && cabal test` to build the test suite.
11−- Run `purescript-test-everything` to make sure you haven't broken any core library builds.
12−- Run `starter-kit` to make sure the starter kit has not been broken.
16+- Run `cabal configure --enable-tests && cabal build && cabal test` to build the test suite. You will need `npm` and `node` on your PATH to run the tests.
17+- Build the core libraries by running the script in `core-tests`.
1318
14−If you would like to contribute, please consider the issues in the current milestone first. If you are a new contributor, you may want to have a go at the ["easy" issues](https://github.com/purescript/purescript/labels/easy) to get started.
15−
16−Finally, if you have made code changes and would like to be included in the copyright notice in the cabal file, please include that change in your pull request.
19+## Code Review
1720
1821To prevent core libraries from getting broken, every change must be reviewed. A pull request will be merged as long as one other team member has verified the changes.
1922
20−## Adding dependencies
23+## Adding Dependencies
2124
2225Because the PureScript compiler is distributed in binary form, we include
2326the licenses of all dependencies, including transitive ones, in the LICENSE
@@ -30,3 +33,8 @@ You can automate this (if you have bash):
3033- run at the command line: `./license/generate > LICENSE`
3134
3235[cabal-dependency-licenses]: https://github.com/jaspervdj/cabal-dependency-licenses
36+
37+## Writing Issues
38+
39+- If the issue is actually a question, please consider asking on Reddit, Stack Overflow or IRC first.
40+- Please include a minimal, repeatable test case with any bug report.
INSTALL.mdnew file+47
@@ -0,0 +1,47 @@
1+# Installation information
2+
3+If you are having difficulty installing the PureScript compiler, feel free to
4+ask for help! A good place is the #purescript IRC channel on Freenode, or
5+alternatively Stack Overflow.
6+
7+## Using prebuilt binaries
8+
9+The prebuilt binaries are compiled with GHC 7.8.3, and therefore they should
10+run on any operating system supported by GHC 7.8.3, such as:
11+
12+* Windows 2000 or later,
13+* OS X 10.7 or later,
14+* Linux ??? (we're not sure what the minimum version is).
15+
16+This list is not exhaustive. If your OS is too old or not listed, or if the
17+binaries fail to run, you may be able to install the compiler by building it
18+from source; see below.
19+
20+It's probably safe to assume that other prebuilt distributions (eg, Homebrew,
21+Chocolatey, AUR, npm) use the same binaries, and therefore have the same
22+requirements.
23+
24+## Compiling from source
25+
26+GHC 7.6.1 or newer is required to compile from source. The easiest way is to
27+use `cabal-install`:
28+
29+```
30+$ cabal update && cabal install purescript
31+```
32+
33+The PureScript compiler has been known to run on OS X 10.6 when built with GHC
34+7.6.
35+
36+## The "curses" library
37+
38+`psci` depends on the `curses` library (via the Haskell package `terminfo`). If
39+you are having difficulty running the compiler, it may be because the `curses`
40+library is missing.
41+
42+On Linux, you will probably need to install `ncurses` manually. On Ubuntu, for
43+example, this can be done by running:
44+
45+```
46+$ sudo apt-get install libncurses5-dev
47+```
LICENSE+218−89
@@ -22,6 +22,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2222
2323PureScript uses the following Haskell library packages. Their license files follow.
2424
25+ Glob
26+ HUnit
2527 aeson
2628 aeson-better-errors
2729 ansi-terminal
@@ -29,6 +31,7 @@ PureScript uses the following Haskell library packages. Their license files foll
2931 array
3032 attoparsec
3133 base
34+ blaze-builder
3235 bower-json
3336 boxes
3437 bytestring
@@ -38,10 +41,10 @@ PureScript uses the following Haskell library packages. Their license files foll
3841 dlist
3942 filepath
4043 ghc-prim
41− Glob
4244 hashable
4345 haskeline
4446 integer-gmp
47+ language-javascript
4548 mtl
4649 nats
4750 old-locale
@@ -69,6 +72,69 @@ PureScript uses the following Haskell library packages. Their license files foll
6972 vector
7073 void
7174
75+Glob LICENSE file:
76+
77+ The code in Glob is released under the license below. Copyrights to parts of
78+ the code are held by whoever wrote the code in question: see CREDITS.txt for a
79+ list of authors.
80+
81+ Copyright (c) 2008-2012 <authors>
82+ All rights reserved.
83+
84+ Redistribution and use in source and binary forms, with or without
85+ modification, are permitted provided that the following conditions are met:
86+ * Redistributions of source code must retain the above copyright
87+ notice, this list of conditions and the following disclaimer.
88+ * Redistributions in binary form must reproduce the above copyright
89+ notice, this list of conditions and the following disclaimer in the
90+ documentation and/or other materials provided with the distribution.
91+ * Neither the name of the project nor the names of its contributors may be
92+ used to endorse or promote products derived from this software without
93+ specific prior written permission.
94+
95+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR IMPLIED
96+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
97+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
98+ EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
99+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
100+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
101+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
102+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
103+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
104+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
105+
106+HUnit LICENSE file:
107+
108+ HUnit is Copyright (c) Dean Herington, 2002, all rights reserved,
109+ and is distributed as free software under the following license.
110+
111+ Redistribution and use in source and binary forms, with or without
112+ modification, are permitted provided that the following conditions
113+ are met:
114+
115+ - Redistributions of source code must retain the above copyright
116+ notice, this list of conditions, and the following disclaimer.
117+
118+ - Redistributions in binary form must reproduce the above copyright
119+ notice, this list of conditions, and the following disclaimer in the
120+ documentation and/or other materials provided with the distribution.
121+
122+ - The names of the copyright holders may not be used to endorse or
123+ promote products derived from this software without specific prior
124+ written permission.
125+
126+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY
127+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
128+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
129+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE
130+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
131+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
132+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
133+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
134+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
135+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
136+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
137+
72138aeson LICENSE file:
73139
74140 Copyright (c) 2011, MailRank, Inc.
@@ -149,6 +215,7 @@ ansi-terminal LICENSE file:
149215 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
150216 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
151217 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
218+
152219ansi-wl-pprint LICENSE file:
153220
154221 Copyright 2008, Daan Leijen and Max Bolingbroke. All rights reserved.
@@ -382,6 +449,39 @@ base LICENSE file:
382449
383450 -----------------------------------------------------------------------------
384451
452+blaze-builder LICENSE file:
453+
454+ Copyright Jasper Van der Jeugt 2010, Simon Meier 2010 & 2011
455+
456+ All rights reserved.
457+
458+ Redistribution and use in source and binary forms, with or without
459+ modification, are permitted provided that the following conditions are met:
460+
461+ * Redistributions of source code must retain the above copyright
462+ notice, this list of conditions and the following disclaimer.
463+
464+ * Redistributions in binary form must reproduce the above
465+ copyright notice, this list of conditions and the following
466+ disclaimer in the documentation and/or other materials provided
467+ with the distribution.
468+
469+ * Neither the name of Jasper Van der Jeugt nor the names of other
470+ contributors may be used to endorse or promote products derived
471+ from this software without specific prior written permission.
472+
473+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
474+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
475+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
476+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
477+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
478+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
479+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
480+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
481+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
482+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
483+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
484+
385485bower-json LICENSE file:
386486
387487 Copyright (c) 2015 Harry Garrood
@@ -742,10 +842,6 @@ ghc-prim LICENSE file:
742842 be a definition of the Haskell 98 Language.
743843
744844
745−Glob LICENSE file:
746−
747− Page not found: Sorry, it's just not here.
748−
749845hashable LICENSE file:
750846
751847 Copyright Milan Straka 2010
@@ -838,6 +934,39 @@ integer-gmp LICENSE file:
838934 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
839935 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
840936
937+language-javascript LICENSE file:
938+
939+ Copyright (c)2010, Alan Zimmerman
940+
941+ All rights reserved.
942+
943+ Redistribution and use in source and binary forms, with or without
944+ modification, are permitted provided that the following conditions are met:
945+
946+ * Redistributions of source code must retain the above copyright
947+ notice, this list of conditions and the following disclaimer.
948+
949+ * Redistributions in binary form must reproduce the above
950+ copyright notice, this list of conditions and the following
951+ disclaimer in the documentation and/or other materials provided
952+ with the distribution.
953+
954+ * Neither the name of Alan Zimmerman nor the names of other
955+ contributors may be used to endorse or promote products derived
956+ from this software without specific prior written permission.
957+
958+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
959+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
960+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
961+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
962+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
963+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
964+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
965+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
966+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
967+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
968+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
969+
841970mtl LICENSE file:
842971
843972 The Glasgow Haskell Compiler License
@@ -1198,7 +1327,7 @@ rts LICENSE file:
11981327
11991328safe LICENSE file:
12001329
1201− Copyright Neil Mitchell 2007-2014.
1330+ Copyright Neil Mitchell 2007-2015.
12021331 All rights reserved.
12031332
12041333 Redistribution and use in source and binary forms, with or without
@@ -1323,89 +1452,89 @@ split LICENSE file:
13231452
13241453syb LICENSE file:
13251454
1326− This library (libraries/syb) is derived from code from several
1327− sources:
1328−
1329− * Code from the GHC project which is largely (c) The University of
1330− Glasgow, and distributable under a BSD-style license (see below),
1331−
1332− * Code from the Haskell 98 Report which is (c) Simon Peyton Jones
1333− and freely redistributable (but see the full license for
1334− restrictions).
1335−
1336− * Code from the Haskell Foreign Function Interface specification,
1337− which is (c) Manuel M. T. Chakravarty and freely redistributable
1338− (but see the full license for restrictions).
1339−
1340− The full text of these licenses is reproduced below. All of the
1341− licenses are BSD-style or compatible.
1342−
1343− -----------------------------------------------------------------------------
1344−
1345− The Glasgow Haskell Compiler License
1346−
1347− Copyright 2004, The University Court of the University of Glasgow.
1348− All rights reserved.
1349−
1350− Redistribution and use in source and binary forms, with or without
1351− modification, are permitted provided that the following conditions are met:
1352−
1353− - Redistributions of source code must retain the above copyright notice,
1354− this list of conditions and the following disclaimer.
1355−
1356− - Redistributions in binary form must reproduce the above copyright notice,
1357− this list of conditions and the following disclaimer in the documentation
1358− and/or other materials provided with the distribution.
1359−
1360− - Neither name of the University nor the names of its contributors may be
1361− used to endorse or promote products derived from this software without
1362− specific prior written permission.
1363−
1364− THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF
1365− GLASGOW AND THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
1366− INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
1367− FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
1368− UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS BE LIABLE
1369− FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1370− DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1371− SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1372− CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1373− LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1374− OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1375− DAMAGE.
1376−
1377− -----------------------------------------------------------------------------
1378−
1379− Code derived from the document "Report on the Programming Language
1380− Haskell 98", is distributed under the following license:
1381−
1382− Copyright (c) 2002 Simon Peyton Jones
1383−
1384− The authors intend this Report to belong to the entire Haskell
1385− community, and so we grant permission to copy and distribute it for
1386− any purpose, provided that it is reproduced in its entirety,
1387− including this Notice. Modified versions of this Report may also be
1388− copied and distributed for any purpose, provided that the modified
1389− version is clearly presented as such, and that it does not claim to
1390− be a definition of the Haskell 98 Language.
1391−
1392− -----------------------------------------------------------------------------
1393−
1394− Code derived from the document "The Haskell 98 Foreign Function
1395− Interface, An Addendum to the Haskell 98 Report" is distributed under
1396− the following license:
1397−
1398− Copyright (c) 2002 Manuel M. T. Chakravarty
1399−
1400− The authors intend this Report to belong to the entire Haskell
1401− community, and so we grant permission to copy and distribute it for
1402− any purpose, provided that it is reproduced in its entirety,
1403− including this Notice. Modified versions of this Report may also be
1404− copied and distributed for any purpose, provided that the modified
1405− version is clearly presented as such, and that it does not claim to
1406− be a definition of the Haskell 98 Foreign Function Interface.
1407−
1408− -----------------------------------------------------------------------------
1455+ This library (libraries/syb) is derived from code from several
1456+ sources:
1457+
1458+ * Code from the GHC project which is largely (c) The University of
1459+ Glasgow, and distributable under a BSD-style license (see below),
1460+
1461+ * Code from the Haskell 98 Report which is (c) Simon Peyton Jones
1462+ and freely redistributable (but see the full license for
1463+ restrictions).
1464+
1465+ * Code from the Haskell Foreign Function Interface specification,
1466+ which is (c) Manuel M. T. Chakravarty and freely redistributable
1467+ (but see the full license for restrictions).
1468+
1469+ The full text of these licenses is reproduced below. All of the
1470+ licenses are BSD-style or compatible.
1471+
1472+ -----------------------------------------------------------------------------
1473+
1474+ The Glasgow Haskell Compiler License
1475+
1476+ Copyright 2004, The University Court of the University of Glasgow.
1477+ All rights reserved.
1478+
1479+ Redistribution and use in source and binary forms, with or without
1480+ modification, are permitted provided that the following conditions are met:
1481+
1482+ - Redistributions of source code must retain the above copyright notice,
1483+ this list of conditions and the following disclaimer.
1484+
1485+ - Redistributions in binary form must reproduce the above copyright notice,
1486+ this list of conditions and the following disclaimer in the documentation
1487+ and/or other materials provided with the distribution.
1488+
1489+ - Neither name of the University nor the names of its contributors may be
1490+ used to endorse or promote products derived from this software without
1491+ specific prior written permission.
1492+
1493+ THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF
1494+ GLASGOW AND THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
1495+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
1496+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
1497+ UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS BE LIABLE
1498+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1499+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1500+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1501+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1502+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1503+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1504+ DAMAGE.
1505+
1506+ -----------------------------------------------------------------------------
1507+
1508+ Code derived from the document "Report on the Programming Language
1509+ Haskell 98", is distributed under the following license:
1510+
1511+ Copyright (c) 2002 Simon Peyton Jones
1512+
1513+ The authors intend this Report to belong to the entire Haskell
1514+ community, and so we grant permission to copy and distribute it for
1515+ any purpose, provided that it is reproduced in its entirety,
1516+ including this Notice. Modified versions of this Report may also be
1517+ copied and distributed for any purpose, provided that the modified
1518+ version is clearly presented as such, and that it does not claim to
1519+ be a definition of the Haskell 98 Language.
1520+
1521+ -----------------------------------------------------------------------------
1522+
1523+ Code derived from the document "The Haskell 98 Foreign Function
1524+ Interface, An Addendum to the Haskell 98 Report" is distributed under
1525+ the following license:
1526+
1527+ Copyright (c) 2002 Manuel M. T. Chakravarty
1528+
1529+ The authors intend this Report to belong to the entire Haskell
1530+ community, and so we grant permission to copy and distribute it for
1531+ any purpose, provided that it is reproduced in its entirety,
1532+ including this Notice. Modified versions of this Report may also be
1533+ copied and distributed for any purpose, provided that the modified
1534+ version is clearly presented as such, and that it does not claim to
1535+ be a definition of the Haskell 98 Foreign Function Interface.
1536+
1537+ -----------------------------------------------------------------------------
14091538
14101539template-haskell LICENSE file:
14111540
README.md+1−1
@@ -2,7 +2,7 @@
22
33A small strongly typed programming language with expressive types that compiles to Javascript, written in and inspired by Haskell.
44
5−[![Hackage](https://budueba.com/hackage/purescript)](http://hackage.haskell.org/package/purescript) [![Build Status](https://secure.travis-ci.org/purescript/purescript.png?branch=master)](http://travis-ci.org/purescript/purescript) [![Coverage Status](https://coveralls.io/repos/purescript/purescript/badge.png?branch=master)](https://coveralls.io/r/purescript/purescript?branch=master)
5+[![Hackage](https://budueba.com/hackage/purescript)](http://hackage.haskell.org/package/purescript) [![Build Status](https://api.travis-ci.org/purescript/purescript.svg?branch=master)](http://travis-ci.org/purescript/purescript) [![Coverage Status](https://coveralls.io/repos/purescript/purescript/badge.svg?branch=master)](https://coveralls.io/r/purescript/purescript?branch=master)
66
77## Language info
88
bundle/README+6−5
@@ -10,11 +10,12 @@ Installation Instructions
1010
1111This bundle contains the following executables:
1212
13−- psc The PureScript compiler (generates JavaScript for use
14− in the browser)
15−- psc-make The PureScript compiler (generates CommonJS modules)
16−- psci The PureScript interactive module (requires NodeJS)
17−- psc-docs A documentation generator
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
1819
1920Copy these files anywhere on your PATH.
2021
bundle/build.sh+3−2
@@ -18,18 +18,19 @@ mkdir -p build/purescript/
1818# Strip the binaries
1919strip ../dist/build/psc/psc
2020strip ../dist/build/psci/psci
21−strip ../dist/build/psc-make/psc-make
2221strip ../dist/build/psc-docs/psc-docs
2322strip ../dist/build/psc-publish/psc-publish
23+strip ../dist/build/psc-bundle/psc-bundle
2424
2525# Copy files to staging directory
2626cp ../dist/build/psc/psc build/purescript/
2727cp ../dist/build/psci/psci build/purescript/
28−cp ../dist/build/psc-make/psc-make build/purescript/
2928cp ../dist/build/psc-docs/psc-docs build/purescript/
3029cp ../dist/build/psc-publish/psc-publish build/purescript/
30+cp ../dist/build/psc-bundle/psc-bundle build/purescript/
3131cp README build/purescript/
3232cp ../LICENSE build/purescript/
33+cp ../INSTALL.md build/purescript/
3334
3435# Make the binary bundle
3536pushd build > /dev/null
bundle/winbuild.sh+3−2
@@ -14,18 +14,19 @@ mkdir -p build/purescript/
1414# Strip the binaries
1515strip ../dist/build/psc/psc.exe
1616strip ../dist/build/psci/psci.exe
17−strip ../dist/build/psc-make/psc-make.exe
1817strip ../dist/build/psc-docs/psc-docs.exe
1918strip ../dist/build/psc-publish/psc-publish.exe
19+strip ../dist/build/psc-bundle/psc-bundle.exe
2020
2121# Copy files to staging directory
2222cp ../dist/build/psc/psc.exe build/purescript/
2323cp ../dist/build/psci/psci.exe build/purescript/
24−cp ../dist/build/psc-make/psc-make.exe build/purescript/
2524cp ../dist/build/psc-docs/psc-docs.exe build/purescript/
2625cp ../dist/build/psc-publish/psc-publish.exe build/purescript/
26+cp ../dist/build/psc-bundle/psc-bundle.exe build/purescript/
2727cp README build/purescript/
2828cp ../LICENSE build/purescript/
29+cp ../INSTALL.md build/purescript/
2930
3031# Make the binary bundle
3132pushd build
core-tests/test-everything.sh+6−3
@@ -18,7 +18,6 @@ bower i purescript-prelude \
1818 purescript-maps \
1919 purescript-free \
2020 purescript-transformers \
21− purescript-monad-eff \
2221 purescript-exists \
2322 purescript-monoid \
2423 purescript-either \
@@ -45,6 +44,10 @@ bower i purescript-prelude \
4544 purescript-globals \
4645 purescript-exceptions \
4746 purescript-validation \
47+ purescript-parallel \
48+ purescript-proxy \
49+ purescript-semirings \
4850 purescript-math
49−
50−find bower_components/**/src -name '*.purs' | xargs ../dist/build/psc-make/psc-make
51+
52+../dist/build/psc/psc 'bower_components/purescript-*/src/**/*.purs' \
53+ --ffi 'bower_components/purescript-*/src/**/*.js'
examples/failing/365.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInDeclaration
12module Main where
23
34import Prelude
examples/failing/438.purs+6−2
@@ -1,3 +1,8 @@
1+-- @shouldFailWith NoInstanceFound
2+
3+-- See issue 438 for details: this test is mainly here to test that code like
4+-- this doesn't cause the compiler to loop.
5+
16module Main where
27
38import Prelude
@@ -5,7 +10,6 @@ import Prelude
510data Fix f = In (f (Fix f))
611
712instance eqFix :: (Eq (f (Fix f))) => Eq (Fix f) where
8− (==) (In f) (In g) = f == g
9− (/=) a b = not (a == b)
13+ eq (In f) (In g) = f == g
1014
1115example = In [] == In []
examples/failing/ArrayType.purs+3−1
@@ -1,7 +1,9 @@
1+-- @shouldFailWith TypesDoNotUnify
2+
13module Main where
24
35import Prelude
4−import Debug.Trace
6+import Control.Monad.Eff.Console
57
68bar :: Number -> Number -> Number
79bar n m = n + m
examples/failing/Arrays.purs+3
@@ -1,5 +1,8 @@
1+-- @shouldFailWith ExprDoesNotHaveType
12module Main where
23
34import Prelude
45
6+foreign import (!!) :: forall a. Array a -> Int -> a
7+
58test = \arr -> arr !! (0 !! 0)
examples/failing/CaseDoesNotMatchAllConstructorArgs.pursnew file+15
@@ -0,0 +1,15 @@
1+-- @shouldFailWith IncorrectConstructorArity
2+module Main where
3+
4+import Prelude
5+
6+data Person = Person String Int
7+
8+data TwoPeople = Two Person Person
9+
10+getName p = case p of
11+ (Two (Person n) (Person n2 a2)) -> n
12+ _ -> "Unknown"
13+
14+
15+name = getName (Two (Person "Jimmy" 20) (Person "" 1))
examples/failing/Do.purs+2
@@ -1,3 +1,5 @@
1+-- @shouldFailWith InvalidDoBind
2+-- @shouldFailWith InvalidDoLet
13module Main where
24
35import Prelude
examples/failing/DoNotSuggestComposition.pursnew file+13
@@ -0,0 +1,13 @@
1+-- @shouldFailWith TypesDoNotUnify
2+-- TODO: Check that this does not produce a "function composition is (<<<)"
3+-- suggestion.
4+module DoNotSuggestComposition where
5+
6+import Prelude
7+
8+x = { y: 3 }
9+
10+foo :: String -> String
11+foo y = y
12+
13+bar = foo x
examples/failing/DoNotSuggestComposition2.pursnew file+7
@@ -0,0 +1,7 @@
1+-- @shouldFailWith CannotApplyFunction
2+-- TODO: Check that this does not produce a "function composition is (<<<)"
3+-- suggestion.
4+
5+module DoNotSuggestComposition2 where
6+
7+foo = let x = { y: 3 } in x 2
examples/failing/DuplicateDeclarationsInLet.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith OverlappingNamesInLet
12module Main where
23
34import Prelude
examples/failing/DuplicateProperties1.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith TypesDoNotUnify
12module DuplicateProperties where
23
34import Prelude
examples/failing/DuplicateProperties2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith DuplicateLabel
12module DuplicateProperties where
23
34import Prelude
examples/failing/DuplicateTypeVars.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith DuplicateTypeArgument
12module Main where
23
34import Prelude
examples/failing/Eff.purs+3−2
@@ -1,12 +1,13 @@
1+-- @shouldFailWith TypesDoNotUnify
12module Main where
23
34import Prelude
45import Control.Monad.Eff
56import Control.Monad.ST
6−import Debug.Trace
7+import Control.Monad.Eff.Console
78
89test = pureST (do
910 ref <- newSTRef 0
10− trace "ST"
11+ log "ST"
1112 modifySTRef ref $ \n -> n + 1
1213 readSTRef ref)
examples/failing/ExtraRecordField.pursnew file+10
@@ -0,0 +1,10 @@
1+-- @shouldFailWith PropertyIsMissing
2+-- TODO: Make this fail with a new error ExtraProperty instead.
3+module ExtraRecordField where
4+
5+import Prelude ((<>))
6+
7+full :: { first :: String, last :: String } -> String
8+full p = p.first <> " " <> p.last
9+
10+oops = full { first: "Jane", last: "Smith", age: 29 }
examples/failing/Foldable.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInDeclaration
12module Main where
23
34import Prelude
examples/failing/InfiniteKind.pursnew file+5
@@ -0,0 +1,5 @@
1+-- @shouldFailWith InfiniteKind
2+
3+module Main where
4+
5+data F a = F (a a)
examples/failing/InfiniteType.pursnew file+5
@@ -0,0 +1,5 @@
1+-- @shouldFailWith InfiniteType
2+
3+module Main where
4+
5+f a = a a
examples/failing/InstanceExport.purs+2
@@ -1,3 +1,4 @@
1+-- @shouldFailWith TransitiveExportError
12module InstanceExport (S(..), f) where
23
34import Prelude
@@ -13,5 +14,6 @@ instance fs :: F S where
1314module Test where
1415
1516import InstanceExport
17+import Prelude
1618
1719test = f $ S "Test"
examples/failing/KindError.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith KindsDoNotUnify
12module Main where
23
34import Prelude
examples/failing/LeadingZeros1.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
12module Main where
23
34import Prelude
examples/failing/LeadingZeros2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
12module Main where
23
34import Prelude
examples/failing/Let.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInDeclaration
12module Main where
23
34import Prelude
examples/failing/MPTCs.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith KindsDoNotUnify
12module Main where
23
34import Prelude
examples/failing/MissingClassExport.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith TransitiveExportError
12module Test (bar) where
23
34import Prelude
examples/failing/MissingClassMemberExport.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith TransitiveExportError
12module Test (Foo) where
23
34import Prelude
examples/failing/MissingRecordField.pursnew file+11
@@ -0,0 +1,11 @@
1+-- @shouldFailWith TypesDoNotUnify
2+-- TODO: Update type checker to make this fail with PropertyIsMissing instead.
3+module MissingRecordField where
4+
5+import Prelude ((>))
6+
7+john = { first: "John", last: "Smith" }
8+
9+isOver50 p = p.age > 50.0
10+
11+result = isOver50 john
examples/failing/MultipleErrors.purs+4−2
@@ -1,11 +1,13 @@
1+-- @shouldFailWith ExprDoesNotHaveType
2+-- @shouldFailWith ExprDoesNotHaveType
13module MultipleErrors where
24
35import Prelude
46
5−foo :: Number -> Number
7+foo :: Int -> Int
68foo 0 = "Test"
79foo n = bar (n - 1)
810
9−bar :: Number -> Number
11+bar :: Int -> Int
1012bar 0 = "Test"
1113bar n = foo (n - 1)
examples/failing/MultipleErrors2.purs+2
@@ -1,3 +1,5 @@
1+-- @shouldFailWith UnknownValue
2+-- @shouldFailWith UnknownValue
13module MultipleErrors2 where
24
35import Prelude
examples/failing/MutRec.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInDeclaration
12module MutRec where
23
34import Prelude
examples/failing/MutRec2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInDeclaration
12module Main where
23
34import Prelude
examples/failing/NewtypeMultiArgs.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith InvalidNewtype
12module Main where
23
34import Prelude
examples/failing/NewtypeMultiCtor.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith InvalidNewtype
12module Main where
23
34import Prelude
examples/failing/NoOverlap.pursdeleted−13
@@ -1,13 +0,0 @@
1−module Main where
2−
3−import Prelude
4−
5−data Foo = Foo
6−
7−instance showFoo1 :: Show Foo where
8− show _ = "Foo"
9−
10−instance showFoo2 :: Show Foo where
11− show _ = "Bar"
12−
13−test = show Foo
examples/failing/NullaryAbs.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
12module Main where
23
34import Prelude
examples/failing/Object.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith PropertyIsMissing
12module Main where
23
34import Prelude
examples/failing/OverlappingArguments.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith OverlappingArgNames
12module OverlappingArguments where
23
34import Prelude
examples/failing/OverlappingBinders.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith OverlappingArgNames
12module OverlappingBinders where
23
34import Prelude
examples/failing/OverlappingInstances.purs+2−1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith OverlappingInstances
12module OverlappingInstances where
23
34import Prelude
@@ -10,4 +11,4 @@ instance showA1 :: Show A where
1011instance showA2 :: Show A where
1112 show A = "Instance 2"
1213
13−main = Debug.Trace.trace $ show A
14+main = Control.Monad.Eff.Console.log $ show A
examples/failing/OverlappingInstances2.purs+6−7
@@ -1,3 +1,4 @@
1+-- @shouldFailWith OverlappingInstances
12module OverlappingInstances where
23
34import Prelude
@@ -5,14 +6,12 @@ import Prelude
56data A = A | B
67
78instance eqA1 :: Eq A where
8− (==) A A = true
9− (==) B B = true
10− (==) _ _ = false
11− (/=) x y = not (x == y)
9+ eq A A = true
10+ eq B B = true
11+ eq _ _ = false
1212
1313instance eqA2 :: Eq A where
14− (==) _ _ = true
15− (/=) _ _ = false
14+ eq _ _ = true
1615
1716instance ordA :: Ord A where
1817 compare A B = LT
@@ -22,4 +21,4 @@ instance ordA :: Ord A where
2221test :: forall a. (Ord a) => a -> a -> String
2322test x y = show $ x == y
2423
25−main = Debug.Trace.trace $ test A B
24+main = Control.Monad.Eff.Console.log $ test A B
examples/failing/OverlappingVars.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith NoInstanceFound
12module Main where
23
34import Prelude
examples/failing/Rank2Types.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ExprDoesNotHaveType
12module Main where
23
34import Prelude
examples/failing/Reserved.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
12module Main where
23
34import Prelude
examples/failing/RowConstructors1.purs+2−1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith KindsDoNotUnify
12module Main where
23
34import Prelude
@@ -5,4 +6,4 @@ import Prelude
56data Foo = Bar
67type Baz = { | Foo }
78
8−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/failing/RowConstructors2.purs+2−1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith KindsDoNotUnify
12module Main where
23
34import Prelude
@@ -5,4 +6,4 @@ import Prelude
56type Foo r = (x :: Number | r)
67type Bar = { | Foo }
78
8−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/failing/RowConstructors3.purs+2−1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith KindsDoNotUnify
12module Main where
23
34import Prelude
@@ -5,4 +6,4 @@ import Prelude
56type Foo = { x :: Number }
67type Bar = { | Foo }
78
8−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/failing/SkolemEscape.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith EscapedSkolem
12module Main where
23
34import Prelude
examples/failing/SkolemEscape2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith EscapedSkolem
12module Main where
23
34import Prelude
examples/failing/SuggestComposition.pursnew file+7
@@ -0,0 +1,7 @@
1+-- @shouldFailWith TypesDoNotUnify
2+-- TODO: Ensure the correct suggestion is produced.
3+module SuggestComposition where
4+
5+import Prelude
6+
7+f = g . g where g = (+1)
examples/failing/Superclasses1.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith NoInstanceFound
12module Main where
23
34import Prelude
examples/failing/Superclasses2.purs+2
@@ -1,3 +1,5 @@
1+-- @shouldFailWith CycleInTypeSynonym
2+-- TODO: Should this have its own error, perhaps CycleInTypeClassDeclaration?
13module CycleInSuperclasses where
24
35import Prelude
examples/failing/Superclasses3.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith UndefinedTypeVariable
12module UnknownSuperclassTypeVar where
23
34import Prelude
examples/failing/Superclasses4.purs+2−1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith OverlappingInstances
12module OverlappingInstances where
23
34import Prelude
@@ -11,4 +12,4 @@ instance foo2 :: Foo Number
1112test :: forall a. (Foo a) => a -> a
1213test a = a
1314
14−test1 = test 0
15+test1 = test 0.0
examples/failing/TopLevelCaseNoArgs.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith DuplicateValueDeclaration
12module Main where
23
34import Prelude
examples/failing/TypeClassInstances.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith MissingClassMember
12module Main where
23
34import Prelude
examples/failing/TypeClasses2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith NoInstanceFound
12module Main where
23
34import Prelude ()
examples/failing/TypeError.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ExprDoesNotHaveType
12module Main where
23
34import Prelude
examples/failing/TypeSynonyms.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInTypeSynonym
12module Main where
23
34import Prelude
examples/failing/TypeSynonyms2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith TypeSynonymInstance
12module Main where
23
34import Prelude
examples/failing/TypeSynonyms3.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith TypeSynonymInstance
12module Main where
23
34import Prelude
examples/failing/TypeSynonyms4.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith PartiallyAppliedSynonym
12module TypeSynonyms4 where
23
34import Prelude
examples/failing/TypeSynonyms5.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith CycleInTypeSynonym
12module Main where
23
34import Prelude
examples/failing/TypeWildcards1.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
12module TypeWildcards where
23
34import Prelude
examples/failing/TypeWildcards2.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
12module TypeWildcards where
23
34import Prelude
examples/failing/TypeWildcards3.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith ErrorParsingModule
12module TypeWildcards where
23
34import Prelude
examples/failing/UnderscoreModuleName.purs+2−1
@@ -1,5 +1,6 @@
1+-- @shouldFailWith ErrorParsingModule
12module Bad_Module where
23
34import Prelude
45
5−main = Debug.Trace.trace "Done"
6+main = Control.Monad.Eff.Console.log "Done"
examples/failing/UnifyInTypeInstanceLookup.purs+3
@@ -1,3 +1,6 @@
1+-- @shouldFailWith NoInstanceFound
2+-- See issue #390.
3+-- TODO: Improve this error.
14module Main where
25
36import Prelude
examples/failing/UnknownType.purs+1
@@ -1,3 +1,4 @@
1+-- @shouldFailWith UnknownType
12module Main where
23
34import Prelude
examples/manual/QualifiedNames.purs+1−1
@@ -10,4 +10,4 @@ either :: forall a b c. (a -> c) -> (b -> c) -> Data.Either.Either a b -> c
1010either f _ (Data.Either.Left x) = f x
1111either _ g (Data.Either.Right y) = g y
1212
13−main = Debug.Trace.trace (either id id (Data.Either.Left "Done"))
13+main = Control.Monad.Eff.Console.log (either id id (Data.Either.Left "Done"))
examples/manual/failing/ExportExplicit1.purs+1−1
@@ -11,4 +11,4 @@ module Main where
1111 -- should fail as Y constructor is not exported from M1
1212 testY = Y
1313
14− main = Debug.Trace.trace "Done"
14+ main = Control.Monad.Eff.Console.log "Done"
examples/manual/failing/ExportExplicit3.purs+1−1
@@ -10,4 +10,4 @@ module Main where
1010 -- should fail as Z is not exported from M1
1111 testZ = M1.Z
1212
13− main = Debug.Trace.trace "Done"
13+ main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/ExportExplicit.purs+1−1
@@ -17,4 +17,4 @@ module Main where
1717 testZ = Z
1818 testFoo = foo
1919
20− main = Debug.Trace.trace "Done"
20+ main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/ExportExplicit2.purs+1−1
@@ -12,4 +12,4 @@ module Main where
1212
1313 testBar = bar
1414
15− main = Debug.Trace.trace "Done"
15+ main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/Import.purs+1−1
@@ -16,4 +16,4 @@ module M2 where
1616
1717module Main where
1818
19−main = Debug.Trace.trace "Done"
19+main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/ImportExplicit.purs+1−1
@@ -11,4 +11,4 @@ module Main where
1111 testX = X
1212 testY = Y
1313
14− main = Debug.Trace.trace "Done"
14+ main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/ImportQualified.purs+3−3
@@ -1,12 +1,12 @@
11module M1 where
22
3− trace x = x
3+ log x = x
44
55module Main where
66
77 import Prelude
88 import Control.Monad.Eff
99 import M1
10− import qualified Debug.Trace as T
10+ import qualified Control.Monad.Eff.Console as C
1111
12− main = T.trace (trace "Done")
12+ main = C.log (log "Done")
examples/manual/passing/Module.purs+1−1
@@ -25,4 +25,4 @@ module M2 where
2525
2626module Main where
2727
28−main = Debug.Trace.trace "Done"
28+main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/ModuleDeps.purs+1−1
@@ -14,4 +14,4 @@ baz = 1
1414
1515module Main where
1616
17−main = Debug.Trace.trace "Done"
17+main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/RedefinedFixity.purs+1−1
@@ -21,4 +21,4 @@ import M2
2121
2222module Main where
2323
24−main = Debug.Trace.trace "Done"
24+main = Control.Monad.Eff.Console.log "Done"
examples/manual/passing/ShadowedName.purs+2−2
@@ -1,10 +1,10 @@
11module Main where
22
33import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
55
66done :: String
77done = let str = "Not yet done" in
88 let str = "Done" in str
99
10−main = Debug.Trace.trace done
10+main = Control.Monad.Eff.Console.log done
examples/manual/passing/TransitiveImport.purs+1−1
@@ -16,7 +16,7 @@ module Main where
1616
1717 import Prelude
1818 import Middle
19− import Debug.Trace
19+ import Control.Monad.Eff.Console
2020
2121 main = do
2222 print (middle unit)
examples/manual/passing/WildcardType.purs+2−2
@@ -1,7 +1,7 @@
11module Main where
22
33import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
55
66f1 :: (_ -> _) -> _
77f1 g = g 1
@@ -9,5 +9,5 @@ f1 g = g 1
99f2 :: _ -> _
1010f2 _ = "Done"
1111
12−main = Debug.Trace.trace $ f1 f2
12+main = Control.Monad.Eff.Console.log $ f1 f2
1313
examples/passing/652.purs+1−1
@@ -14,4 +14,4 @@ instance bar :: Bar (a -> b) b
1414
1515instance baz :: (Eq a) => Baz (a -> b) a b
1616
17−main = Debug.Trace.trace "Done"
17+main = Control.Monad.Eff.Console.log "Done"
examples/passing/810.purs+1−1
@@ -10,4 +10,4 @@ test m = o.x
1010 o = case m of Nothing -> { x : Nothing }
1111 Just a -> { x : Just a }
1212
13−main = Debug.Trace.trace "Done"
13+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Applicative.purs+4−4
@@ -4,13 +4,13 @@ import Prelude ()
44
55class Applicative f where
66 pure :: forall a. a -> f a
7− (<*>) :: forall a b. f (a -> b) -> f a -> f b
7+ apply :: forall a b. f (a -> b) -> f a -> f b
88
99data Maybe a = Nothing | Just a
1010
1111instance applicativeMaybe :: Applicative Maybe where
1212 pure = Just
13− (<*>) (Just f) (Just a) = Just (f a)
14− (<*>) _ _ = Nothing
13+ apply (Just f) (Just a) = Just (f a)
14+ apply _ _ = Nothing
1515
16−main = Debug.Trace.trace "Done"
16+main = Control.Monad.Eff.Console.log "Done"
examples/passing/ArrayType.purs+1−1
@@ -8,4 +8,4 @@ class Pointed p where
88instance pointedArray :: Pointed Array where
99 point a = [a]
1010
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Auto.purs+1−1
@@ -12,4 +12,4 @@ exists = \state step f -> f (Auto { state: state, step: step })
1212run :: forall i o. SomeAuto i o -> i -> o
1313run = \s i -> s (\a -> case a of Auto a -> a.step a.state i)
1414
15−main = Debug.Trace.trace "Done"
15+main = Control.Monad.Eff.Console.log "Done"
examples/passing/AutoPrelude.purs+2−2
@@ -1,9 +1,9 @@
11module Main where
22
33import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
55
66f x = x * 10.0
77g y = y - 10.0
88
9−main = trace $ show $ (f <<< g) 100.0
9+main = log $ show $ (f <<< g) 100.0
examples/passing/AutoPrelude2.purs+2−2
@@ -2,9 +2,9 @@ module Main where
22
33import Prelude
44import qualified Prelude as P
5−import Debug.Trace
5+import Control.Monad.Eff.Console
66
77f :: forall a. a -> a
88f = P.id
99
10−main = P.($) trace ((f P.<<< f) "Done")
10+main = P.($) log ((f P.<<< f) "Done")
examples/passing/BindersInFunctions.purs+5−6
@@ -1,12 +1,11 @@
11module Main where
22
33import Prelude
4−import Assert
4+import Test.Assert
55
66snd = \[_, y] -> y
77
8−main =
9− let ts = snd [1.0, 2.0] in
10− if ts == 2.0
11− then Debug.Trace.trace "Done"
12− else error "Incorrect result from 'snd'."
8+main = do
9+ let ts = snd [1.0, 2.0]
10+ assert' "Incorrect result from 'snd'." (ts == 2.0)
11+ Control.Monad.Eff.Console.log "Done"
examples/passing/BindingGroups.purs+1−1
@@ -7,4 +7,4 @@ foo = bar
77
88r = foo 2.0
99
10−main = Debug.Trace.trace "Done"
10+main = Control.Monad.Eff.Console.log "Done"
examples/passing/BlockString.purs+1−1
@@ -5,4 +5,4 @@ import Prelude
55foo :: String
66foo = """foo"""
77
8−main = Debug.Trace.trace "Done"
8+main = Control.Monad.Eff.Console.log "Done"
examples/passing/CaseInDo.purs+3−3
@@ -1,14 +1,14 @@
11module Main where
22
33import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
55import Control.Monad.Eff
66
77doIt :: forall eff. Eff eff Boolean
88doIt = return true
99
1010set = do
11− trace "Testing..."
11+ log "Testing..."
1212 case 0 of
1313 0 -> doIt
1414 _ -> return false
@@ -16,4 +16,4 @@ set = do
1616main = do
1717 b <- set
1818 case b of
19− true -> trace "Done"
19+ true -> log "Done"
examples/passing/CaseStatement.purs+1−1
@@ -18,4 +18,4 @@ h f N a = a
1818h f a N = a
1919h f (J a) (J b) = J (f a b)
2020
21−main = Debug.Trace.trace $ f "Done" "Failed" A
21+main = Control.Monad.Eff.Console.log $ f "Done" "Failed" A
examples/passing/CheckFunction.purs+1−1
@@ -4,4 +4,4 @@ import Prelude
44
55test = ((\x -> x+1.0) >>> (\x -> x*2.0)) 4.0
66
7−main = Debug.Trace.trace "Done"
7+main = Control.Monad.Eff.Console.log "Done"
examples/passing/CheckSynonymBug.purs+4−1
@@ -2,8 +2,11 @@ module Main where
22
33import Prelude
44
5+length :: forall a. Array a -> Int
6+length _ = 0
7+
58type Foo a = Array a
69
710foo _ = length ([] :: Foo Number)
811
9−main = Debug.Trace.trace "Done"
12+main = Control.Monad.Eff.Console.log "Done"
examples/passing/CheckTypeClass.purs+1−1
@@ -14,5 +14,5 @@ foo_ x = foo ((mkBar :: forall a. (Foo a) => a -> Bar a) x)
1414mkBar :: forall a. a -> Bar a
1515mkBar _ = Bar
1616
17−main = Debug.Trace.trace "Done"
17+main = Control.Monad.Eff.Console.log "Done"
1818
examples/passing/Church.purs+1−1
@@ -15,4 +15,4 @@ append = \l1 l2 r f -> l2 (l1 r f) f
1515
1616test = append (cons 1 empty) (cons 2 empty)
1717
18−main = Debug.Trace.trace "Done"
18+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Collatz.purs+6−6
@@ -4,15 +4,15 @@ import Prelude
44import Control.Monad.Eff
55import Control.Monad.ST
66
7−collatz :: Number -> Number
7+collatz :: Int -> Int
88collatz n = runPure (runST (do
99 r <- newSTRef n
10− count <- newSTRef 0.0
10+ count <- newSTRef 0
1111 untilE $ do
12− modifySTRef count $ (+) 1.0
12+ modifySTRef count $ (+) 1
1313 m <- readSTRef r
14− writeSTRef r $ if m % 2.0 == 0.0 then m / 2.0 else 3.0 * m + 1.0
15− return $ m == 1.0
14+ writeSTRef r $ if m `mod` 2 == 0 then m / 2 else 3 * m + 1
15+ return $ m == 1
1616 readSTRef count))
1717
18−main = Debug.Trace.print $ collatz 1000.0
18+main = Control.Monad.Eff.Console.print $ collatz 1000
examples/passing/Comparisons.purs+3−3
@@ -2,8 +2,8 @@ module Main where
22
33import Prelude
44import Control.Monad.Eff
5−import Debug.Trace
6−import Assert
5+import Control.Monad.Eff.Console
6+import Test.Assert
77
88main = do
99 assert (1.0 < 2.0)
@@ -12,4 +12,4 @@ main = do
1212 assert ("a" < "b")
1313 assert ("a" == "a")
1414 assert ("z" > "a")
15− trace "Done!"
15+ log "Done!"
examples/passing/Conditional.purs+1−1
@@ -6,4 +6,4 @@ fns = \f -> if f true then f else \x -> x
66
77not = \x -> if x then false else true
88
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Console.purs+2−2
@@ -2,7 +2,7 @@ module Main where
22
33import Prelude
44import Control.Monad.Eff
5−import Debug.Trace
5+import Control.Monad.Eff.Console
66
77replicateM_ :: forall m a. (Monad m) => Number -> m a -> m {}
88replicateM_ 0.0 _ = return {}
@@ -10,4 +10,4 @@ replicateM_ n act = do
1010 act
1111 replicateM_ (n - 1.0) act
1212
13−main = replicateM_ 10.0 (trace "Hello World!")
13+main = replicateM_ 10.0 (log "Hello World!")
examples/passing/DataAndType.purs+1−1
@@ -6,4 +6,4 @@ data A = A B
66
77type B = A
88
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/DeepArrayBinder.purs+5−4
@@ -2,7 +2,7 @@ module Main where
22
33import Prelude
44import Control.Monad.Eff
5−import Assert
5+import Test.Assert
66
77data List a = Cons a (List a) | Nil
88
@@ -10,6 +10,7 @@ match2 :: List Number -> Number
1010match2 (Cons x (Cons y xs)) = x * y + match2 xs
1111match2 _ = 0.0
1212
13−main = case match2 (Cons 1.0 (Cons 2.0 (Cons 3.0 (Cons 4.0 (Cons 5.0 (Cons 6.0 (Cons 7.0 (Cons 8.0 (Cons 9.0 Nil))))))))) of
14− 100.0 -> Debug.Trace.trace "Done"
15− _ -> error "Incorrect result!"
13+main = do
14+ let result = match2 (Cons 1.0 (Cons 2.0 (Cons 3.0 (Cons 4.0 (Cons 5.0 (Cons 6.0 (Cons 7.0 (Cons 8.0 (Cons 9.0 Nil)))))))))
15+ assert' "Incorrect result!" (result == 100.0)
16+ Control.Monad.Eff.Console.log "Done"
examples/passing/DeepCase.purs+1−1
@@ -1,7 +1,7 @@
11module Main where
22
33import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
55import Control.Monad.Eff
66import Control.Monad.ST
77
examples/passing/Do.purs+7−7
@@ -5,19 +5,19 @@ import Prelude
55data Maybe a = Nothing | Just a
66
77instance functorMaybe :: Functor Maybe where
8− (<$>) f Nothing = Nothing
9− (<$>) f (Just x) = Just (f x)
8+ map f Nothing = Nothing
9+ map f (Just x) = Just (f x)
1010
1111instance applyMaybe :: Apply Maybe where
12− (<*>) (Just f) (Just x) = Just (f x)
13− (<*>) _ _ = Nothing
12+ apply (Just f) (Just x) = Just (f x)
13+ apply _ _ = Nothing
1414
1515instance applicativeMaybe :: Applicative Maybe where
1616 pure = Just
1717
1818instance bindMaybe :: Bind Maybe where
19− (>>=) Nothing _ = Nothing
20− (>>=) (Just a) f = f a
19+ bind Nothing _ = Nothing
20+ bind (Just a) f = f a
2121
2222instance monadMaybe :: Prelude.Monad Maybe
2323
@@ -64,4 +64,4 @@ test10 _ = do
6464 g x = f x / 2.0
6565 Just (f 10.0)
6666
67−main = Debug.Trace.trace "Done"
67+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Dollar.purs+1−1
@@ -13,4 +13,4 @@ test1 x = id $ id $ id $ id $ x
1313
1414test2 x = id id $ id x
1515
16−main = Debug.Trace.trace "Done"
16+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Eff.purs+5−5
@@ -3,11 +3,11 @@ module Main where
33import Prelude
44import Control.Monad.Eff
55import Control.Monad.ST
6−import Debug.Trace
6+import Control.Monad.Eff.Console
77
88test1 = do
9− trace "Line 1"
10− trace "Line 2"
9+ log "Line 1"
10+ log "Line 2"
1111
1212test2 = runPure (runST (do
1313 ref <- newSTRef 0.0
@@ -21,5 +21,5 @@ test3 = pureST (do
2121
2222main = do
2323 test1
24− Debug.Trace.print test2
25− Debug.Trace.print test3
24+ Control.Monad.Eff.Console.print test2
25+ Control.Monad.Eff.Console.print test3
examples/passing/EmptyDataDecls.purs+4−4
@@ -1,7 +1,7 @@
11module Main where
22
33import Prelude
4−import Assert
4+import Test.Assert
55
66data Z
77data S n
@@ -12,8 +12,8 @@ nil :: forall a. ArrayBox Z a
1212nil = ArrayBox []
1313
1414cons' :: forall a n. a -> ArrayBox n a -> ArrayBox (S n) a
15−cons' x (ArrayBox xs) = ArrayBox $ concat [x] xs
15+cons' x (ArrayBox xs) = ArrayBox $ append [x] xs
1616
1717main = case cons' 1 $ cons' 2 $ cons' 3 nil of
18− ArrayBox [1, 2, 3] -> Debug.Trace.trace "Done"
19− _ -> error "Failed"
18+ ArrayBox [1, 2, 3] -> Control.Monad.Eff.Console.log "Done"
19+ _ -> assert' "Failed" false
examples/passing/EmptyRow.purs+1−1
@@ -7,4 +7,4 @@ data Foo r = Foo { | r }
77test :: Foo ()
88test = Foo {}
99
10−main = Debug.Trace.trace "Done"
10+main = Control.Monad.Eff.Console.log "Done"
examples/passing/EmptyTypeClass.purs+1−1
@@ -9,4 +9,4 @@ head [x] = x
99
1010instance allowPartials :: Partial
1111
12−main = Debug.Trace.trace $ head ["Done"]
12+main = Control.Monad.Eff.Console.log $ head ["Done"]
examples/passing/EqOrd.purs+2−3
@@ -10,7 +10,6 @@ instance ordPair :: (Ord a, Ord b) => Ord (Pair a b) where
1010 r -> r
1111
1212instance eqPair :: (Eq a, Eq b) => Eq (Pair a b) where
13− (==) (Pair a1 b1) (Pair a2 b2) = a1 == a2 && b1 == b2
14− (/=) (Pair a1 b1) (Pair a2 b2) = a1 /= a2 || b1 /= b2
13+ eq (Pair a1 b1) (Pair a2 b2) = a1 == a2 && b1 == b2
1514
16−main = Debug.Trace.print $ Pair 1.0 2.0 == Pair 1.0 2.0
15+main = Control.Monad.Eff.Console.print $ Pair 1.0 2.0 == Pair 1.0 2.0
examples/passing/ExtendedInfixOperators.purs+1−1
@@ -11,4 +11,4 @@ null _ = false
1111test = [1.0, 2.0, 3.0] `comparing null` [4.0, 5.0, 6.0]
1212
1313main = do
14− Debug.Trace.print test
14+ Control.Monad.Eff.Console.print test
examples/passing/Fib.purs+1−1
@@ -12,4 +12,4 @@ main = runST (do
1212 n2' <- readSTRef n2
1313 writeSTRef n2 $ n1' + n2'
1414 writeSTRef n1 n2'
15− Debug.Trace.print n2')
15+ Control.Monad.Eff.Console.print n2')
examples/passing/FinalTagless.purs+2−2
@@ -1,6 +1,6 @@
11module Main where
22
3−import Prelude
3+import Prelude hiding (add)
44
55class E e where
66 num :: Number -> e Number
@@ -19,4 +19,4 @@ runId (Id a) = a
1919three :: Expr Number
2020three = add (num 1.0) (num 2.0)
2121
22−main = Debug.Trace.print $ runId three
22+main = Control.Monad.Eff.Console.print $ runId three
examples/passing/FunctionScope.purs+3−4
@@ -1,13 +1,12 @@
11module Main where
22
33import Prelude
4−import Assert
4+import Test.Assert
55
66mkValue :: Number -> Number
77mkValue id = id
88
99main = do
1010 let value = mkValue 1.0
11− if value == 1.0
12− then Debug.Trace.trace "Done"
13− else error "Not done"
11+ assert $ value == 1.0
12+ Control.Monad.Eff.Console.log "Done"
examples/passing/Functions.purs+1−1
@@ -12,4 +12,4 @@ test4 = \(%%) -> 1.0 %% 2.0
1212
1313test5 = \(+++) (***) -> 1.0 +++ 2.0 *** 3.0
1414
15−main = Debug.Trace.trace "Done"
15+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Functions2.purs+3−4
@@ -1,13 +1,12 @@
11module Main where
22
33import Prelude
4−import Assert
4+import Test.Assert
55
66test :: forall a b. a -> b -> a
77test = \const _ -> const
88
99main = do
1010 let value = test "Done" {}
11− if value == "Done"
12− then Debug.Trace.trace "Done"
13− else error "Not done"
11+ assert' "Not done" $ value == "Done"
12+ Control.Monad.Eff.Console.log "Done"
examples/passing/Guards.purs+2−2
@@ -3,7 +3,7 @@ module Main where
33import Prelude
44
55collatz = \x -> case x of
6− y | y % 2.0 == 0.0 -> y / 2.0
6+ y | y `mod` 2.0 == 0.0 -> y / 2.0
77 y -> y * 3.0 + 1.0
88
99-- Guards have access to current scope
@@ -26,4 +26,4 @@ testIndentation x y | x > 0.0
2626 | otherwise
2727 = y - x
2828
29−main = Debug.Trace.trace $ min "Done" "ZZZZ"
29+main = Control.Monad.Eff.Console.log $ min "Done" "ZZZZ"
examples/passing/HoistError.purs+3−3
@@ -2,11 +2,11 @@ module Main where
22
33import Prelude
44import Control.Monad.Eff
5−import Debug.Trace
6−import Assert
5+import Control.Monad.Eff.Console
6+import Test.Assert
77
88main = do
99 let x = 0.0
1010 assert $ x == 0.0
1111 let x = 1.0 + 1.0
12− trace "Done"
12+ log "Done"
examples/passing/IfThenElseMaybe.purs+1−1
@@ -8,4 +8,4 @@ test1 = if true then Just 10 else Nothing
88
99test2 = if true then Nothing else Just 10
1010
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/ImplicitEmptyImport.purs+3−3
@@ -3,6 +3,6 @@ module Main where
33import Prelude
44
55main = do
6− Debug.Trace.trace "Hello"
7− Debug.Trace.trace "Goodbye"
8− Debug.Trace.trace "Done"
6+ Control.Monad.Eff.Console.log "Hello"
7+ Control.Monad.Eff.Console.log "Goodbye"
8+ Control.Monad.Eff.Console.log "Done"
examples/passing/ImportHiding.purs+1−1
@@ -1,6 +1,6 @@
11module Main where
22
3−import Debug.Trace
3+import Control.Monad.Eff.Console
44import Prelude hiding (
55 show, -- a value
66 Show, -- a type class
examples/passing/InferRecFunWithConstrainedArgument.purs+1−1
@@ -5,4 +5,4 @@ import Prelude
55test 100.0 = 100.0
66test n = test(1.0 + n)
77
8−main = Debug.Trace.print $ test 0.0
8+main = Control.Monad.Eff.Console.print $ test 0.0
examples/passing/InstanceBeforeClass.purs+1−1
@@ -8,4 +8,4 @@ instance fooNumber :: Foo Number where
88class Foo a where
99 foo :: a
1010
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/IntAndChar.purs+2−2
@@ -2,7 +2,7 @@ module Main where
22
33import Prelude
44import Control.Monad.Eff
5−import Assert
5+import Test.Assert
66
77f 1 = 1
88f _ = 0
@@ -15,4 +15,4 @@ main = do
1515 assert $ f 0 == 0
1616 assert $ g 'a' == 'a'
1717 assert $ g 'b' == 'b'
18− Debug.Trace.trace "Done"
18+ Control.Monad.Eff.Console.log "Done"
examples/passing/JSReserved.purs+1−1
@@ -9,4 +9,4 @@ public = \return -> return
99
1010this catch = catch
1111
12−main = Debug.Trace.trace "Done"
12+main = Control.Monad.Eff.Console.log "Done"
examples/passing/KindedType.purs+1−1
@@ -30,4 +30,4 @@ class Clazz (a :: *) where
3030instance clazzString :: Clazz String where
3131 def = "test"
3232
33−main = Debug.Trace.trace "Done"
33+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Let.purs+7−7
@@ -44,10 +44,10 @@ test10 _ =
4444 in f 10.0
4545
4646main = do
47− Debug.Trace.print (test1 1.0)
48− Debug.Trace.print (test2 1.0 2.0)
49− Debug.Trace.print test3
50− Debug.Trace.print test4
51− Debug.Trace.print test5
52− Debug.Trace.print test7
53− Debug.Trace.print (test8 100.0)
47+ Control.Monad.Eff.Console.print (test1 1.0)
48+ Control.Monad.Eff.Console.print (test2 1.0 2.0)
49+ Control.Monad.Eff.Console.print test3
50+ Control.Monad.Eff.Console.print test4
51+ Control.Monad.Eff.Console.print test5
52+ Control.Monad.Eff.Console.print test7
53+ Control.Monad.Eff.Console.print (test8 100.0)
examples/passing/Let2.purs+1−1
@@ -14,4 +14,4 @@ test =
1414 x = f 1.0
1515 in not x
1616
17−main = Debug.Trace.print test
17+main = Control.Monad.Eff.Console.print test
examples/passing/LetInInstance.purs+1−1
@@ -11,4 +11,4 @@ instance fooString :: Foo String where
1111 go :: String -> String
1212 go s = s
1313
14−main = Debug.Trace.trace "Done"
14+main = Control.Monad.Eff.Console.log "Done"
examples/passing/LiberalTypeSynonyms.purs+1−1
@@ -18,4 +18,4 @@ f :: (forall r. F r) -> String
1818f g = case g { x: "Hello" } of
1919 { x = x } -> x
2020
21−main = Debug.Trace.trace "Done"
21+main = Control.Monad.Eff.Console.log "Done"
examples/passing/MPTCs.purs+1−1
@@ -17,4 +17,4 @@ instance coerceRefl :: Coerce a a where
1717instance coerceShow :: (Prelude.Show a) => Coerce a String where
1818 coerce = show
1919
20−main = Debug.Trace.trace "Done"
20+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Match.purs+1−1
@@ -6,4 +6,4 @@ data Foo a = Foo
66
77foo = \f -> case f of Foo -> "foo"
88
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/ModuleExport.pursnew file+9
@@ -0,0 +1,9 @@
1+module A (module Prelude) where
2+ import Prelude
3+
4+module Main where
5+ import Control.Monad.Eff.Console
6+ import A
7+
8+ main = do
9+ print (show 1.0)
examples/passing/ModuleExportDupes.pursnew file+19
@@ -0,0 +1,19 @@
1+module A (module Prelude) where
2+ import Prelude
3+
4+module B (module Prelude) where
5+ import Prelude
6+
7+module C (module Prelude, module A) where
8+ import Prelude
9+ import A
10+
11+module Main where
12+ import Control.Monad.Eff.Console
13+ import A
14+ import B
15+ import C
16+ import Prelude
17+
18+ main = do
19+ print (show 1.0)
examples/passing/ModuleExportExcluded.pursnew file+14
@@ -0,0 +1,14 @@
1+module A (module Prelude, foo) where
2+ import Prelude
3+
4+ foo :: Number -> Number
5+ foo _ = 0.0
6+
7+module Main where
8+ import Control.Monad.Eff.Console
9+ import A (foo)
10+
11+ otherwise = false
12+
13+ main = do
14+ print "1.0"
examples/passing/ModuleExportHiding.pursnew file+11
@@ -0,0 +1,11 @@
1+module A (module Prelude) where
2+ import Prelude
3+
4+module Main where
5+ import Control.Monad.Eff.Console
6+ import A hiding (module Prelude)
7+
8+ otherwise = false
9+
10+ main = do
11+ print "1.0"
examples/passing/ModuleExportQualified.pursnew file+9
@@ -0,0 +1,9 @@
1+module A (module Prelude) where
2+ import Prelude
3+
4+module Main where
5+ import Control.Monad.Eff.Console
6+ import qualified A as B
7+
8+ main = do
9+ print (B.show 1.0)
examples/passing/ModuleExportSelf.pursnew file+14
@@ -0,0 +1,14 @@
1+module A (module A, module Prelude) where
2+ import Prelude
3+
4+ type Foo = Boolean
5+
6+module Main where
7+ import Control.Monad.Eff.Console
8+ import A
9+
10+ bar :: Foo
11+ bar = true
12+
13+ main = do
14+ print (show bar)
examples/passing/Monad.purs+1−1
@@ -29,4 +29,4 @@ test1 = test id
2929
3030test2 = test maybe
3131
32−main = Debug.Trace.trace "Done"
32+main = Control.Monad.Eff.Console.log "Done"
examples/passing/MonadState.purs+4−4
@@ -13,16 +13,16 @@ data State s a = State (s -> Tuple s a)
1313runState s (State f) = f s
1414
1515instance functorState :: Functor (State s) where
16− (<$>) = liftM1
16+ map = liftM1
1717
1818instance applyState :: Apply (State s) where
19− (<*>) = ap
19+ apply = ap
2020
2121instance applicativeState :: Applicative (State s) where
2222 pure a = State $ \s -> Tuple s a
2323
2424instance bindState :: Bind (State s) where
25− (>>=) f g = State $ \s -> case runState s f of
25+ bind f g = State $ \s -> case runState s f of
2626 Tuple s1 a -> runState s1 (g a)
2727
2828instance monadState :: Monad (State s)
@@ -44,5 +44,5 @@ test = runState "" $ do
4444
4545main = do
4646 let t1 = test
47− Debug.Trace.trace "Done"
47+ Control.Monad.Eff.Console.log "Done"
4848
examples/passing/MultiArgFunctions.purs+13−13
@@ -3,7 +3,7 @@ module Main where
33import Prelude
44import Data.Function
55import Control.Monad.Eff
6−import Debug.Trace
6+import Control.Monad.Eff.Console
77
88f = mkFn2 $ \a b -> runFn2 g a b + runFn2 g b a
99
@@ -12,16 +12,16 @@ g = mkFn2 $ \a b -> case {} of
1212 _ -> runFn2 f (a - 0.0) (b - 0.0)
1313
1414main = do
15− runFn0 (mkFn0 $ \_ -> trace $ show 0.0)
16− runFn1 (mkFn1 $ \a -> trace $ show a) 0.0
17− runFn2 (mkFn2 $ \a b -> trace $ show [a, b]) 0.0 0.0
18− runFn3 (mkFn3 $ \a b c -> trace $ show [a, b, c]) 0.0 0.0 0.0
19− runFn4 (mkFn4 $ \a b c d -> trace $ show [a, b, c, d]) 0.0 0.0 0.0 0.0
20− runFn5 (mkFn5 $ \a b c d e -> trace $ show [a, b, c, d, e]) 0.0 0.0 0.0 0.0 0.0
21− runFn6 (mkFn6 $ \a b c d e f -> trace $ show [a, b, c, d, e, f]) 0.0 0.0 0.0 0.0 0.0 0.0
22− runFn7 (mkFn7 $ \a b c d e f g -> trace $ show [a, b, c, d, e, f, g]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0
23− runFn8 (mkFn8 $ \a b c d e f g h -> trace $ show [a, b, c, d, e, f, g, h]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
24− runFn9 (mkFn9 $ \a b c d e f g h i -> trace $ show [a, b, c, d, e, f, g, h, i]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
25− runFn10 (mkFn10 $ \a b c d e f g h i j-> trace $ show [a, b, c, d, e, f, g, h, i, j]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
15+ runFn0 (mkFn0 $ \_ -> log $ show 0.0)
16+ runFn1 (mkFn1 $ \a -> log $ show a) 0.0
17+ runFn2 (mkFn2 $ \a b -> log $ show [a, b]) 0.0 0.0
18+ runFn3 (mkFn3 $ \a b c -> log $ show [a, b, c]) 0.0 0.0 0.0
19+ runFn4 (mkFn4 $ \a b c d -> log $ show [a, b, c, d]) 0.0 0.0 0.0 0.0
20+ runFn5 (mkFn5 $ \a b c d e -> log $ show [a, b, c, d, e]) 0.0 0.0 0.0 0.0 0.0
21+ runFn6 (mkFn6 $ \a b c d e f -> log $ show [a, b, c, d, e, f]) 0.0 0.0 0.0 0.0 0.0 0.0
22+ runFn7 (mkFn7 $ \a b c d e f g -> log $ show [a, b, c, d, e, f, g]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0
23+ runFn8 (mkFn8 $ \a b c d e f g h -> log $ show [a, b, c, d, e, f, g, h]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
24+ runFn9 (mkFn9 $ \a b c d e f g h i -> log $ show [a, b, c, d, e, f, g, h, i]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
25+ runFn10 (mkFn10 $ \a b c d e f g h i j-> log $ show [a, b, c, d, e, f, g, h, i, j]) 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
2626 print $ runFn2 g 0.0 0.0
27− trace "Done!"
27+ log "Done!"
examples/passing/MutRec.purs+1−1
@@ -16,4 +16,4 @@ evenToNumber (Even n) = oddToNumber n + 0.0
1616
1717oddToNumber (Odd n) = evenToNumber n + 0.0
1818
19−main = Debug.Trace.trace "Done"
19+main = Control.Monad.Eff.Console.log "Done"
examples/passing/MutRec2.purs+1−1
@@ -16,4 +16,4 @@ g b = case b of B a -> f a
1616showN :: A -> S
1717showN a = f a
1818
19−main = Debug.Trace.trace "Done"
19+main = Control.Monad.Eff.Console.log "Done"
examples/passing/MutRec3.purs+1−1
@@ -16,4 +16,4 @@ g b = case b of B a -> f a
1616showN :: A -> S
1717showN a = f a
1818
19−main = Debug.Trace.trace "Done"
19+main = Control.Monad.Eff.Console.log "Done"
examples/passing/NamedPatterns.purs+1−1
@@ -6,4 +6,4 @@ foo = \x -> case x of
66 y@{ foo = "Foo" } -> y
77 y -> y
88
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/NegativeBinder.purs+1−1
@@ -6,4 +6,4 @@ test :: Number -> Boolean
66test -1.0 = false
77test _ = true
88
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Nested.purs+1−1
@@ -6,4 +6,4 @@ data Extend r a = Extend { prev :: r a, next :: a }
66
77data Matrix r a = Square (r (r a)) | Bigger (Matrix (Extend r) a)
88
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/NestedTypeSynonyms.purs+1−1
@@ -8,4 +8,4 @@ type Y = X -> X
88fn :: Y
99fn a = a
1010
11−main = Debug.Trace.print (fn "Done")
11+main = Control.Monad.Eff.Console.print (fn "Done")
examples/passing/NestedWhere.purs+1−1
@@ -9,4 +9,4 @@ f x = g x
99 go x = go1 (x - 1.0)
1010 go1 x = go x
1111
12−main = Debug.Trace.trace "Done"
12+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Newtype.purs+3−3
@@ -1,8 +1,8 @@
11module Main where
22
3−import Prelude
3+import Prelude hiding (apply)
44import Control.Monad.Eff
5−import Debug.Trace
5+import Control.Monad.Eff.Console
66
77newtype Thing = Thing String
88
@@ -20,4 +20,4 @@ main = do
2020 print $ Thing "hello"
2121 print $ Box 42.0
2222 print $ apply Box 9000.0
23− trace "Done"
23+ log "Done"
examples/passing/NewtypeEff.purs+9−9
@@ -1,29 +1,29 @@
11module Main where
22
33import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
55import Control.Monad.Eff
66
7−newtype T a = T (Eff (trace :: Trace) a)
7+newtype T a = T (Eff (console :: CONSOLE) a)
88
9−runT :: forall a. T a -> Eff (trace :: Trace) a
9+runT :: forall a. T a -> Eff (console :: CONSOLE) a
1010runT (T t) = t
1111
1212instance functorT :: Functor T where
13− (<$>) f (T t) = T (f <$> t)
13+ map f (T t) = T (f <$> t)
1414
1515instance applyT :: Apply T where
16− (<*>) (T f) (T x) = T (f <*> x)
16+ apply (T f) (T x) = T (f <*> x)
1717
1818instance applicativeT :: Applicative T where
1919 pure t = T (pure t)
2020
2121instance bindT :: Bind T where
22− (>>=) (T t) f = T (t >>= \x -> runT (f x))
22+ bind (T t) f = T (t >>= \x -> runT (f x))
2323
2424instance monadT :: Monad T
2525
2626main = runT do
27− T $ trace "Done"
28− T $ trace "Done"
29− T $ trace "Done"
27+ T $ log "Done"
28+ T $ log "Done"
29+ T $ log "Done"
examples/passing/NewtypeWithRecordUpdate.purs+2−2
@@ -3,7 +3,7 @@
33module Main where
44
55import Prelude
6−import Debug.Trace
6+import Control.Monad.Eff.Console
77
88newtype NewType a = NewType (Object a)
99
@@ -13,4 +13,4 @@ rec1 = { a: 0.0, b: 0.0, c: 0.0 }
1313rec2 :: NewType (a :: Number, b :: Number, c :: Number)
1414rec2 = NewType (rec1 { a = 1.0 })
1515
16−main = trace "Done"
16+main = log "Done"
examples/passing/ObjectGetter.purs+4−4
@@ -7,7 +7,7 @@ getX = _.x
77point = { x: 1.0, y: 0.0 }
88
99main = do
10− Debug.Trace.print $ getX point
11− Debug.Trace.trace $ _." 123 string Prop Name " { " 123 string Prop Name ": "OK" }
12− Debug.Trace.trace $ (_.x >>> _.y) { x: { y: "Nested" } }
13− Debug.Trace.trace $ _.value { value: "Done!" }
10+ Control.Monad.Eff.Console.print $ getX point
11+ Control.Monad.Eff.Console.log $ _." 123 string Prop Name " { " 123 string Prop Name ": "OK" }
12+ Control.Monad.Eff.Console.log $ (_.x >>> _.y) { x: { y: "Nested" } }
13+ Control.Monad.Eff.Console.log $ _.value { value: "Done!" }
examples/passing/ObjectSynonym.purs+1−1
@@ -12,4 +12,4 @@ type Outer = { inner :: Inner }
1212outer :: Outer
1313outer = { inner: inner }
1414
15−main = Debug.Trace.trace "Done"
15+main = Control.Monad.Eff.Console.log "Done"
examples/passing/ObjectUpdate.purs+1−1
@@ -17,4 +17,4 @@ polyUpdate = \o -> o { foo = "Foo" }
1717
1818inferPolyUpdate = \o -> o { foo = "Foo" }
1919
20−main = Debug.Trace.trace ((update1 {foo: ""}).foo)
20+main = Control.Monad.Eff.Console.log ((update1 {foo: ""}).foo)
examples/passing/ObjectUpdate2.purs+1−1
@@ -14,4 +14,4 @@ test = blah x
1414 { baz = "blah"
1515 }
1616
17−main = Debug.Trace.trace "Done"
17+main = Control.Monad.Eff.Console.log "Done"
examples/passing/ObjectUpdater.purs+2−2
@@ -2,8 +2,8 @@ module Main where
22
33import Prelude
44import Control.Monad.Eff
5−import Debug.Trace
6−import Assert
5+import Control.Monad.Eff.Console
6+import Test.Assert
77
88getValue :: forall e. Eff (| e) Boolean
99getValue = return true
examples/passing/ObjectWildcards.purs+3−3
@@ -2,8 +2,8 @@ module Main where
22
33import Prelude
44import Control.Monad.Eff
5−import Debug.Trace
6−import Assert
5+import Control.Monad.Eff.Console
6+import Test.Assert
77
88mkRecord = { foo: _, bar: _, baz: "baz" }
99
@@ -17,4 +17,4 @@ main = do
1717 point <- { x: _, y: x } <$> return 2.0
1818 assert $ point.x == 2.0
1919 assert $ point.y == 1.0
20− trace (mkRecord 1.0 "Done!").bar
20+ log (mkRecord 1.0 "Done!").bar
examples/passing/Objects.purs+2−2
@@ -1,6 +1,6 @@
11module Main where
22
3−import Prelude
3+import Prelude hiding (append)
44
55test = \x -> x.foo + x.bar + 1.0
66
@@ -32,4 +32,4 @@ test6 = case { "***": 1.0 } of
3232
3333test7 {a: snoog , b : blah } = blah
3434
35−main = Debug.Trace.trace "Done"
35+main = Control.Monad.Eff.Console.log "Done"
examples/passing/OneConstructor.purs+1−1
@@ -6,4 +6,4 @@ data One a = One a
66
77one' (One a) = a
88
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/OperatorAssociativity.purs+3−3
@@ -2,8 +2,8 @@ module Main where
22
33import Prelude
44import Control.Monad.Eff
5−import Debug.Trace
6−import Assert
5+import Control.Monad.Eff.Console
6+import Test.Assert
77
88bug :: Number -> Number -> Number
99bug a b = 0.0 - (a - b)
@@ -22,4 +22,4 @@ main = do
2222 assert (1.0 + 10.0 - 5.0 == 6.0)
2323 assert (1.0 + 10.0 * 5.0 == 51.0)
2424 assert (10.0 * 5.0 - 1.0 == 49.0)
25− trace "Success!"
25+ log "Success!"
examples/passing/OperatorInlining.purs+1−1
@@ -1,7 +1,7 @@
11module Main where
22
33import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
55
66main = do
77
examples/passing/OperatorSections.purs+2−2
@@ -1,11 +1,11 @@
11module Main where
22
33import Prelude
4−import Assert
4+import Test.Assert
55
66main = do
77 assert $ (/ 2.0) 4.0 == 2.0
88 assert $ (2.0 /) 4.0 == 0.5
99 assert $ (`const` 1.0) 2.0 == 2.0
1010 assert $ (1.0 `const`) 2.0 == 1.0
11− Debug.Trace.trace "Done!"
11+ Control.Monad.Eff.Console.log "Done!"
examples/passing/Operators.purs+2−2
@@ -2,7 +2,7 @@ module Main where
22
33import Prelude
44import Control.Monad.Eff
5−import Debug.Trace
5+import Control.Monad.Eff.Console
66
77(?!) :: forall a. a -> a -> a
88(?!) x _ = x
@@ -96,4 +96,4 @@ main = do
9696 let t18 = test18
9797 let t19 = test19
9898 let t20 = test20
99− trace "Done"
99+ log "Done"
examples/passing/OptimizerBug.purs+1−1
@@ -6,4 +6,4 @@ x a = 1.0 + y a
66
77y a = x a
88
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/PartialFunction.purs+2−2
@@ -1,10 +1,10 @@
11module Main where
22
33import Prelude
4−import Assert
4+import Test.Assert
55
66fn :: Number -> Number
77fn 0.0 = 0.0
88fn 1.0 = 2.0
99
10−main = assertPartial $ \_ -> fn 2.0
10+main = assertThrows $ \_ -> fn 2.0
examples/passing/Patterns.purs+1−1
@@ -19,4 +19,4 @@ isDesc :: Array Number -> Boolean
1919isDesc [x, y] | x > y = true
2020isDesc _ = false
2121
22−main = Debug.Trace.trace "Done"
22+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Person.purs+1−1
@@ -8,4 +8,4 @@ showPerson :: Person -> String
88showPerson = \p -> case p of
99 Person o -> o.name ++ ", aged " ++ show o.age
1010
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Rank2Data.purs+2−2
@@ -1,6 +1,6 @@
11module Main where
22
3−import Prelude
3+import Prelude hiding (add)
44
55data Id = Id forall a. a -> a
66
@@ -26,4 +26,4 @@ two = succ zero'
2626four = add two two
2727fourNumber = runNat four
2828
29−main = Debug.Trace.trace "Done'"
29+main = Control.Monad.Eff.Console.log "Done'"
examples/passing/Rank2Object.purs+2−2
@@ -1,11 +1,11 @@
11module Main where
22
33import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
55
66data Foo = Foo { id :: forall a. a -> a }
77
88foo :: Foo -> Number
99foo (Foo { id = f }) = f 0.0
1010
11−main = trace "Done"
11+main = log "Done"
examples/passing/Rank2TypeSynonym.purs+1−1
@@ -13,4 +13,4 @@ bar = foo 3.0
1313
1414main = do
1515 x <- bar
16− Debug.Trace.print x
16+ Control.Monad.Eff.Console.print x
examples/passing/Rank2Types.purs+1−1
@@ -8,4 +8,4 @@ test1 = \f -> f 0.0
88forever :: forall m a b. (forall a b. m a -> (a -> m b) -> m b) -> m a -> m b
99forever = \bind action -> bind action $ \_ -> forever bind action
1010
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/RebindableSyntax.purs+6−6
@@ -9,7 +9,7 @@ example1 = do
99 " for"
1010 " Semigroup"
1111 where
12− (>>=) x f = x <> f unit
12+ bind x f = x <> f unit
1313
1414(*>) :: forall f a b. (Apply f) => f a -> f b -> f b
1515(*>) fa fb = const id <$> fa <*> fb
@@ -20,10 +20,10 @@ runConst :: forall a b. Const a b -> a
2020runConst (Const a) = a
2121
2222instance functorConst :: Functor (Const a) where
23− (<$>) _ (Const a) = Const a
23+ map _ (Const a) = Const a
2424
2525instance applyConst :: (Semigroup a) => Apply (Const a) where
26− (<*>) (Const a1) (Const a2) = Const (a1 <> a2)
26+ apply (Const a1) (Const a2) = Const (a1 <> a2)
2727
2828example2 :: Const String Unit
2929example2 = do
@@ -32,8 +32,8 @@ example2 = do
3232 Const " for"
3333 Const " Apply"
3434 where
35− (>>=) x f = x *> f unit
35+ bind x f = x *> f unit
3636
3737main = do
38− Debug.Trace.trace example1
39− Debug.Trace.trace $ runConst example2
38+ Control.Monad.Eff.Console.log example1
39+ Control.Monad.Eff.Console.log $ runConst example2
examples/passing/Recursion.purs+1−1
@@ -7,4 +7,4 @@ fib = \n -> case n of
77 1.0 -> 1.0
88 n -> fib (n - 1.0) + fib (n - 2.0)
99
10−main = Debug.Trace.trace "Done"
10+main = Control.Monad.Eff.Console.log "Done"
examples/passing/ReservedWords.purs+1−1
@@ -12,4 +12,4 @@ p = o { type = "p" }
1212f :: forall r. { type :: String | r } -> String
1313f { type = "p" } = "Done"
1414
15−main = Debug.Trace.trace $ f { type: p.type, foo: "bar" }
15+main = Control.Monad.Eff.Console.log $ f { type: p.type, foo: "bar" }
examples/passing/RowConstructors.purs+1−1
@@ -39,4 +39,4 @@ wildcard { w: w } = { x: w, y: w, z: w, w: w }
3939wildcard' :: { | Quux _ } -> Number
4040wildcard' { q: q } = q
4141
42−main = Debug.Trace.trace "Done"
42+main = Control.Monad.Eff.Console.log "Done"
examples/passing/RowPolyInstanceContext.purs+1−1
@@ -19,4 +19,4 @@ test2 = state $ \o -> o { foo = o.foo ++ "!" }
1919main = do
2020 let t1 = test1
2121 let t2 = test2
22− Debug.Trace.trace "Done"
22+ Control.Monad.Eff.Console.log "Done"
examples/passing/RuntimeScopeIssue.purs+1−1
@@ -16,4 +16,4 @@ instance bNumber :: B Number where
1616 b 0.0 = false
1717 b n = a (n - 1.0)
1818
19−main = Debug.Trace.print $ a 10.0
19+main = Control.Monad.Eff.Console.print $ a 10.0
examples/passing/ScopedTypeVariables.purs+1−1
@@ -33,4 +33,4 @@ test4 = h
3333 j x = x
3434
3535
36−main = Debug.Trace.trace "Done"
36+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Sequence.purs+1−1
@@ -12,4 +12,4 @@ instance sequenceList :: Sequence List where
1212 sequence Nil = pure Nil
1313 sequence (Cons x xs) = Cons <$> x <*> sequence xs
1414
15−main = sequence $ Cons (Debug.Trace.trace "Done") Nil
15+main = sequence $ Cons (Control.Monad.Eff.Console.log "Done") Nil
examples/passing/SequenceDesugared.purs+4−4
@@ -31,7 +31,7 @@ sequenceList''' = Sequence ((\val -> case val of
3131 Cons x xs -> Cons <$> x <*> sequence sequenceList''' xs) :: forall m a. (Monad m) => List (m a) -> m (List a))
3232
3333main = do
34− sequence sequenceList $ Cons (Debug.Trace.trace "Done") Nil
35− sequence sequenceList' $ Cons (Debug.Trace.trace "Done") Nil
36− sequence sequenceList'' $ Cons (Debug.Trace.trace "Done") Nil
37− sequence sequenceList''' $ Cons (Debug.Trace.trace "Done") Nil
34+ sequence sequenceList $ Cons (Control.Monad.Eff.Console.log "Done") Nil
35+ sequence sequenceList' $ Cons (Control.Monad.Eff.Console.log "Done") Nil
36+ sequence sequenceList'' $ Cons (Control.Monad.Eff.Console.log "Done") Nil
37+ sequence sequenceList''' $ Cons (Control.Monad.Eff.Console.log "Done") Nil
examples/passing/ShadowedRename.purs+3−3
@@ -2,8 +2,8 @@ module Main where
22
33import Prelude
44import Control.Monad.Eff
5−import Debug.Trace
6−import Assert
5+import Control.Monad.Eff.Console
6+import Test.Assert
77
88foo foo = let foo_1 = \_ -> foo
99 foo_2 = foo_1 unit + 1.0
@@ -11,4 +11,4 @@ foo foo = let foo_1 = \_ -> foo
1111
1212main = do
1313 assert $ foo 1.0 == 2.0
14− trace "Done"
14+ log "Done"
examples/passing/ShadowedTCO.purs+2−2
@@ -1,6 +1,6 @@
11module Main where
22
3−import Prelude
3+import Prelude hiding (add)
44
55runNat f = f 0.0 (\n -> n + 1.0)
66
@@ -15,4 +15,4 @@ two = succ one'
1515four = add two two
1616fourNumber = runNat four
1717
18−main = Debug.Trace.trace $ show fourNumber
18+main = Control.Monad.Eff.Console.log $ show fourNumber
examples/passing/ShadowedTCOLet.purs+1−1
@@ -6,4 +6,4 @@ f x y z =
66 let f 1.0 2.0 3.0 = 1.0
77 in f x z y
88
9−main = Debug.Trace.trace $ show $ f 1.0 3.0 2.0
9+main = Control.Monad.Eff.Console.log $ show $ f 1.0 3.0 2.0
examples/passing/SignedNumericLiterals.purs+1−1
@@ -14,4 +14,4 @@ f x = -x
1414
1515test1 = 2.0 - 1.0
1616
17−main = Debug.Trace.trace "Done"
17+main = Control.Monad.Eff.Console.log "Done"
examples/passing/Superclasses1.purs+1−1
@@ -17,4 +17,4 @@ instance clNumber :: Cl Number where
1717test :: forall a. (Cl a) => a -> a
1818test a = su (cl a a)
1919
20−main = Debug.Trace.print $ test 10.0
20+main = Control.Monad.Eff.Console.print $ test 10.0
examples/passing/Superclasses2.purs+1−2
@@ -1,7 +1,6 @@
11module Main where
22
33import Prelude
4−import Prelude.Unsafe (unsafeIndex)
54
65class Su a where
76 su :: a -> a
@@ -21,4 +20,4 @@ instance clNumber :: Cl Number where
2120test :: forall a. (Cl a) => a -> Array a
2221test x = su [cl x x]
2322
24−main = Debug.Trace.print $ test 10.0 `unsafeIndex` 0.0
23+main = Control.Monad.Eff.Console.print $ test 10.0
examples/passing/Superclasses3.purs+7−7
@@ -1,7 +1,7 @@
11module Main where
22
33import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
55import Control.Monad.Eff
66
77class (Monad m) <= MonadWriter w m where
@@ -16,26 +16,26 @@ test w = do
1616 tell w
1717 tell w
1818
19−data MTrace a = MTrace (Eff (trace :: Trace) a)
19+data MTrace a = MTrace (Eff (console :: CONSOLE) a)
2020
21−runMTrace :: forall a. MTrace a -> Eff (trace :: Trace) a
21+runMTrace :: forall a. MTrace a -> Eff (console :: CONSOLE) a
2222runMTrace (MTrace a) = a
2323
2424instance functorMTrace :: Functor MTrace where
25− (<$>) = liftM1
25+ map = liftM1
2626
2727instance applyMTrace :: Apply MTrace where
28− (<*>) = ap
28+ apply = ap
2929
3030instance applicativeMTrace :: Applicative MTrace where
3131 pure = MTrace <<< return
3232
3333instance bindMTrace :: Bind MTrace where
34− (>>=) m f = MTrace (runMTrace m >>= (runMTrace <<< f))
34+ bind m f = MTrace (runMTrace m >>= (runMTrace <<< f))
3535
3636instance monadMTrace :: Monad MTrace
3737
3838instance writerMTrace :: MonadWriter String MTrace where
39− tell s = MTrace (trace s)
39+ tell s = MTrace (log s)
4040
4141main = runMTrace $ test "Done"
examples/passing/TCOCase.purs+1−1
@@ -4,7 +4,7 @@ import Prelude
44
55data Data = One | More Data
66
7−main = Debug.Trace.trace (from (to 10000.0 One))
7+main = Control.Monad.Eff.Console.log (from (to 10000.0 One))
88 where
99 to 0.0 a = a
1010 to n a = to (n - 1.0) (More a)
examples/passing/TailCall.purs+1−1
@@ -14,4 +14,4 @@ loop x = loop (x + 1.0)
1414notATailCall = \x ->
1515 (\notATailCall -> notATailCall x) (\x -> x)
1616
17−main = Debug.Trace.print (test 0.0 (1.0 `C` (2.0 `C` (3.0 `C` N))))
17+main = Control.Monad.Eff.Console.print (test 0.0 (1.0 `C` (2.0 `C` (3.0 `C` N))))
examples/passing/Tick.purs+1−1
@@ -4,4 +4,4 @@ import Prelude
44
55test' x = x
66
7−main = Debug.Trace.trace "Done"
7+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TopLevelCase.purs+3−3
@@ -5,8 +5,8 @@ import Prelude
55gcd :: Number -> Number -> Number
66gcd 0.0 x = x
77gcd x 0.0 = x
8−gcd x y | x > y = gcd (x % y) y
9−gcd x y = gcd (y % x) x
8+gcd x y | x > y = gcd (x `mod` y) y
9+gcd x y = gcd (y `mod` x) x
1010
1111guardsTest [x] | x > 0.0 = []
1212guardsTest xs = xs
@@ -15,4 +15,4 @@ data A = A
1515
1616parseTest A 0.0 = 0.0
1717
18−main = Debug.Trace.trace "Done"
18+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypeClassMemberOrderChange.purs+1−1
@@ -10,4 +10,4 @@ instance testBoolean :: Test Boolean where
1010 val = true
1111 fn x y = y
1212
13−main = Debug.Trace.trace (show (fn true val))
13+main = Control.Monad.Eff.Console.log (show (fn true val))
examples/passing/TypeClasses.purs+8−8
@@ -22,33 +22,33 @@ instance showData :: (Prelude.Show a) => Prelude.Show (Data a) where
2222test3 = \_ -> show (Data "testing")
2323
2424instance functorData :: Functor Data where
25− (<$>) = liftM1
25+ map = liftM1
2626
2727instance applyData :: Apply Data where
28− (<*>) = ap
28+ apply = ap
2929
3030instance applicativeData :: Applicative Data where
3131 pure = Data
3232
3333instance bindData :: Bind Data where
34− (>>=) (Data a) f = f a
34+ bind (Data a) f = f a
3535
3636instance monadData :: Monad Data
3737
3838data Maybe a = Nothing | Just a
3939
4040instance functorMaybe :: Functor Maybe where
41− (<$>) = liftM1
41+ map = liftM1
4242
4343instance applyMaybe :: Apply Maybe where
44− (<*>) = ap
44+ apply = ap
4545
4646instance applicativeMaybe :: Applicative Maybe where
4747 pure = Just
4848
4949instance bindMaybe :: Bind Maybe where
50− (>>=) Nothing _ = Nothing
51− (>>=) (Just a) f = f a
50+ bind Nothing _ = Nothing
51+ bind (Just a) f = f a
5252
5353instance monadMaybe :: Monad Maybe
5454
@@ -65,5 +65,5 @@ test9 _ = runReader 0.0 $ do
6565 n <- ask
6666 return $ n + 1.0
6767
68−main = Debug.Trace.trace (test7 "Done")
68+main = Control.Monad.Eff.Console.log (test7 "Done")
6969
examples/passing/TypeClassesInOrder.purs+1−1
@@ -8,4 +8,4 @@ class Foo a where
88instance fooString :: Foo String where
99 foo s = s
1010
11−main = Debug.Trace.trace $ foo "Done"
11+main = Control.Monad.Eff.Console.log $ foo "Done"
examples/passing/TypeClassesWithOverlappingTypeVariables.purs+3−3
@@ -5,7 +5,7 @@ import Prelude
55data Either a b = Left a | Right b
66
77instance functorEither :: Prelude.Functor (Either a) where
8− (<$>) _ (Left x) = Left x
9− (<$>) f (Right y) = Right (f y)
8+ map _ (Left x) = Left x
9+ map f (Right y) = Right (f y)
1010
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypeDecl.purs+1−1
@@ -9,4 +9,4 @@ iterate :: forall a. Number -> (a -> a) -> a -> a
99iterate 0.0 f a = a
1010iterate n f a = iterate (n - 1.0) f (f a)
1111
12−main = Debug.Trace.trace "Done"
12+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypeSynonymInData.purs+1−1
@@ -8,4 +8,4 @@ data Foo a = Foo (A a) | Bar
88
99foo (Foo []) = Bar
1010
11−main = Debug.Trace.trace "Done"
11+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypeSynonyms.purs+1−1
@@ -24,4 +24,4 @@ fst =
2424test1 :: forall a b c. Lens (Pair (Pair a b) c) a
2525test1 = composeLenses fst fst
2626
27−main = Debug.Trace.trace "Done"
27+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypeWildcards.purs+1−1
@@ -12,4 +12,4 @@ test f a = go (f a) a
1212 go a1 a2 | a1 == a2 = a1
1313 go a1 _ = go (f a1) a1
1414
15−main = Debug.Trace.trace "Done"
15+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypeWildcardsRecordExtension.purs+1−1
@@ -5,4 +5,4 @@ import Prelude
55foo :: forall a. {b :: Number | a} -> {b :: Number | _}
66foo f = f
77
8−main = Debug.Trace.trace "Done"
8+main = Control.Monad.Eff.Console.log "Done"
examples/passing/TypedWhere.purs+1−1
@@ -14,4 +14,4 @@ lefts = go N
1414 go ls (C (L a) rest) = go (C a ls) rest
1515 go ls (C _ rest) = go ls rest
1616
17−main = Debug.Trace.trace "Done"
17+main = Control.Monad.Eff.Console.log "Done"
examples/passing/UnderscoreIdent.purs+1−1
@@ -8,4 +8,4 @@ type Type_name = Data_type
88
99done (Con_2 s) = s
1010
11−main = Debug.Trace.trace (done (Con_2 "Done"))
11+main = Control.Monad.Eff.Console.log (done (Con_2 "Done"))
examples/passing/Unit.purs+1−1
@@ -1,6 +1,6 @@
11module Main where
22
33import Prelude
4−import Debug.Trace
4+import Control.Monad.Eff.Console
55
66main = print (const unit $ "Hello world")
examples/passing/UnknownInTypeClassLookup.purs+1−1
@@ -11,4 +11,4 @@ test _ _ = "Done"
1111
1212runTest a = test a a
1313
14−main = Debug.Trace.trace $ runTest 0.0
14+main = Control.Monad.Eff.Console.log $ runTest 0.0
examples/passing/Where.purs+7−7
@@ -40,10 +40,10 @@ test7 x = go x
4040 go y = go $ (y + x / y) / 2.0
4141
4242main = do
43− Debug.Trace.print (test1 1.0)
44− Debug.Trace.print (test2 1.0 2.0)
45− Debug.Trace.print test3
46− Debug.Trace.print test4
47− Debug.Trace.print test5
48− Debug.Trace.print test6
49− Debug.Trace.print (test7 100.0)
43+ Control.Monad.Eff.Console.print (test1 1.0)
44+ Control.Monad.Eff.Console.print (test2 1.0 2.0)
45+ Control.Monad.Eff.Console.print test3
46+ Control.Monad.Eff.Console.print test4
47+ Control.Monad.Eff.Console.print test5
48+ Control.Monad.Eff.Console.print test6
49+ Control.Monad.Eff.Console.print (test7 100.0)
examples/passing/iota.purs+1−1
@@ -6,4 +6,4 @@ k = \x -> \y -> x
66
77iota = \x -> x s k
88
9−main = Debug.Trace.trace "Done"
9+main = Control.Monad.Eff.Console.log "Done"
examples/passing/s.purs+1−1
@@ -4,4 +4,4 @@ import Prelude
44
55s = \x y z -> x z (y z)
66
7−main = Debug.Trace.trace "Done"
7+main = Control.Monad.Eff.Console.log "Done"
hierarchy/Main.hs+9−5
@@ -13,6 +13,8 @@
1313--
1414-----------------------------------------------------------------------------
1515
16+{-# LANGUAGE TupleSections #-}
17+
1618module Main where
1719
1820import Control.Monad (unless)
@@ -24,6 +26,7 @@ import Data.Version (showVersion)
2426import Options.Applicative
2527import System.Directory (createDirectoryIfMissing)
2628import System.FilePath ((</>))
29+import System.FilePath.Glob (glob)
2730import System.Exit (exitFailure, exitSuccess)
2831import System.IO (hPutStr, stderr)
2932
@@ -50,13 +53,14 @@ instance Ord SuperMap where
5053runModuleName :: P.ModuleName -> String
5154runModuleName (P.ModuleName pns) = intercalate "_" (P.runProperName `map` pns)
5255
53−readInput :: FilePath -> IO (Either P.MultipleErrors [P.Module])
54−readInput filename = do
55− content <- readFile filename
56− return $ map snd <$> P.parseModulesFromFiles id [(filename, content)]
56+readInput :: [FilePath] -> IO (Either P.MultipleErrors [P.Module])
57+readInput paths = do
58+ content <- mapM (\path -> (path, ) <$> readFile path) paths
59+ return $ map snd <$> P.parseModulesFromFiles id content
5760
5861compile :: HierarchyOptions -> IO ()
59−compile (HierarchyOptions input mOutput) = do
62+compile (HierarchyOptions inputGlob mOutput) = do
63+ input <- glob inputGlob
6064 modules <- readInput input
6165 case modules of
6266 Left errs -> hPutStr stderr (P.prettyPrintMultipleErrors False errs) >> exitFailure
license-generator/generate+1−1
@@ -21,7 +21,7 @@ echo_header() {
2121
2222echo_deps_names() {
2323 cabal-dependency-licenses \
24− | grep '^- ' | sed 's/^..//' | sort -h
24+ | grep '^- ' | sed 's/^..//' | gsort -h
2525}
2626
2727echo_deps_licenses() {
psc-bundle/Main.hsnew file+138
@@ -0,0 +1,138 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : psc-bundle
4+-- Copyright : (c) Phil Freeman 2015
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- | Bundles compiled PureScript modules for the browser.
12+--
13+-----------------------------------------------------------------------------
14+
15+{-# LANGUAGE PatternGuards #-}
16+{-# LANGUAGE FlexibleContexts #-}
17+{-# LANGUAGE ScopedTypeVariables #-}
18+{-# LANGUAGE TupleSections #-}
19+{-# LANGUAGE RecordWildCards #-}
20+
21+module Main (main) where
22+
23+import Data.Traversable (for)
24+import Data.Version (showVersion)
25+
26+import Control.Applicative
27+import Control.Monad
28+import Control.Monad.Error.Class
29+import Control.Monad.Trans.Except
30+import Control.Monad.IO.Class
31+
32+import System.FilePath (takeFileName, takeDirectory)
33+import System.FilePath.Glob (glob)
34+import System.Exit (exitFailure)
35+import System.IO (stderr, hPutStrLn)
36+import System.Directory (createDirectoryIfMissing)
37+
38+import Language.PureScript.Bundle
39+
40+import Options.Applicative as Opts
41+
42+import qualified Paths_purescript as Paths
43+
44+-- | Command line options.
45+data Options = Options
46+ { optionsInputFiles :: [FilePath]
47+ , optionsOutputFile :: Maybe FilePath
48+ , optionsEntryPoints :: [String]
49+ , optionsMainModule :: Maybe String
50+ , optionsNamespace :: String
51+ } deriving Show
52+
53+-- | Given a filename, assuming it is in the correct place on disk, infer a ModuleIdentifier.
54+guessModuleIdentifier :: (Applicative m, MonadError ErrorMessage m) => FilePath -> m ModuleIdentifier
55+guessModuleIdentifier filename = ModuleIdentifier (takeFileName (takeDirectory filename)) <$> (guessModuleType (takeFileName filename))
56+ where
57+ guessModuleType "index.js" = pure Regular
58+ guessModuleType "foreign.js" = pure Foreign
59+ guessModuleType name = throwError $ UnsupportedModulePath name
60+
61+-- | The main application function.
62+-- This function parses the input files, performs dead code elimination, filters empty modules
63+-- and generates and prints the final Javascript bundle.
64+app :: forall m. (Applicative m, MonadError ErrorMessage m, MonadIO m) => Options -> m String
65+app Options{..} = do
66+ inputFiles <- concat <$> mapM (liftIO . glob) optionsInputFiles
67+ when (null inputFiles) . liftIO $ do
68+ hPutStrLn stderr "psc-bundle: No input files."
69+ exitFailure
70+ input <- for inputFiles $ \filename -> do
71+ js <- liftIO (readFile filename)
72+ mid <- guessModuleIdentifier filename
73+ return (mid, js)
74+
75+ let entryIds = (map (`ModuleIdentifier` Regular) optionsEntryPoints)
76+
77+ bundle input entryIds optionsMainModule optionsNamespace
78+
79+-- | Command line options parser.
80+options :: Parser Options
81+options = Options <$> some inputFile
82+ <*> optional outputFile
83+ <*> many entryPoint
84+ <*> optional mainModule
85+ <*> namespace
86+ where
87+ inputFile :: Parser FilePath
88+ inputFile = strArgument $
89+ metavar "FILE"
90+ <> help "The input .js file(s)"
91+
92+ outputFile :: Parser FilePath
93+ outputFile = strOption $
94+ short 'o'
95+ <> long "output"
96+ <> help "The output .js file"
97+
98+ entryPoint :: Parser String
99+ entryPoint = strOption $
100+ short 'm'
101+ <> long "module"
102+ <> help "Entry point module name(s). All code which is not a transitive dependency of an entry point module will be removed."
103+
104+ mainModule :: Parser String
105+ mainModule = strOption $
106+ long "main"
107+ <> help "Generate code to run the main method in the specified module."
108+
109+ namespace :: Parser String
110+ namespace = strOption $
111+ short 'n'
112+ <> long "namespace"
113+ <> Opts.value "PS"
114+ <> showDefault
115+ <> help "Specify the namespace that PureScript modules will be exported to when running in the browser."
116+
117+-- | Make it go.
118+main :: IO ()
119+main = do
120+ opts <- execParser (info (version <*> helper <*> options) infoModList)
121+ output <- runExceptT (app opts)
122+ case output of
123+ Left err -> do
124+ hPutStrLn stderr (unlines (printErrorMessage err))
125+ exitFailure
126+ Right js ->
127+ case optionsOutputFile opts of
128+ Just outputFile -> do
129+ createDirectoryIfMissing True (takeDirectory outputFile)
130+ writeFile outputFile js
131+ Nothing -> putStrLn js
132+ where
133+ infoModList = fullDesc <> headerInfo <> footerInfo
134+ headerInfo = header "psc-bundle - Bundles compiled PureScript modules for the browser"
135+ footerInfo = footer $ "psc-bundle " ++ showVersion Paths.version
136+
137+ version :: Parser (a -> a)
138+ version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> help "Show the version number" <> hidden
psc-bundle/README.mdnew file+18
@@ -0,0 +1,18 @@
1+# psc-bundle
2+
3+A dead code elimination tool for PureScript-style CommonJS modules. This can be used as an alternative to Browserify.
4+
5+## Usage
6+
7+ psc-bundle FILE (-m|--module ARG) [--main ARG] [--namespace ARG]
8+
9+Options:
10+
11+- The input .js file(s)
12+- Entry point module name(s) are specified with `-m` or `--module`. All code which is not a transitive dependency of an entry point module will be removed.
13+- The main module is (optionally) specified using `--main`. If specified, this will generate code to run the main method in the specified module.
14+- The browser namespace defaults to `PS`, and can be overridden with `--namespace`.
15+
16+For example, to bundle the modules in the `output` directory, with main module `Main`:
17+
18+ psc-bundle output/**/*.js -m Main --main Main
psc-docs/Main.hs+3−1
@@ -34,6 +34,7 @@ import System.Exit (exitFailure)
3434import System.IO (hPutStrLn, stderr)
3535import System.Directory (createDirectoryIfMissing)
3636import System.FilePath (takeDirectory)
37+import System.FilePath.Glob (glob)
3738
3839import Etags
3940import Ctags
@@ -61,7 +62,8 @@ data PSCDocsOptions = PSCDocsOptions
6162 deriving (Show)
6263
6364docgen :: PSCDocsOptions -> IO ()
64−docgen (PSCDocsOptions fmt input output) =
65+docgen (PSCDocsOptions fmt inputGlob output) = do
66+ input <- concat <$> mapM glob inputGlob
6567 case fmt of
6668 Etags -> dumpTags input dumpEtags
6769 Ctags -> dumpTags input dumpCtags
psc-make/Main.hsdeleted−164
@@ -1,164 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Main
4−-- Copyright : (c) Phil Freeman 2013
5−-- License : MIT
6−--
7−-- Maintainer : Phil Freeman <paf31@cantab.net>
8−-- Stability : experimental
9−-- Portability :
10−--
11−-- |
12−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE DataKinds #-}
16−{-# LANGUAGE FlexibleContexts #-}
17−{-# LANGUAGE RecordWildCards #-}
18−{-# LANGUAGE TupleSections #-}
19−
20−module Main where
21−
22−import Control.Applicative
23−import Control.Monad
24−import Control.Monad.Error.Class (MonadError(..))
25−import Control.Monad.Writer
26−
27−import Data.Version (showVersion)
28−import qualified Data.Map as M
29−
30−import Options.Applicative as Opts
31−
32−import System.Exit (exitSuccess, exitFailure)
33−import System.IO (hPutStrLn, stderr)
34−
35−import qualified Language.PureScript as P
36−import qualified Paths_purescript as Paths
37−
38−import Make
39−
40−data PSCMakeOptions = PSCMakeOptions
41− { pscmInput :: [FilePath]
42− , pscmForeignInput :: [FilePath]
43− , pscmOutputDir :: FilePath
44− , pscmOpts :: P.Options P.Make
45− , pscmUsePrefix :: Bool
46− }
47−
48−data InputOptions = InputOptions
49− { ioInputFiles :: [FilePath]
50− }
51−
52−compile :: PSCMakeOptions -> IO ()
53−compile (PSCMakeOptions input inputForeign outputDir opts usePrefix) = do
54− moduleFiles <- readInput (InputOptions input)
55− foreignFiles <- forM inputForeign (\inFile -> (inFile,) <$> readFile inFile)
56− case runWriterT (parseInputs moduleFiles foreignFiles) of
57− Left errs -> do
58− hPutStrLn stderr (P.prettyPrintMultipleErrors (P.optionsVerboseErrors opts) errs)
59− exitFailure
60− Right ((ms, foreigns), warnings) -> do
61− when (P.nonEmpty warnings) $
62− hPutStrLn stderr (P.prettyPrintMultipleWarnings (P.optionsVerboseErrors opts) warnings)
63− let filePathMap = M.fromList $ map (\(fp, P.Module _ mn _ _) -> (mn, fp)) ms
64− makeActions = buildMakeActions outputDir filePathMap foreigns usePrefix
65− e <- runMake opts $ P.make makeActions ms
66− case e of
67− Left errs -> do
68− putStrLn (P.prettyPrintMultipleErrors (P.optionsVerboseErrors opts) errs)
69− exitFailure
70− Right (_, warnings') -> do
71− when (P.nonEmpty warnings') $
72− putStrLn (P.prettyPrintMultipleWarnings (P.optionsVerboseErrors opts) warnings')
73− exitSuccess
74−
75−readInput :: InputOptions -> IO [(Either P.RebuildPolicy FilePath, String)]
76−readInput InputOptions{..} = forM ioInputFiles $ \inFile -> (Right inFile, ) <$> readFile inFile
77−
78−parseInputs :: (Functor m, Applicative m, MonadError P.MultipleErrors m, MonadWriter P.MultipleErrors m)
79− => [(Either P.RebuildPolicy FilePath, String)]
80− -> [(FilePath, P.ForeignJS)]
81− -> m ([(Either P.RebuildPolicy FilePath, P.Module)], M.Map P.ModuleName (FilePath, P.ForeignJS))
82−parseInputs modules foreigns =
83− (,) <$> P.parseModulesFromFiles (either (const "") id) modules
84− <*> P.parseForeignModulesFromFiles foreigns
85−
86−inputFile :: Parser FilePath
87−inputFile = strArgument $
88− metavar "FILE"
89− <> help "The input .purs file(s)"
90−
91−inputForeignFile :: Parser FilePath
92−inputForeignFile = strOption $
93− short 'f'
94− <> long "ffi"
95− <> help "The input .js file(s) providing foreign import implementations"
96−
97−outputDirectory :: Parser FilePath
98−outputDirectory = strOption $
99− short 'o'
100− <> long "output"
101− <> Opts.value "output"
102− <> showDefault
103− <> help "The output directory"
104−
105−noTco :: Parser Bool
106−noTco = switch $
107− long "no-tco"
108− <> help "Disable tail call optimizations"
109−
110−noMagicDo :: Parser Bool
111−noMagicDo = switch $
112− long "no-magic-do"
113− <> help "Disable the optimization that overloads the do keyword to generate efficient code specifically for the Eff monad."
114−
115−noOpts :: Parser Bool
116−noOpts = switch $
117− long "no-opts"
118− <> help "Skip the optimization phase."
119−
120−comments :: Parser Bool
121−comments = switch $
122− short 'c'
123− <> long "comments"
124− <> help "Include comments in the generated code."
125−
126−verboseErrors :: Parser Bool
127−verboseErrors = switch $
128− short 'v'
129− <> long "verbose-errors"
130− <> help "Display verbose error messages"
131−
132−noPrefix :: Parser Bool
133−noPrefix = switch $
134− short 'p'
135− <> long "no-prefix"
136− <> help "Do not include comment header"
137−
138−
139−options :: Parser (P.Options P.Make)
140−options = P.Options <$> noTco
141− <*> noMagicDo
142− <*> pure Nothing
143− <*> noOpts
144− <*> verboseErrors
145− <*> (not <$> comments)
146− <*> pure P.MakeOptions
147−
148−pscMakeOptions :: Parser PSCMakeOptions
149−pscMakeOptions = PSCMakeOptions <$> many inputFile
150− <*> many inputForeignFile
151− <*> outputDirectory
152− <*> options
153− <*> (not <$> noPrefix)
154−
155−main :: IO ()
156−main = execParser opts >>= compile
157− where
158− opts = info (version <*> helper <*> pscMakeOptions) infoModList
159− infoModList = fullDesc <> headerInfo <> footerInfo
160− headerInfo = header "psc-make - Compiles PureScript to Javascript"
161− footerInfo = footer $ "psc-make " ++ showVersion Paths.version
162−
163− version :: Parser (a -> a)
164− version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> help "Show the version number" <> hidden
psc-make/Make.hsdeleted−138
@@ -1,138 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Make
4−-- Copyright : (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors
5−-- License : MIT
6−--
7−-- Maintainer : Phil Freeman <paf31@cantab.net>
8−-- Stability : experimental
9−-- Portability :
10−--
11−-- |
12−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE DataKinds #-}
16−{-# LANGUAGE FlexibleContexts #-}
17−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
18−{-# LANGUAGE TupleSections #-}
19−
20−module Make
21− ( Make(..)
22− , runMake
23− , buildMakeActions
24− ) where
25−
26−import Control.Applicative
27−import Control.Monad
28−import Control.Monad.Error.Class (MonadError(..))
29−import Control.Monad.Trans.Except
30−import Control.Monad.Reader
31−import Control.Monad.Writer
32−
33−import Data.Maybe (fromMaybe)
34−import Data.Time.Clock
35−import Data.Traversable (traverse)
36−import Data.Version (showVersion)
37−import qualified Data.Map as M
38−
39−import System.Directory
40− (doesFileExist, getModificationTime, createDirectoryIfMissing)
41−import System.FilePath ((</>), takeDirectory)
42−import System.IO.Error (tryIOError)
43−
44−import qualified Language.PureScript as P
45−import qualified Language.PureScript.CodeGen.JS as J
46−import qualified Language.PureScript.CoreFn as CF
47−import qualified Paths_purescript as Paths
48−
49−newtype Make a = Make { unMake :: ReaderT (P.Options P.Make) (WriterT P.MultipleErrors (ExceptT P.MultipleErrors IO)) a }
50− deriving (Functor, Applicative, Monad, MonadIO, MonadError P.MultipleErrors, MonadWriter P.MultipleErrors, MonadReader (P.Options P.Make))
51−
52−runMake :: P.Options P.Make -> Make a -> IO (Either P.MultipleErrors (a, P.MultipleErrors))
53−runMake opts = runExceptT . runWriterT . flip runReaderT opts . unMake
54−
55−makeIO :: (IOError -> P.ErrorMessage) -> IO a -> Make a
56−makeIO f io = do
57− e <- liftIO $ tryIOError io
58− either (throwError . P.singleError . f) return e
59−
60−-- Traverse (Either e) instance (base 4.7)
61−traverseEither :: Applicative f => (a -> f b) -> Either e a -> f (Either e b)
62−traverseEither _ (Left x) = pure (Left x)
63−traverseEither f (Right y) = Right <$> f y
64−
65−buildMakeActions :: FilePath
66− -> M.Map P.ModuleName (Either P.RebuildPolicy String)
67− -> M.Map P.ModuleName (FilePath, P.ForeignJS)
68− -> Bool
69− -> P.MakeActions Make
70−buildMakeActions outputDir filePathMap foreigns usePrefix =
71− P.MakeActions getInputTimestamp getOutputTimestamp readExterns codegen progress
72− where
73−
74− getInputTimestamp :: P.ModuleName -> Make (Either P.RebuildPolicy (Maybe UTCTime))
75− getInputTimestamp mn = do
76− let path = fromMaybe (error "Module has no filename in 'make'") $ M.lookup mn filePathMap
77− traverseEither getTimestamp path
78−
79− getOutputTimestamp :: P.ModuleName -> Make (Maybe UTCTime)
80− getOutputTimestamp mn = do
81− let filePath = P.runModuleName mn
82− jsFile = outputDir </> filePath </> "index.js"
83− externsFile = outputDir </> filePath </> "externs.purs"
84− min <$> getTimestamp jsFile <*> getTimestamp externsFile
85−
86− readExterns :: P.ModuleName -> Make (FilePath, String)
87− readExterns mn = do
88− let path = outputDir </> P.runModuleName mn </> "externs.purs"
89− (path, ) <$> readTextFile path
90−
91− codegen :: CF.Module CF.Ann -> P.Environment -> P.SupplyVar -> P.Externs -> Make ()
92− codegen m _ nextVar exts = do
93− let mn = CF.moduleName m
94− foreignInclude <- case mn `M.lookup` foreigns of
95− Just (path, _)
96− | not $ requiresForeign m -> do
97− tell $ P.errorMessage $ P.UnnecessaryFFIModule mn path
98− return Nothing
99− | otherwise -> return $ Just $ J.JSApp (J.JSVar "require") [J.JSStringLiteral "./foreign"]
100− Nothing | requiresForeign m -> throwError . P.errorMessage $ P.MissingFFIModule mn
101− | otherwise -> return Nothing
102− pjs <- P.evalSupplyT nextVar $ P.prettyPrintJS <$> J.moduleToJs m foreignInclude
103− let filePath = P.runModuleName mn
104− jsFile = outputDir </> filePath </> "index.js"
105− externsFile = outputDir </> filePath </> "externs.purs"
106− foreignFile = outputDir </> filePath </> "foreign.js"
107− prefix = ["Generated by psc-make version " ++ showVersion Paths.version | usePrefix]
108− js = unlines $ map ("// " ++) prefix ++ [pjs]
109− writeTextFile jsFile js
110− maybe (return ()) (writeTextFile foreignFile . snd) $ mn `M.lookup` foreigns
111− writeTextFile externsFile exts
112−
113− requiresForeign :: CF.Module a -> Bool
114− requiresForeign = not . null . CF.moduleForeign
115−
116− getTimestamp :: FilePath -> Make (Maybe UTCTime)
117− getTimestamp path = makeIO (const (P.SimpleErrorWrapper $ P.CannotGetFileInfo path)) $ do
118− exists <- doesFileExist path
119− traverse (const $ getModificationTime path) $ guard exists
120−
121− readTextFile :: FilePath -> Make String
122− readTextFile path = do
123− verboseErrorsEnabled <- asks P.optionsVerboseErrors
124− makeIO (const (P.SimpleErrorWrapper $ P.CannotReadFile path)) $ do
125− when verboseErrorsEnabled $ putStrLn $ "Reading " ++ path
126− readFile path
127−
128− writeTextFile :: FilePath -> String -> Make ()
129− writeTextFile path text = makeIO (const (P.SimpleErrorWrapper $ P.CannotWriteFile path)) $ do
130− mkdirp path
131− putStrLn $ "Writing " ++ path
132− writeFile path text
133− where
134− mkdirp :: FilePath -> IO ()
135− mkdirp = createDirectoryIfMissing True . takeDirectory
136−
137− progress :: String -> Make ()
138− progress = liftIO . putStrLn
psc-publish/Main.hs+29−271
@@ -1,280 +1,38 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE RecordWildCards #-}
3−{-# LANGUAGE TupleSections #-}
4−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
51
6−import Prelude hiding (userError)
7−
8−import Data.Maybe
9−import Data.Char (isSpace)
10−import Data.String (fromString)
11−import Data.List (stripPrefix, isSuffixOf, (\\))
12−import Data.List.Split (splitOn)
13−import Data.List.NonEmpty (NonEmpty(..))
14−import Data.Version
15−import Safe (headMay)
16−
17−import qualified Data.ByteString.Lazy.Char8 as BL
18−import qualified Data.Text as T
2+module Main where
193
4+import Data.Version (Version(..), showVersion)
205import qualified Data.Aeson as A
21−import Data.Aeson.BetterErrors
22−
23−import Control.Applicative
24−import Control.Category ((>>>))
25−import Control.Arrow ((***))
26−import Control.Exception (catch, try)
27−import Control.Monad.Trans.Except
28−import Control.Monad.Error.Class (MonadError(..))
29−import Control.Monad.Writer
6+import qualified Data.ByteString.Lazy.Char8 as BL
307
31−import System.Directory (doesFileExist)
32−import System.Process (readProcess)
33−import System.Exit (exitFailure)
34−import qualified System.FilePath.Glob as Glob
8+import Options.Applicative hiding (str)
359
36−import Web.Bower.PackageMeta (PackageMeta(..), BowerError(..), PackageName,
37− runPackageName, parsePackageName, Repository(..))
38−import qualified Web.Bower.PackageMeta as Bower
10+import qualified Paths_purescript as Paths
11+import Language.PureScript.Publish
3912
40−import qualified Language.PureScript.Docs as D
41−import Utils
42−import ErrorsWarnings
13+dryRun :: Parser Bool
14+dryRun = switch $
15+ long "dry-run"
16+ <> help "Produce no output, and don't require a tagged version to be checked out."
4317
4418main :: IO ()
45−main = do
46− pkg <- preparePackage
47− BL.putStrLn (A.encode pkg)
48−
49−-- | Attempt to retrieve package metadata from the current directory.
50−-- Calls exitFailure if no package metadata could be retrieved.
51−preparePackage :: IO D.UploadedPackage
52−preparePackage =
53− runPrepareM preparePackage'
54− >>= either (\e -> printError e >> exitFailure)
55− handleWarnings
56− where
57− handleWarnings (result, warns) = do
58− printWarnings warns
59− return result
60−
61−newtype PrepareM a =
62− PrepareM { unPrepareM :: WriterT [PackageWarning] (ExceptT PackageError IO) a }
63− deriving (Functor, Applicative, Monad,
64− MonadWriter [PackageWarning],
65− MonadError PackageError)
66−
67−-- This MonadIO instance ensures that IO errors don't crash the program.
68−instance MonadIO PrepareM where
69− liftIO act =
70− lift' (try act) >>= either (otherError . IOExceptionThrown) return
71− where
72− lift' :: IO a -> PrepareM a
73− lift' = PrepareM . lift . lift
74−
75−runPrepareM :: PrepareM a -> IO (Either PackageError (a, [PackageWarning]))
76−runPrepareM = runExceptT . runWriterT . unPrepareM
77−
78−warn :: PackageWarning -> PrepareM ()
79−warn w = tell [w]
80−
81−userError :: UserError -> PrepareM a
82−userError = throwError . UserError
83−
84−internalError :: InternalError -> PrepareM a
85−internalError = throwError . InternalError
86−
87−otherError :: OtherError -> PrepareM a
88−otherError = throwError . OtherError
89−
90−catchLeft :: Applicative f => Either a b -> (a -> f b) -> f b
91−catchLeft a f = either f pure a
92−
93−preparePackage' :: PrepareM D.UploadedPackage
94−preparePackage' = do
95− exists <- liftIO (doesFileExist "bower.json")
96− unless exists (userError BowerJSONNotFound)
97−
98− pkgMeta <- liftIO (Bower.decodeFile "bower.json")
99− >>= flip catchLeft (userError . CouldntParseBowerJSON)
100− (pkgVersionTag, pkgVersion) <- getVersionFromGitTag
101− pkgGithub <- getBowerInfo pkgMeta
102− (pkgBookmarks, pkgModules) <- getModulesAndBookmarks
103−
104− let declaredDeps = map fst (bowerDependencies pkgMeta ++
105− bowerDevDependencies pkgMeta)
106− pkgResolvedDependencies <- getResolvedDependencies declaredDeps
107−
108− let pkgUploader = D.NotYetKnown
109−
110− return D.Package{..}
111−
112−getModulesAndBookmarks :: PrepareM ([D.Bookmark], [D.RenderedModule])
113−getModulesAndBookmarks = do
114− (inputFiles, depsFiles) <- liftIO getInputAndDepsFiles
115− liftIO (D.parseAndDesugar inputFiles depsFiles renderModules)
116− >>= either (userError . ParseAndDesugarError) return
19+main = execParser opts >>= publish
11720 where
118− renderModules bookmarks modules =
119− return (bookmarks, map D.renderModule modules)
120−
121−getVersionFromGitTag :: PrepareM (String, Version)
122−getVersionFromGitTag = do
123− out <- readProcess' "git" ["tag", "--list", "--points-at", "HEAD"] ""
124− let vs = map trimWhitespace (lines out)
125− case mapMaybe parseMay vs of
126− [] -> userError TagMustBeCheckedOut
127− [x] -> return x
128− xs -> userError (AmbiguousVersions (map snd xs))
129− where
130− trimWhitespace =
131− dropWhile isSpace >>> reverse >>> dropWhile isSpace >>> reverse
132− parseMay str =
133− (str,) <$> D.parseVersion' (dropPrefix "v" str)
134− dropPrefix prefix str =
135− fromMaybe str (stripPrefix prefix str)
136−
137−getBowerInfo :: PackageMeta -> PrepareM (D.GithubUser, D.GithubRepo)
138−getBowerInfo = either (userError . BadRepositoryField) return . tryExtract
139− where
140− tryExtract pkgMeta =
141− case bowerRepository pkgMeta of
142− Nothing -> Left RepositoryFieldMissing
143− Just Repository{..} -> do
144− unless (repositoryType == "git")
145− (Left (BadRepositoryType repositoryType))
146− maybe (Left NotOnGithub) Right (extractGithub repositoryUrl)
147−
148−extractGithub :: String -> Maybe (D.GithubUser, D.GithubRepo)
149−extractGithub =
150− stripPrefix "git://github.com/"
151− >>> fmap (splitOn "/")
152− >=> takeTwo
153− >>> fmap (D.GithubUser *** (D.GithubRepo . dropDotGit))
154−
155− where
156− takeTwo :: [a] -> Maybe (a, a)
157− takeTwo [x, y] = Just (x, y)
158− takeTwo _ = Nothing
159−
160− dropDotGit :: String -> String
161− dropDotGit str
162− | ".git" `isSuffixOf` str = take (length str - 4) str
163− | otherwise = str
164−
165−readProcess' :: String -> [String] -> String -> PrepareM String
166−readProcess' prog args stdin = do
167− out <- liftIO (catch (Right <$> readProcess prog args stdin)
168− (return . Left))
169− either (otherError . ProcessFailed prog args) return out
170−
171−data DependencyStatus
172− = Missing
173− | ResolvedOther String
174− -- ^ Resolved, but to something other than a version. The String argument
175− -- is the resolution type. The values it can take that I'm aware of are
176− -- "commit" and "branch".
177− | ResolvedVersion String
178− -- ^ Resolved to a version. The String argument is the resolution tag (eg,
179− -- "v0.1.0").
180− deriving (Show, Eq)
181−
182−-- Go through all bower dependencies which contain purescript code, and
183−-- extract their versions.
184−--
185−-- In the case where a bower dependency is taken from a particular version,
186−-- that's easy; take that version. In any other case (eg, a branch, or a commit
187−-- sha) we print a warning that documentation links will not work, and avoid
188−-- linking to documentation for any types from that package.
189−--
190−-- The rationale for this is: people will prefer to use a released version
191−-- where possible. If they are not using a released version, then this is
192−-- probably for a reason. However, docs are only ever available for released
193−-- versions. Therefore there will probably be no version of the docs which is
194−-- appropriate to link to, and we should omit links.
195−getResolvedDependencies :: [PackageName] -> PrepareM [(PackageName, Version)]
196−getResolvedDependencies declaredDeps = do
197− depsBS <- fromString <$> readProcess' "bower" ["list", "--json", "--offline"] ""
198−
199− deps <- catchLeft (parse asBowerResolvedDependencies depsBS)
200− (internalError . JSONError FromBowerList)
201−
202− warnUndeclared declaredDeps (map fst deps)
203− handleDeps deps
204−
205− where
206− asBowerResolvedDependencies ::
207− Parse BowerError [(PackageName, DependencyStatus)]
208− asBowerResolvedDependencies =
209− key "dependencies"
210− (eachInObjectWithKey (parsePackageName . T.unpack) asDependencyStatus)
211−
212−asDependencyStatus :: Parse e DependencyStatus
213−asDependencyStatus = do
214− isMissing <- keyOrDefault "missing" False asBool
215− if isMissing
216− then
217− return Missing
218− else
219− key "pkgMeta" $
220− key "_resolution" $ do
221− type_ <- key "type" asString
222− case type_ of
223− "version" -> ResolvedVersion <$> key "tag" asString
224− other -> return (ResolvedOther other)
225−
226−warnUndeclared :: [PackageName] -> [PackageName] -> PrepareM ()
227−warnUndeclared declared actual =
228− mapM_ (warn . UndeclaredDependency) (actual \\ declared)
229−
230−handleDeps ::
231− [(PackageName, DependencyStatus)] -> PrepareM [(PackageName, Version)]
232−handleDeps deps = do
233− let (missing, notVersion, installed) = partitionDeps deps
234− case missing of
235− (x:xs) ->
236− userError (MissingDependencies (x :| xs))
237− [] -> do
238− mapM_ (warn . ResolutionNotVersion . fst) notVersion
239− let withVersions = mapMaybe tryExtractVersion installed
240− filterM (liftIO . isPureScript . bowerDir . fst) withVersions
241−
242− where
243− partitionDeps = foldr go ([], [], [])
244− go (pkgName, d) (ms, os, is) =
245− case d of
246− Missing -> (pkgName : ms, os, is)
247− ResolvedOther o -> (ms, (pkgName, o) : os, is)
248− ResolvedVersion v -> (ms, os, (pkgName, v) : is)
249−
250− bowerDir pkgName = "bower_components/" ++ runPackageName pkgName
251−
252−tryExtractVersion :: (PackageName, String) -> Maybe (PackageName, Version)
253−tryExtractVersion (pkgName, tag) =
254− let tag' = fromMaybe tag (stripPrefix "v" tag)
255− in (pkgName,) <$> D.parseVersion' tag'
256−
257−-- | Returns whether it looks like there is a purescript package checked out
258−-- in the given directory.
259−isPureScript :: FilePath -> IO Bool
260−isPureScript dir = do
261− files <- Glob.globDir1 purescriptSourceFiles dir
262− return (not (null files))
263−
264−getInputAndDepsFiles :: IO ([FilePath], [(PackageName, FilePath)])
265−getInputAndDepsFiles = do
266− inputFiles <- globRelative purescriptSourceFiles
267− depsFiles' <- globRelative purescriptDepsFiles
268− return (inputFiles, mapMaybe withPackageName depsFiles')
269−
270−withPackageName :: FilePath -> Maybe (PackageName, FilePath)
271−withPackageName fp = (,fp) <$> getPackageName fp
272−
273−getPackageName :: FilePath -> Maybe PackageName
274−getPackageName fp = do
275− let xs = splitOn "/" fp
276− ys <- stripPrefix ["bower_components"] xs
277− y <- headMay ys
278− case Bower.mkPackageName y of
279− Right name -> Just name
280− Left _ -> Nothing
21+ opts = info (version <*> helper <*> dryRun) infoModList
22+ infoModList = fullDesc <> headerInfo <> footerInfo
23+ headerInfo = header "psc-publish - Generates documentation packages for upload to http://pursuit.purescript.org"
24+ footerInfo = footer $ "psc-publish " ++ showVersion Paths.version
25+
26+ version :: Parser (a -> a)
27+ version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> help "Show the version number" <> hidden
28+
29+publish :: Bool -> IO ()
30+publish isDryRun =
31+ if isDryRun
32+ then do
33+ let dummyVersion = ("0.0.0", Version [0,0,0] [])
34+ _ <- preparePackage $ defaultPublishOptions { publishGetVersion = return dummyVersion }
35+ putStrLn "Dry run completed, no errors."
36+ else do
37+ pkg <- preparePackage defaultPublishOptions
38+ BL.putStrLn (A.encode pkg)
psc-publish/Utils.hsdeleted−22
@@ -1,22 +0,0 @@
1−
2−module Utils where
3−
4−import Data.List
5−import Data.Maybe
6−import System.Directory
7−import qualified System.FilePath.Glob as Glob
8−
9−-- | Glob relative to the current directory, and produce relative pathnames.
10−globRelative :: Glob.Pattern -> IO [FilePath]
11−globRelative pat = do
12− currentDir <- getCurrentDirectory
13− filesAbsolute <- Glob.globDir1 pat currentDir
14− return (mapMaybe (stripPrefix (currentDir ++ "/")) filesAbsolute)
15−
16−-- | Glob pattern for PureScript source files.
17−purescriptSourceFiles :: Glob.Pattern
18−purescriptSourceFiles = Glob.compile "src/**/*.purs"
19−
20−-- | Glob pattern for PureScript dependency files.
21−purescriptDepsFiles :: Glob.Pattern
22−purescriptDepsFiles = Glob.compile "bower_components/*/src/**/*.purs"
psc-publish/tests/Test.hs+13−10
@@ -1,5 +1,6 @@
11{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
22{-# OPTIONS_GHC -fno-warn-unused-imports #-}
3+{-# LANGUAGE ScopedTypeVariables #-}
34
45-- | To run these tests:
56--
@@ -11,6 +12,7 @@ module Test where
1112
1213import Control.Monad
1314import Control.Applicative
15+import Control.Exception
1416import System.Process
1517import System.Directory
1618import qualified Data.ByteString.Lazy as BL
@@ -21,17 +23,17 @@ import Data.Aeson.BetterErrors
2123import Main
2224import Language.PureScript.Docs
2325
24−packageName = "purescript-integers"
25−packageUrl = "https://github.com/purescript/" ++ packageName
26−packageDir = "tmp/" ++ packageName
26+pkgName = "purescript-prelude"
27+packageUrl = "https://github.com/purescript/" ++ pkgName
28+packageDir = "tmp/" ++ pkgName
2729
28−pushd :: FilePath -> IO a -> IO a
30+pushd :: forall a. FilePath -> IO a -> IO a
2931pushd dir act = do
3032 original <- getCurrentDirectory
3133 setCurrentDirectory dir
32− result <- act
34+ result <- try act :: IO (Either IOException a)
3335 setCurrentDirectory original
34− return result
36+ either throwIO return result
3537
3638clonePackage :: IO ()
3739clonePackage = do
@@ -39,8 +41,9 @@ clonePackage = do
3941 pushd packageDir $ do
4042 exists <- doesDirectoryExist ".git"
4143 unless exists $ do
42− putStrLn ("Cloning " ++ packageName ++ " into " ++ packageDir ++ "...")
44+ putStrLn ("Cloning " ++ pkgName ++ " into " ++ packageDir ++ "...")
4345 readProcess "git" ["clone", packageUrl, "."] "" >>= putStr
46+ readProcess "git" ["tag", "v999.0.0"] "" >>= putStr
4447
4548bowerInstall :: IO ()
4649bowerInstall = do
@@ -54,7 +57,7 @@ getPackage = do
5457 pushd packageDir preparePackage
5558
5659data TestResult
57− = ParseFailed (ParseError UploadedPackageError)
60+ = ParseFailed String
5861 | Mismatch ByteString ByteString -- ^ encoding before, encoding after
5962 | Pass ByteString
6063 deriving (Show)
@@ -67,10 +70,10 @@ test = roundTrip <$> getPackage
6770roundTrip :: UploadedPackage -> TestResult
6871roundTrip pkg =
6972 let before = A.encode pkg
70− in case parse asUploadedPackage before of
73+ in case A.eitherDecode before of
7174 Left err -> ParseFailed err
7275 Right parsed -> do
73− let after = A.encode parsed
76+ let after = A.encode (parsed :: UploadedPackage)
7477 if before == after
7578 then Pass before
7679 else Mismatch before after
psc/Main.hs+78−130
@@ -15,7 +15,6 @@
1515{-# LANGUAGE DataKinds #-}
1616{-# LANGUAGE FlexibleContexts #-}
1717{-# LANGUAGE RecordWildCards #-}
18−{-# LANGUAGE ScopedTypeVariables #-}
1918{-# LANGUAGE TupleSections #-}
2019
2120module Main where
@@ -23,52 +22,42 @@ module Main where
2322import Control.Applicative
2423import Control.Monad
2524import Control.Monad.Error.Class (MonadError(..))
26−import Control.Monad.Reader
2725import Control.Monad.Writer
2826
29−import Data.Maybe (fromMaybe)
3027import Data.Version (showVersion)
28+import qualified Data.Map as M
3129
3230import Options.Applicative as Opts
3331
34−import System.Directory (createDirectoryIfMissing)
3532import System.Exit (exitSuccess, exitFailure)
36−import System.FilePath (takeDirectory)
3733import System.IO (hPutStrLn, stderr)
34+import System.FilePath.Glob (glob)
3835
39−import qualified Data.Map as M
4036import qualified Language.PureScript as P
4137import qualified Paths_purescript as Paths
4238
43−data PSCOptions = PSCOptions
44− { pscInput :: [FilePath]
45− , pscForeignInput :: [FilePath]
46− , pscOpts :: P.Options P.Compile
47− , pscStdIn :: Bool
48− , pscOutput :: Maybe FilePath
49− , pscExterns :: Maybe FilePath
50− , pscUsePrefix :: Bool
39+import Language.PureScript.Make
40+
41+data PSCMakeOptions = PSCMakeOptions
42+ { pscmInput :: [FilePath]
43+ , pscmForeignInput :: [FilePath]
44+ , pscmOutputDir :: FilePath
45+ , pscmOpts :: P.Options
46+ , pscmUsePrefix :: Bool
5147 }
5248
5349data InputOptions = InputOptions
54− { ioUseStdIn :: Bool
55− , ioInputFiles :: [FilePath]
50+ { ioInputFiles :: [FilePath]
5651 }
5752
58−readInput :: InputOptions -> IO [(Maybe FilePath, String)]
59−readInput InputOptions{..}
60− | ioUseStdIn = return . (Nothing ,) <$> getContents
61− | otherwise = forM ioInputFiles $ \inFile -> (Just inFile, ) <$> readFile inFile
62−
63−type PSC = ReaderT (P.Options P.Compile) (WriterT P.MultipleErrors (Either P.MultipleErrors))
64−
65−runPSC :: P.Options P.Compile -> PSC a -> Either P.MultipleErrors (a, P.MultipleErrors)
66−runPSC opts rwe = runWriterT (runReaderT rwe opts)
67−
68−compile :: PSCOptions -> IO ()
69−compile (PSCOptions input inputForeign opts stdin output externs usePrefix) = do
70− let prefix = ["Generated by psc version " ++ showVersion Paths.version | usePrefix]
71− moduleFiles <- readInput (InputOptions stdin input)
53+compile :: PSCMakeOptions -> IO ()
54+compile (PSCMakeOptions inputGlob inputForeignGlob outputDir opts usePrefix) = do
55+ input <- concat <$> mapM glob inputGlob
56+ when (null input) $ do
57+ hPutStrLn stderr "psc: No input files."
58+ exitFailure
59+ moduleFiles <- readInput (InputOptions input)
60+ inputForeign <- concat <$> mapM glob inputForeignGlob
7261 foreignFiles <- forM inputForeign (\inFile -> (inFile,) <$> readFile inFile)
7362 case runWriterT (parseInputs moduleFiles foreignFiles) of
7463 Left errs -> do
@@ -77,115 +66,80 @@ compile (PSCOptions input inputForeign opts stdin output externs usePrefix) = do
7766 Right ((ms, foreigns), warnings) -> do
7867 when (P.nonEmpty warnings) $
7968 hPutStrLn stderr (P.prettyPrintMultipleWarnings (P.optionsVerboseErrors opts) warnings)
80− case runPSC opts (P.compileJS ms foreigns prefix) of
69+ let filePathMap = M.fromList $ map (\(fp, P.Module _ mn _ _) -> (mn, fp)) ms
70+ makeActions = buildMakeActions outputDir filePathMap foreigns usePrefix
71+ e <- runMake opts $ P.make makeActions (map snd ms)
72+ case e of
8173 Left errs -> do
8274 hPutStrLn stderr (P.prettyPrintMultipleErrors (P.optionsVerboseErrors opts) errs)
8375 exitFailure
84− Right ((js, exts, _), warnings') -> do
76+ Right (_, warnings') -> do
8577 when (P.nonEmpty warnings') $
8678 hPutStrLn stderr (P.prettyPrintMultipleWarnings (P.optionsVerboseErrors opts) warnings')
87− case output of
88− Just path -> mkdirp path >> writeFile path js
89− Nothing -> putStrLn js
90− case externs of
91− Just path -> mkdirp path >> writeFile path exts
92− Nothing -> return ()
9379 exitSuccess
9480
81+readInput :: InputOptions -> IO [(Either P.RebuildPolicy FilePath, String)]
82+readInput InputOptions{..} = forM ioInputFiles $ \inFile -> (Right inFile, ) <$> readFile inFile
83+
9584parseInputs :: (Functor m, Applicative m, MonadError P.MultipleErrors m, MonadWriter P.MultipleErrors m)
96− => [(Maybe FilePath, String)] -> [(FilePath, P.ForeignJS)] -> m ([P.Module], M.Map P.ModuleName (FilePath, P.ForeignJS))
85+ => [(Either P.RebuildPolicy FilePath, String)]
86+ -> [(FilePath, P.ForeignJS)]
87+ -> m ([(Either P.RebuildPolicy FilePath, P.Module)], M.Map P.ModuleName (FilePath, P.ForeignJS))
9788parseInputs modules foreigns =
98− (,) <$> (map snd <$> P.parseModulesFromFiles (fromMaybe "") modules)
89+ (,) <$> P.parseModulesFromFiles (either (const "") id) modules
9990 <*> P.parseForeignModulesFromFiles foreigns
10091
101−mkdirp :: FilePath -> IO ()
102−mkdirp = createDirectoryIfMissing True . takeDirectory
103−
104−codeGenModule :: Parser String
105−codeGenModule = strOption $
106− long "codegen"
107− <> help "A list of modules for which Javascript and externs should be generated. This argument can be used multiple times."
92+inputFile :: Parser FilePath
93+inputFile = strArgument $
94+ metavar "FILE"
95+ <> help "The input .purs file(s)"
10896
109−dceModule :: Parser String
110−dceModule = strOption $
111− short 'm'
112− <> long "module"
113− <> help "Enables dead code elimination, all code which is not a transitive dependency of a specified module will be removed. This argument can be used multiple times."
97+inputForeignFile :: Parser FilePath
98+inputForeignFile = strOption $
99+ short 'f'
100+ <> long "ffi"
101+ <> help "The input .js file(s) providing foreign import implementations"
114102
115−browserNamespace :: Parser String
116−browserNamespace = strOption $
117− long "browser-namespace"
118− <> Opts.value "PS"
103+outputDirectory :: Parser FilePath
104+outputDirectory = strOption $
105+ short 'o'
106+ <> long "output"
107+ <> Opts.value "output"
119108 <> showDefault
120− <> help "Specify the namespace that PureScript modules will be exported to when running in the browser."
109+ <> help "The output directory"
121110
122−verboseErrors :: Parser Bool
123−verboseErrors = switch $
124− short 'v'
125− <> long "verbose-errors"
126− <> help "Display verbose error messages"
111+requirePath :: Parser (Maybe FilePath)
112+requirePath = optional $ strOption $
113+ short 'r'
114+ <> long "require-path"
115+ <> help "The path prefix to use for require() calls in the generated JavaScript"
127116
128−noOpts :: Parser Bool
129−noOpts = switch $
130− long "no-opts"
131− <> help "Skip the optimization phase."
132−
133−runMain :: Parser (Maybe String)
134−runMain = optional $ noArgs <|> withArgs
135− where
136− defaultVal = "Main"
137− noArgs = flag' defaultVal (long "main")
138− withArgs = strOption $
139− long "main"
140− <> help (concat [
141− "Generate code to run the main method in the specified module. ",
142− "(no argument: \"", defaultVal, "\")"
143− ])
117+noTco :: Parser Bool
118+noTco = switch $
119+ long "no-tco"
120+ <> help "Disable tail call optimizations"
144121
145122noMagicDo :: Parser Bool
146123noMagicDo = switch $
147124 long "no-magic-do"
148− <> help "Disable the optimization that overloads the do keyword to generate efficient code specifically for the Eff monad."
125+ <> help "Disable the optimization that overloads the do keyword to generate efficient code specifically for the Eff monad"
149126
150−noTco :: Parser Bool
151−noTco = switch $
152− long "no-tco"
153− <> help "Disable tail call optimizations"
127+noOpts :: Parser Bool
128+noOpts = switch $
129+ long "no-opts"
130+ <> help "Skip the optimization phase"
154131
155132comments :: Parser Bool
156133comments = switch $
157134 short 'c'
158135 <> long "comments"
159− <> help "Include comments in the generated code."
160−
161−useStdIn :: Parser Bool
162−useStdIn = switch $
163− short 's'
164− <> long "stdin"
165− <> help "Read from standard input"
166−
167−inputFile :: Parser FilePath
168−inputFile = strArgument $
169− metavar "FILE"
170− <> help "The input .purs file(s)"
136+ <> help "Include comments in the generated code"
171137
172−inputForeignFile :: Parser FilePath
173−inputForeignFile = strOption $
174− short 'f'
175− <> long "ffi"
176− <> help "The input .js file(s) providing foreign import implementations"
177−
178−outputFile :: Parser (Maybe FilePath)
179−outputFile = optional . strOption $
180− short 'o'
181− <> long "output"
182− <> help "The output .js file"
183−
184−externsFile :: Parser (Maybe FilePath)
185−externsFile = optional . strOption $
186− short 'e'
187− <> long "externs"
188− <> help "The output .e.purs file"
138+verboseErrors :: Parser Bool
139+verboseErrors = switch $
140+ short 'v'
141+ <> long "verbose-errors"
142+ <> help "Display verbose error messages"
189143
190144noPrefix :: Parser Bool
191145noPrefix = switch $
@@ -193,33 +147,27 @@ noPrefix = switch $
193147 <> long "no-prefix"
194148 <> help "Do not include comment header"
195149
196−options :: Parser (P.Options P.Compile)
150+
151+options :: Parser P.Options
197152options = P.Options <$> noTco
198153 <*> noMagicDo
199− <*> runMain
154+ <*> pure Nothing
200155 <*> noOpts
201156 <*> verboseErrors
202157 <*> (not <$> comments)
203− <*> additionalOptions
204− where
205− additionalOptions =
206− P.CompileOptions <$> browserNamespace
207− <*> many dceModule
208− <*> many codeGenModule
209−
210−pscOptions :: Parser PSCOptions
211−pscOptions = PSCOptions <$> many inputFile
212− <*> many inputForeignFile
213− <*> options
214− <*> useStdIn
215− <*> outputFile
216− <*> externsFile
217− <*> (not <$> noPrefix)
158+ <*> requirePath
159+
160+pscMakeOptions :: Parser PSCMakeOptions
161+pscMakeOptions = PSCMakeOptions <$> many inputFile
162+ <*> many inputForeignFile
163+ <*> outputDirectory
164+ <*> options
165+ <*> (not <$> noPrefix)
218166
219167main :: IO ()
220168main = execParser opts >>= compile
221169 where
222− opts = info (version <*> helper <*> pscOptions) infoModList
170+ opts = info (version <*> helper <*> pscMakeOptions) infoModList
223171 infoModList = fullDesc <> headerInfo <> footerInfo
224172 headerInfo = header "psc - Compiles PureScript to Javascript"
225173 footerInfo = footer $ "psc " ++ showVersion Paths.version
psci/Completion.hs+9−6
@@ -6,6 +6,7 @@ import Data.Char (isUpper)
66import Data.Function (on)
77import Data.Traversable (traverse)
88
9+import Control.Arrow (second)
910import Control.Applicative ((<$>), (<*>))
1011import Control.Monad.Trans.Reader (asks, runReaderT, ReaderT)
1112import Control.Monad.Trans.State.Strict
@@ -196,13 +197,15 @@ typeDecls = mapMaybe getTypeName . filter P.isDataDecl . P.exportedDeclarations
196197 getTypeName _ = Nothing
197198
198199identNames :: P.Module -> [(N.Ident, P.Declaration)]
199−identNames = nubOnFst . mapMaybe getDeclName . P.exportedDeclarations
200+identNames = nubOnFst . concatMap getDeclNames . P.exportedDeclarations
200201 where
201− getDeclName :: P.Declaration -> Maybe (P.Ident, P.Declaration)
202− getDeclName d@(P.ValueDeclaration ident _ _ _) = Just (ident, d)
203− getDeclName d@(P.ExternDeclaration ident _) = Just (ident, d)
204− getDeclName (P.PositionedDeclaration _ _ d) = getDeclName d
205− getDeclName _ = Nothing
202+ getDeclNames :: P.Declaration -> [(P.Ident, P.Declaration)]
203+ getDeclNames d@(P.ValueDeclaration ident _ _ _) = [(ident, d)]
204+ getDeclNames d@(P.TypeDeclaration ident _ ) = [(ident, d)]
205+ getDeclNames d@(P.ExternDeclaration ident _) = [(ident, d)]
206+ getDeclNames d@(P.TypeClassDeclaration _ _ _ ds) = map (second (const d)) $ concatMap getDeclNames ds
207+ getDeclNames (P.PositionedDeclaration _ _ d) = getDeclNames d
208+ getDeclNames _ = []
206209
207210dctorNames :: P.Module -> [(N.ProperName, P.Declaration)]
208211dctorNames = nubOnFst . concatMap go . P.exportedDeclarations
psci/Make.hsdeleted−127
@@ -1,127 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Make
4−-- Copyright : (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors
5−-- License : MIT
6−--
7−-- Maintainer : Phil Freeman <paf31@cantab.net>
8−-- Stability : experimental
9−-- Portability :
10−--
11−-- |
12−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE DataKinds #-}
16−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
17−{-# LANGUAGE TupleSections #-}
18−
19−module Make where
20−
21−import Data.List (isPrefixOf)
22−import Data.Maybe (fromMaybe)
23−import Data.Time.Clock
24−import Data.Traversable (traverse)
25−import qualified Data.Map as M
26−
27−import Control.Applicative
28−import Control.Monad
29−import Control.Monad.Error.Class (MonadError(..))
30−import Control.Monad.IO.Class (MonadIO, liftIO)
31−import Control.Monad.Reader (MonadReader, ReaderT, runReaderT)
32−import Control.Monad.Trans.Except (ExceptT(..), runExceptT)
33−import Control.Monad.Writer (MonadWriter, WriterT, runWriterT, tell)
34−
35−import System.Directory (getModificationTime, doesFileExist)
36−import System.FilePath ((</>), pathSeparator)
37−import System.IO.Error (tryIOError)
38−
39−import qualified Language.PureScript as P
40−import qualified Language.PureScript.CodeGen.JS as J
41−import qualified Language.PureScript.CoreFn as CF
42−
43−import IO (mkdirp)
44−
45−options :: P.Options P.Make
46−options = P.Options False False Nothing False False False P.MakeOptions
47−
48−modulesDir :: FilePath
49−modulesDir = ".psci_modules" ++ pathSeparator : "node_modules"
50−
51−newtype Make a = Make { unMake :: ReaderT (P.Options P.Make) (WriterT P.MultipleErrors (ExceptT P.MultipleErrors IO)) a }
52− deriving (Functor, Applicative, Monad, MonadIO, MonadError P.MultipleErrors, MonadWriter P.MultipleErrors, MonadReader (P.Options P.Make))
53−
54−runMake :: Make a -> IO (Either P.MultipleErrors a)
55−runMake = runExceptT . fmap fst . runWriterT . flip runReaderT options . unMake
56−
57−makeIO :: (IOError -> P.ErrorMessage) -> IO a -> Make a
58−makeIO f io = do
59− e <- liftIO $ tryIOError io
60− either (throwError . P.singleError . f) return e
61−
62−-- Traverse (Either e) instance (base 4.7)
63−traverseEither :: Applicative f => (a -> f b) -> Either e a -> f (Either e b)
64−traverseEither _ (Left x) = pure (Left x)
65−traverseEither f (Right y) = Right <$> f y
66−
67−buildMakeActions :: M.Map P.ModuleName (Either P.RebuildPolicy String)
68− -> M.Map P.ModuleName P.ForeignJS
69− -> P.MakeActions Make
70−buildMakeActions filePathMap foreigns =
71− P.MakeActions getInputTimestamp getOutputTimestamp readExterns codegen progress
72− where
73−
74− getInputTimestamp :: P.ModuleName -> Make (Either P.RebuildPolicy (Maybe UTCTime))
75− getInputTimestamp mn = do
76− let path = fromMaybe (error "Module has no filename in 'make'") $ M.lookup mn filePathMap
77− traverseEither getTimestamp path
78−
79− getOutputTimestamp :: P.ModuleName -> Make (Maybe UTCTime)
80− getOutputTimestamp mn = do
81− let filePath = P.runModuleName mn
82− jsFile = modulesDir </> filePath </> "index.js"
83− externsFile = modulesDir </> filePath </> "externs.purs"
84− min <$> getTimestamp jsFile <*> getTimestamp externsFile
85−
86− readExterns :: P.ModuleName -> Make (FilePath, String)
87− readExterns mn = do
88− let path = modulesDir </> P.runModuleName mn </> "externs.purs"
89− (path, ) <$> readTextFile path
90−
91− codegen :: CF.Module CF.Ann -> P.Environment -> P.SupplyVar -> P.Externs -> Make ()
92− codegen m _ nextVar exts = do
93− let mn = CF.moduleName m
94− foreignInclude <- case CF.moduleName m `M.lookup` foreigns of
95− Just path
96− | not $ requiresForeign m -> do tell $ P.errorMessage $ P.UnnecessaryFFIModule mn path
97− return Nothing
98− | otherwise -> return $ Just $ J.JSApp (J.JSVar "require") [J.JSStringLiteral "./foreign"]
99− Nothing | requiresForeign m -> throwError . P.errorMessage $ P.MissingFFIModule mn
100− | otherwise -> return Nothing
101− pjs <- P.evalSupplyT nextVar $ P.prettyPrintJS <$> J.moduleToJs m foreignInclude
102− let filePath = P.runModuleName $ CF.moduleName m
103− jsFile = modulesDir </> filePath </> "index.js"
104− externsFile = modulesDir </> filePath </> "externs.purs"
105− foreignFile = modulesDir </> filePath </> "foreign.js"
106− writeTextFile jsFile pjs
107− maybe (return ()) (writeTextFile foreignFile) $ CF.moduleName m `M.lookup` foreigns
108− writeTextFile externsFile exts
109−
110− requiresForeign :: CF.Module a -> Bool
111− requiresForeign = not . null . CF.moduleForeign
112−
113− getTimestamp :: FilePath -> Make (Maybe UTCTime)
114− getTimestamp path = makeIO (const (P.SimpleErrorWrapper $ P.CannotGetFileInfo path)) $ do
115− exists <- doesFileExist path
116− traverse (const $ getModificationTime path) $ guard exists
117−
118− readTextFile :: FilePath -> Make String
119− readTextFile path = makeIO (const (P.SimpleErrorWrapper $ P.CannotReadFile path)) $ readFile path
120−
121− writeTextFile :: FilePath -> String -> Make ()
122− writeTextFile path text = makeIO (const (P.SimpleErrorWrapper $ P.CannotWriteFile path)) $ do
123− mkdirp path
124− writeFile path text
125−
126− progress :: String -> Make ()
127− progress s = unless ("Compiling $PSCI" `isPrefixOf` s) $ liftIO . putStrLn $ s
psci/PSCi.hs+56−23
@@ -30,10 +30,12 @@ import qualified Data.Map as M
3030import Control.Applicative
3131import Control.Arrow (first)
3232import Control.Monad
33+import Control.Monad.Error.Class (MonadError(..))
3334import Control.Monad.Trans.Class
3435import Control.Monad.Trans.Except (runExceptT)
3536import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
3637import Control.Monad.Trans.State.Strict
38+import Control.Monad.IO.Class (liftIO)
3739import Control.Monad.Writer (runWriter)
3840import qualified Control.Monad.Trans.State.Lazy as L
3941
@@ -43,7 +45,9 @@ import System.Console.Haskeline
4345import System.Directory (doesFileExist, findExecutable, getHomeDirectory, getCurrentDirectory)
4446import System.Exit
4547import System.FilePath (pathSeparator, (</>), isPathSeparator)
48+import System.FilePath.Glob (glob)
4649import System.Process (readProcessWithExitCode)
50+import System.IO.Error (tryIOError)
4751
4852import qualified Language.PureScript as P
4953import qualified Language.PureScript.Names as N
@@ -52,7 +56,6 @@ import qualified Paths_purescript as Paths
5256import qualified Directive as D
5357import Completion (completion)
5458import IO (mkdirp)
55−import Make
5659import Parser (parseCommand)
5760import Types
5861
@@ -88,12 +91,15 @@ supportModule =
8891
8992-- File helpers
9093
94+onFirstFileMatching :: Monad m => (b -> m (Maybe a)) -> [b] -> m (Maybe a)
95+onFirstFileMatching f pathVariants = runMaybeT . msum $ map (MaybeT . f) pathVariants
96+
9197-- |
9298-- Locates the node executable.
9399-- Checks for either @nodejs@ or @node@.
94100--
95101findNodeProcess :: IO (Maybe String)
96−findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names
102+findNodeProcess = onFirstFileMatching findExecutable names
97103 where names = ["nodejs", "node"]
98104
99105-- |
@@ -216,12 +222,12 @@ createTemporaryModule exec PSCiState{psciImportedModules = imports, psciLetBindi
216222-- Makes a volatile module to hold a non-qualified type synonym for a fully-qualified data type declaration.
217223--
218224createTemporaryModuleForKind :: PSCiState -> P.Type -> P.Module
219−createTemporaryModuleForKind PSCiState{psciImportedModules = imports} typ =
225+createTemporaryModuleForKind PSCiState{psciImportedModules = imports, psciLetBindings = lets} typ =
220226 let
221227 moduleName = P.ModuleName [P.ProperName "$PSCI"]
222228 itDecl = P.TypeSynonymDeclaration (P.ProperName "IT") [] typ
223229 in
224− P.Module [] moduleName ((importDecl `map` imports) ++ [itDecl]) Nothing
230+ P.Module [] moduleName ((importDecl `map` imports) ++ lets ++ [itDecl]) Nothing
225231
226232-- |
227233-- Makes a volatile module to execute the current imports.
@@ -239,10 +245,25 @@ importDecl (mn, declType, asQ) = P.ImportDeclaration mn declType asQ
239245indexFile :: FilePath
240246indexFile = ".psci_modules" ++ pathSeparator : "index.js"
241247
242−make :: PSCiState -> [(Either P.RebuildPolicy FilePath, P.Module)] -> Make P.Environment
243−make PSCiState{..} ms =
244− let filePathMap = M.fromList $ (first P.getModuleName . swap) `map` (psciLoadedModules ++ ms)
245− in P.make (buildMakeActions filePathMap (M.map snd psciForeignFiles)) (psciLoadedModules ++ ms)
248+modulesDir :: FilePath
249+modulesDir = ".psci_modules" ++ pathSeparator : "node_modules"
250+
251+-- | This is different than the runMake in 'Language.PureScript.Make' in that it specifies the
252+-- options and ignores the warning messages.
253+runMake :: P.Make a -> IO (Either P.MultipleErrors a)
254+runMake mk = fmap (fmap fst) $ P.runMake P.defaultOptions mk
255+
256+makeIO :: (IOError -> P.ErrorMessage) -> IO a -> P.Make a
257+makeIO f io = do
258+ e <- liftIO $ tryIOError io
259+ either (throwError . P.singleError . f) return e
260+
261+make :: PSCiState -> [(Either P.RebuildPolicy FilePath, P.Module)] -> P.Make P.Environment
262+make PSCiState{..} ms = P.make actions' (map snd (psciLoadedModules ++ ms))
263+ where
264+ filePathMap = M.fromList $ (first P.getModuleName . swap) `map` (psciLoadedModules ++ ms)
265+ actions = P.buildMakeActions modulesDir filePathMap psciForeignFiles False
266+ actions' = actions { P.progress = const (return ()) }
246267
247268-- |
248269-- Takes a value declaration and evaluates it with the current state.
@@ -314,6 +335,7 @@ handleShowImportedModules = do
314335 showRef (P.ValueRef ident) = show ident
315336 showRef (P.TypeClassRef pn) = show pn
316337 showRef (P.TypeInstanceRef ident) = show ident
338+ showRef (P.ModuleRef name) = "module " ++ show name
317339 showRef (P.PositionedDeclarationRef _ _ ref) = showRef ref
318340
319341 commaList :: [String] -> String
@@ -467,18 +489,27 @@ whenFileExists filePath f = do
467489 then f absPath
468490 else PSCI . outputStrLn $ "Couldn't locate: " ++ filePath
469491
492+-- |
493+-- Attempts to read initial commands from '.psci' in the present working
494+-- directory then the user's home
495+--
470496loadUserConfig :: IO (Maybe [Command])
471−loadUserConfig = do
472− configFile <- (</> ".psci") <$> getCurrentDirectory
473− exists <- doesFileExist configFile
474− if exists
475− then do
476− ls <- lines <$> readFile configFile
477− case mapM parseCommand ls of
478− Left err -> print err >> exitFailure
479− Right cs -> return $ Just cs
480− else
481− return Nothing
497+loadUserConfig = onFirstFileMatching readCommands pathGetters
498+ where
499+ pathGetters = [getCurrentDirectory, getHomeDirectory]
500+ readCommands :: IO FilePath -> IO (Maybe [Command])
501+ readCommands path = do
502+ configFile <- (</> ".psci") <$> path
503+ exists <- doesFileExist configFile
504+ if exists
505+ then do
506+ ls <- lines <$> readFile configFile
507+ case mapM parseCommand ls of
508+ Left err -> print err >> exitFailure
509+ Right cs -> return $ Just cs
510+ else
511+ return Nothing
512+
482513
483514-- | Checks if the Console module is defined
484515consoleIsDefined :: [P.Module] -> Bool
@@ -490,19 +521,21 @@ consoleIsDefined = any ((== P.ModuleName (map P.ProperName [ "Control", "Monad",
490521loop :: PSCiOptions -> IO ()
491522loop PSCiOptions{..} = do
492523 config <- loadUserConfig
493− modulesOrFirstError <- loadAllModules psciInputFile
524+ inputFiles <- concat <$> mapM glob psciInputFile
525+ foreignFiles <- concat <$> mapM glob psciForeignInputFiles
526+ modulesOrFirstError <- loadAllModules inputFiles
494527 case modulesOrFirstError of
495528 Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> exitFailure
496529 Right modules -> do
497530 historyFilename <- getHistoryFilename
498531 let settings = defaultSettings { historyFile = Just historyFilename }
499532 foreignsOrError <- runMake $ do
500− foreignFiles <- forM psciForeignInputFiles (\inFile -> (inFile,) <$> makeIO (const (P.SimpleErrorWrapper $ P.CannotReadFile inFile)) (readFile inFile))
501− P.parseForeignModulesFromFiles foreignFiles
533+ foreignFilesContent <- forM foreignFiles (\inFile -> (inFile,) <$> makeIO (const (P.SimpleErrorWrapper $ P.CannotReadFile inFile)) (readFile inFile))
534+ P.parseForeignModulesFromFiles foreignFilesContent
502535 case foreignsOrError of
503536 Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> exitFailure
504537 Right foreigns ->
505− flip evalStateT (PSCiState psciInputFile [] modules foreigns [] psciInputNodeFlags) . runInputT (setComplete completion settings) $ do
538+ flip evalStateT (PSCiState inputFiles [] modules foreigns [] psciInputNodeFlags) . runInputT (setComplete completion settings) $ do
506539 outputStrLn prologueMessage
507540 traverse_ (mapM_ (runPSCI . handleCommand)) config
508541 modules' <- lift $ gets psciLoadedModules
psci/tests/Main.hs+35−29
@@ -8,12 +8,13 @@ import Control.Applicative
88import Control.Monad.Writer (runWriterT)
99import Control.Monad.Trans.Except (runExceptT)
1010
11−import Data.List (isSuffixOf, sort)
11+import Data.List (sort)
1212
1313import System.Exit (exitFailure)
1414import System.Console.Haskeline
1515import System.FilePath ((</>))
16−import System.Directory (getCurrentDirectory, getDirectoryContents)
16+import System.Directory (getCurrentDirectory)
17+import qualified System.FilePath.Glob as Glob
1718
1819import Test.HUnit
1920
@@ -48,9 +49,14 @@ completionTestData =
4849 , (":mo", [":module"])
4950 , (":b", [":browse"])
5051
51− -- :browse should complete modules
52− , (":b Prel", [":b Prelude", ":b Prelude.Unsafe"])
53− , (":b Prelude.", [":b Prelude.Unsafe"])
52+ -- :browse should complete module names
53+ , (":b Control.Monad.E", map (":b Control.Monad.Eff" ++) ["", ".Unsafe", ".Class", ".Console"])
54+ , (":b Control.Monad.Eff.", map (":b Control.Monad.Eff" ++) [".Unsafe", ".Class", ".Console"])
55+
56+ -- import should complete module names
57+ , ("import Control.Monad.E", map ("import Control.Monad.Eff" ++) ["", ".Unsafe", ".Class", ".Console"])
58+ , ("import Control.Monad.Eff.", map ("import Control.Monad.Eff" ++) [".Unsafe", ".Class", ".Console"])
59+ , ("import qualified Control.Monad.Eff.", map ("import qualified Control.Monad.Eff" ++) [".Unsafe", ".Class", ".Console"])
5460
5561 -- :load, :module should complete file paths
5662 , (":l psci/tests/data/", [":l psci/tests/data/Sample.purs"])
@@ -66,8 +72,8 @@ completionTestData =
6672 , (":show a", [])
6773
6874 -- :type should complete values and data constructors in scope
69− , (":type Prelude.Unsafe.un", [":type Prelude.Unsafe.unsafeIndex"])
70− , (":type un", [":type unit"])
75+ , (":type Control.Monad.Eff.Console.lo", [":type Control.Monad.Eff.Console.log"])
76+ , (":type uni", [":type unit"])
7177 , (":type E", [":type EQ"])
7278
7379 -- :kind should complete types in scope
@@ -79,25 +85,19 @@ completionTestData =
7985 , (":type EQ ", [])
8086 , (":kind Ordering ", [])
8187
82− -- import should complete module names
83− , ("import Control.Monad.S", ["import Control.Monad.ST"])
84− , ("import qualified Control.Monad.S", ["import qualified Control.Monad.ST"])
85− , ("import Control.Monad.", map ("import Control.Monad." ++)
86− ["Eff", "ST"])
87−
8888 -- a few other import tests
8989 , ("impor", ["import"])
9090 , ("import q", ["import qualified"])
91− , ("import ", map ("import " ++) allModuleNames ++ ["import qualified"])
92− , ("import Prelude.Unsafe ", [])
91+ , ("import ", map ("import " ++) supportModules ++ ["import qualified"])
92+ , ("import Prelude ", [])
9393
9494 -- String and number literals should not be completed
9595 , ("\"hi", [])
9696 , ("34", [])
9797
9898 -- Identifiers and data constructors should be completed
99− , ("un", ["unit"])
100− , ("Debug.Trace.", map ("Debug.Trace." ++) ["print", "trace"])
99+ , ("uni", ["unit"])
100+ , ("Control.Monad.Eff.Class.", ["Control.Monad.Eff.Class.liftEff"])
101101 , ("G", ["GT"])
102102 , ("Prelude.L", ["Prelude.LT"])
103103
@@ -107,14 +107,6 @@ completionTestData =
107107 , ("Control.Monad.ST.new", ["Control.Monad.ST.newSTRef"])
108108 ]
109109 where
110− allModuleNames = [ "Assert"
111− , "Control.Monad.Eff"
112− , "Control.Monad.ST"
113− , "Data.Function"
114− , "Debug.Trace"
115− , "Prelude"
116− , "Prelude.Unsafe"
117− ]
118110
119111assertCompletedOk :: (String, [String]) -> Assertion
120112assertCompletedOk (line, expecteds) = do
@@ -131,10 +123,12 @@ runCM act = do
131123getPSCiState :: IO PSCiState
132124getPSCiState = do
133125 cwd <- getCurrentDirectory
134− let preludeDir = cwd </> "tests" </> "prelude"
135− jsDir = preludeDir </> "js"
136− modulesOrFirstError <- loadAllModules [ preludeDir </> "Prelude.purs" ]
137− jsFiles <- map (jsDir </>) . filter (".js" `isSuffixOf`) <$> getDirectoryContents jsDir
126+ let supportDir = cwd </> "tests" </> "support" </> "flattened"
127+ let supportFiles ext = Glob.globDir1 (Glob.compile ("*." ++ ext)) supportDir
128+ pursFiles <- supportFiles "purs"
129+ jsFiles <- supportFiles "js"
130+
131+ modulesOrFirstError <- loadAllModules pursFiles
138132 foreignFiles <- forM jsFiles (\f -> (f,) <$> readFile f)
139133 Right (foreigns, _) <- runExceptT $ runWriterT $ P.parseForeignModulesFromFiles foreignFiles
140134 case modulesOrFirstError of
@@ -148,3 +142,15 @@ controlMonadSTasST :: ImportedModule
148142controlMonadSTasST = (s "Control.Monad.ST", P.Implicit, Just (s "ST"))
149143 where
150144 s = P.moduleNameFromString
145+
146+supportModules :: [String]
147+supportModules =
148+ [ "Control.Monad.Eff.Class"
149+ , "Control.Monad.Eff.Console"
150+ , "Control.Monad.Eff"
151+ , "Control.Monad.Eff.Unsafe"
152+ , "Control.Monad.ST"
153+ , "Data.Function"
154+ , "Prelude"
155+ , "Test.Assert"
156+ ]
purescript.cabal+52−35
@@ -1,10 +1,10 @@
11name: purescript
2−version: 0.7.0.0
2+version: 0.7.2.0
33cabal-version: >=1.8
44build-type: Simple
55license: MIT
66license-file: LICENSE
7−copyright: (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors
7+copyright: (c) 2013-15 Phil Freeman, (c) 2014-15 Gary Burgess
88maintainer: Phil Freeman <paf31@cantab.net>
99stability: experimental
1010synopsis: PureScript Programming Language Compiler
@@ -13,12 +13,17 @@ category: Language
1313Homepage: http://www.purescript.org/
1414author: Phil Freeman <paf31@cantab.net>,
1515 Gary Burgess <gary.burgess@gmail.com>,
16− Hardy Jones <jones3.hardy@gmail.com>
16+ Hardy Jones <jones3.hardy@gmail.com>,
17+ Harry Garrood <harry@garrood.me>
1718
1819tested-with: GHC==7.8
1920
2021extra-source-files: examples/passing/*.purs
2122 , examples/failing/*.purs
23+ , tests/support/setup.js
24+ , tests/support/package.json
25+ , tests/support/bower.json
26+ , psci/tests/data/Sample.purs
2227
2328source-repository head
2429 type: git
@@ -42,10 +47,16 @@ library
4247 aeson >= 0.8 && < 0.9,
4348 vector -any,
4449 bower-json >= 0.7,
45− aeson-better-errors >= 0.7,
50+ aeson-better-errors >= 0.8,
4651 bytestring -any,
4752 text -any,
48− split -any
53+ split -any,
54+ language-javascript == 0.5.*,
55+ syb -any,
56+ Glob >= 0.7 && < 0.8,
57+ process >= 1.2.0 && < 1.3,
58+ safe >= 0.3.9 && < 0.4,
59+ semigroups >= 0.16.2 && < 0.17
4960
5061 exposed-modules: Language.PureScript
5162 Language.PureScript.AST
@@ -55,6 +66,7 @@ library
5566 Language.PureScript.AST.SourcePos
5667 Language.PureScript.AST.Traversals
5768 Language.PureScript.AST.Exported
69+ Language.PureScript.Bundle
5870 Language.PureScript.CodeGen
5971 Language.PureScript.CodeGen.Externs
6072 Language.PureScript.CodeGen.JS
@@ -78,11 +90,12 @@ library
7890 Language.PureScript.CoreFn.Module
7991 Language.PureScript.CoreFn.Traversals
8092 Language.PureScript.Comments
81− Language.PureScript.DeadCodeElimination
8293 Language.PureScript.Environment
8394 Language.PureScript.Errors
8495 Language.PureScript.Kinds
8596 Language.PureScript.Linter
97+ Language.PureScript.Linter.Exhaustive
98+ Language.PureScript.Make
8699 Language.PureScript.ModuleDependencies
87100 Language.PureScript.Names
88101 Language.PureScript.Options
@@ -126,6 +139,7 @@ library
126139 Language.PureScript.Types
127140
128141 Language.PureScript.Docs
142+ Language.PureScript.Docs.Convert
129143 Language.PureScript.Docs.Render
130144 Language.PureScript.Docs.Types
131145 Language.PureScript.Docs.RenderedCode
@@ -135,6 +149,11 @@ library
135149 Language.PureScript.Docs.ParseAndDesugar
136150 Language.PureScript.Docs.Utils.MonoidExtras
137151
152+ Language.PureScript.Publish
153+ Language.PureScript.Publish.Utils
154+ Language.PureScript.Publish.ErrorsWarnings
155+ Language.PureScript.Publish.BoxesHelpers
156+
138157 Control.Monad.Unify
139158 Control.Monad.Supply
140159 Control.Monad.Supply.Class
@@ -148,28 +167,17 @@ library
148167executable psc
149168 build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
150169 mtl -any, optparse-applicative >= 0.10.0, parsec -any, purescript -any,
151− transformers -any
170+ time -any, transformers -any, transformers-compat -any, Glob >= 0.7 && < 0.8
152171 main-is: Main.hs
153172 buildable: True
154173 hs-source-dirs: psc
155− other-modules:
156− ghc-options: -Wall -O2 -fno-warn-unused-do-bind
157−
158−executable psc-make
159− build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
160− mtl -any, optparse-applicative >= 0.10.0, parsec -any, purescript -any,
161− time -any, transformers -any, transformers-compat -any
162− main-is: Main.hs
163− buildable: True
164− hs-source-dirs: psc-make
165− other-modules: Make
166174 ghc-options: -Wall -O2 -fno-warn-unused-do-bind
167175
168176executable psci
169177 build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
170178 mtl -any, optparse-applicative >= 0.10.0, parsec -any,
171179 haskeline >= 0.7.0.0, purescript -any, transformers -any,
172− transformers-compat -any, process -any, time -any
180+ transformers-compat -any, process -any, time -any, Glob -any
173181
174182 main-is: Main.hs
175183 buildable: True
@@ -179,15 +187,14 @@ executable psci
179187 Directive
180188 Completion
181189 PSCi
182− Make
183190 IO
184191 ghc-options: -Wall -O2
185192
186193executable psc-docs
187194 build-depends: base >=4 && <5, purescript -any,
188195 optparse-applicative >= 0.10.0, process -any, mtl -any,
189− split -any, ansi-wl-pprint -any, directory -any, filepath
190− -any
196+ split -any, ansi-wl-pprint -any, directory -any,
197+ filepath -any, Glob -any
191198 main-is: Main.hs
192199 buildable: True
193200 hs-source-dirs: psc-docs
@@ -197,34 +204,43 @@ executable psc-docs
197204 ghc-options: -Wall -O2
198205
199206executable psc-publish
200− build-depends: base >=4 && <5, purescript -any,
201− optparse-applicative >= 0.10.0, process -any, mtl -any,
202− pattern-arrows -any, aeson -any, bytestring -any,
203− directory -any, transformers -any, text -any, containers
204− -any, boxes -any, split -any, Glob -any, aeson-better-errors
205− -any, transformers-compat -any, bower-json -any, semigroups
206− -any, safe -any
207+ build-depends: base >=4 && <5, purescript -any, bytestring -any, aeson -any, optparse-applicative -any
207208 main-is: Main.hs
208209 buildable: True
209210 hs-source-dirs: psc-publish
210− other-modules: Utils
211− ErrorsWarnings
212− BoxesHelpers
213211 ghc-options: -Wall -O2
214212
215213executable psc-hierarchy
216214 build-depends: base >=4 && <5, purescript -any, optparse-applicative >= 0.10.0,
217− process -any, mtl -any, parsec -any, filepath -any, directory -any
215+ process -any, mtl -any, parsec -any, filepath -any, directory -any,
216+ Glob -any
218217 main-is: Main.hs
219218 buildable: True
220219 hs-source-dirs: hierarchy
221220 other-modules:
222221 ghc-options: -Wall -O2
223222
223+executable psc-bundle
224+ main-is: Main.hs
225+ other-modules:
226+ other-extensions:
227+ build-depends: base >=4 && <5,
228+ purescript -any,
229+ filepath -any,
230+ directory -any,
231+ mtl -any,
232+ transformers -any,
233+ transformers-compat -any,
234+ optparse-applicative >= 0.10.0,
235+ Glob -any
236+ ghc-options: -Wall -O2
237+ hs-source-dirs: psc-bundle
238+
224239test-suite tests
225240 build-depends: base >=4 && <5, containers -any, directory -any,
226241 filepath -any, mtl -any, parsec -any, purescript -any,
227− transformers -any, process -any, transformers-compat -any
242+ transformers -any, process -any, transformers-compat -any, time -any,
243+ Glob -any
228244 type: exitcode-stdio-1.0
229245 main-is: Main.hs
230246 buildable: True
@@ -234,7 +250,8 @@ test-suite psci-tests
234250 build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
235251 mtl -any, optparse-applicative >= 0.10.0, parsec -any,
236252 haskeline >= 0.7.0.0, purescript -any, transformers -any,
237− transformers-compat -any, process -any, HUnit -any, time -any
253+ transformers-compat -any, process -any, HUnit -any, time -any,
254+ Glob -any
238255 type: exitcode-stdio-1.0
239256 main-is: Main.hs
240257 buildable: True
src/Language/PureScript.hs+1−244
@@ -20,41 +20,18 @@
2020
2121module Language.PureScript
2222 ( module P
23− , compile
24− , compile'
25− , compileJS
26− , RebuildPolicy(..)
27− , MakeActions(..)
28− , SupplyVar()
29− , Externs()
30− , make
3123 , version
3224 ) where
3325
34−import Data.Function (on)
35−import Data.List (sortBy, groupBy, intercalate)
36−import Data.Maybe (fromMaybe)
37−import Data.Time.Clock
3826import Data.Version (Version)
39−import qualified Data.Map as M
40−import qualified Data.Set as S
41−
42−import Control.Applicative
43−import Control.Arrow ((&&&))
44−import Control.Monad
45−import Control.Monad.Error.Class (MonadError(..))
46−import Control.Monad.Reader
47−import Control.Monad.Writer
48−import Control.Monad.Supply.Class (MonadSupply, fresh)
4927
5028import Language.PureScript.AST as P
5129import Language.PureScript.Comments as P
52−import Language.PureScript.CodeGen.Externs (moduleToPs)
53−import Language.PureScript.DeadCodeElimination as P
5430import Language.PureScript.Environment as P
5531import Language.PureScript.Errors as P
5632import Language.PureScript.Kinds as P
5733import Language.PureScript.Linter as P
34+import Language.PureScript.Make as P
5835import Language.PureScript.ModuleDependencies as P
5936import Language.PureScript.Names as P
6037import Language.PureScript.Options as P
@@ -65,228 +42,8 @@ import Language.PureScript.Sugar as P
6542import Control.Monad.Supply as P
6643import Language.PureScript.TypeChecker as P
6744import Language.PureScript.Types as P
68−import qualified Language.PureScript.CoreFn as CoreFn
69−import qualified Language.PureScript.Constants as C
70−import qualified Language.PureScript.CodeGen.JS as J
7145
7246import qualified Paths_purescript as Paths
7347
74−-- |
75−-- Compile a collection of modules
76−--
77−-- The compilation pipeline proceeds as follows:
78−--
79−-- * Sort the modules based on module dependencies, checking for cyclic dependencies.
80−--
81−-- * Perform a set of desugaring passes.
82−--
83−-- * Type check, and elaborate values to include type annotations and type class dictionaries.
84−--
85−-- * Regroup values to take into account new value dependencies introduced by elaboration.
86−--
87−-- * Eliminate dead code.
88−--
89−-- * Generate Javascript, and perform optimization passes.
90−--
91−-- * Pretty-print the generated Javascript
92−--
93−compile :: (Functor m, Applicative m, MonadError MultipleErrors m, MonadWriter MultipleErrors m, MonadReader (Options Compile) m)
94− => [Module] -> m ([CoreFn.Module CoreFn.Ann], Environment, SupplyVar, Externs)
95−compile = compile' initEnvironment
96−
97−compile' :: (Functor m, Applicative m, MonadError MultipleErrors m, MonadWriter MultipleErrors m, MonadReader (Options Compile) m)
98− => Environment -> [Module] -> m ([CoreFn.Module CoreFn.Ann], Environment, SupplyVar, Externs)
99−compile' env ms = do
100− additional <- asks optionsAdditional
101− mainModuleIdent <- asks (fmap moduleNameFromString . optionsMain)
102− (sorted, _) <- sortModules $ map importPrim ms
103− mapM_ lint sorted
104− (desugared, nextVar) <- runSupplyT 0 $ desugar sorted
105− (elaborated, env') <- runCheck' env $ forM desugared $ typeCheckModule mainModuleIdent
106− regrouped <- createBindingGroupsModule . collapseBindingGroupsModule $ elaborated
107− let corefn = map (CoreFn.moduleToCoreFn env') regrouped
108− entryPoints = moduleNameFromString `map` entryPointModules additional
109− elim = if null entryPoints then corefn else eliminateDeadCode entryPoints corefn
110− renamed = renameInModules elim
111− codeGenModuleNames = moduleNameFromString `map` codeGenModules additional
112− modulesToCodeGen = if null codeGenModuleNames then renamed else filter (\(CoreFn.Module _ mn _ _ _ _) -> mn `elem` codeGenModuleNames) renamed
113− exts = intercalate "\n" . map (`moduleToPs` env') $ regrouped
114− return (modulesToCodeGen, env', nextVar, exts)
115−
116−-- |
117−-- Compile a collection of modules to JavaScript and externs files
118−--
119−compileJS :: forall m. (Functor m, Applicative m, MonadError P.MultipleErrors m, MonadWriter P.MultipleErrors m, MonadReader (P.Options P.Compile) m)
120− => [P.Module] -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> [String] -> m (String, String, Environment)
121−compileJS ms foreigns prefix = do
122− (modulesToCodeGen, env, nextVar, exts) <- compile ms
123− js <- concat <$> evalSupplyT nextVar (P.parU modulesToCodeGen codegenModule)
124− js' <- generateMain env js
125− let pjs = unlines $ map ("// " ++) prefix ++ [P.prettyPrintJS js']
126− return (pjs, exts, env)
127−
128− where
129−
130− codegenModule :: (Functor n, Applicative n, MonadError P.MultipleErrors n, MonadWriter P.MultipleErrors n, MonadReader (P.Options P.Compile) n, MonadSupply n)
131− => CoreFn.Module CoreFn.Ann -> n [J.JS]
132− codegenModule m =
133− let requiresForeign = not $ null (CoreFn.moduleForeign m)
134− mn = CoreFn.moduleName m
135− in case mn `M.lookup` foreigns of
136− Just (path, js)
137− | not requiresForeign -> do
138− tell $ P.errorMessage $ P.UnnecessaryFFIModule mn path
139− J.moduleToJs m Nothing
140− | otherwise -> J.moduleToJs m $ Just $
141− J.JSApp (J.JSFunction Nothing [] $
142− J.JSBlock [ J.JSVariableIntroduction "exports" (Just $ J.JSObjectLiteral [])
143− , J.JSRaw js
144− , J.JSReturn (J.JSVar "exports")
145− ]) []
146− Nothing | requiresForeign -> throwError . P.errorMessage $ P.MissingFFIModule mn
147− | otherwise -> J.moduleToJs m Nothing
148−
149− generateMain :: P.Environment -> [J.JS] -> m [J.JS]
150− generateMain env js = do
151− mainName <- asks P.optionsMain
152− additional <- asks P.optionsAdditional
153− case P.moduleNameFromString <$> mainName of
154− Just mmi -> do
155− when ((mmi, P.Ident C.main) `M.notMember` P.names env) $
156− throwError . P.errorMessage $ P.NameIsUndefined (P.Ident C.main)
157− return $ js ++ [J.mainCall mmi (P.browserNamespace additional)]
158− _ -> return js
159−
160−-- |
161−-- Actions that require implementations when running in "make" mode.
162−--
163−data MakeActions m = MakeActions {
164− -- |
165− -- Get the timestamp for the input file(s) for a module. If there are multiple
166− -- files (.purs and foreign files, for example) the timestamp should be for
167− -- the most recently modified file.
168− --
169− getInputTimestamp :: ModuleName -> m (Either RebuildPolicy (Maybe UTCTime))
170− -- |
171− -- Get the timestamp for the output files for a module. This should be the
172− -- timestamp for the oldest modified file, or Nothing if any of the required
173− -- output files are missing.
174− --
175− , getOutputTimestamp :: ModuleName -> m (Maybe UTCTime)
176− -- |
177− -- Read the externs file for a module as a string and also return the actual
178− -- path for the file.
179− , readExterns :: ModuleName -> m (FilePath, String)
180− -- |
181− -- Run the code generator for the module and write any required output files.
182− --
183− , codegen :: CoreFn.Module CoreFn.Ann -> Environment -> SupplyVar -> Externs -> m ()
184− -- |
185− -- Respond to a progress update.
186− --
187− , progress :: String -> m ()
188− }
189−
190−-- |
191−-- Generated code for an externs file.
192−--
193−type Externs = String
194−
195−-- |
196−-- A value to be used in the Supply monad.
197−--
198−type SupplyVar = Integer
199−
200−-- |
201−-- Determines when to rebuild a module
202−--
203−data RebuildPolicy
204− -- | Never rebuild this module
205− = RebuildNever
206− -- | Always rebuild this module
207− | RebuildAlways deriving (Show, Eq, Ord)
208−
209−-- |
210−-- Compiles in "make" mode, compiling each module separately to a js files and an externs file
211−--
212−-- If timestamps have not changed, the externs file can be used to provide the module's types without
213−-- having to typecheck the module again.
214−--
215−make :: forall m. (Functor m, Applicative m, Monad m, MonadReader (P.Options P.Make) m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
216− => MakeActions m
217− -> [(Either RebuildPolicy FilePath, Module)]
218− -> m Environment
219−make MakeActions{..} ms = do
220− (sorted, graph) <- sortModules $ map (importPrim . snd) ms
221− mapM_ lint sorted
222− toRebuild <- foldM (\s (Module _ moduleName' _ _) -> do
223− inputTimestamp <- getInputTimestamp moduleName'
224− outputTimestamp <- getOutputTimestamp moduleName'
225− return $ case (inputTimestamp, outputTimestamp) of
226− (Right (Just t1), Just t2) | t1 < t2 -> s
227− (Left RebuildNever, Just _) -> s
228− _ -> S.insert moduleName' s) S.empty sorted
229−
230− marked <- rebuildIfNecessary (reverseDependencies graph) toRebuild sorted
231− (desugared, nextVar) <- runSupplyT 0 $ zip (map fst marked) <$> desugar (map snd marked)
232− evalSupplyT nextVar $ go initEnvironment desugared
233− where
234−
235− go :: Environment -> [(Bool, Module)] -> SupplyT m Environment
236− go env [] = return env
237− go env ((False, m) : ms') = do
238− (_, env') <- lift . runCheck' env $ typeCheckModule Nothing m
239− go env' ms'
240− go env ((True, m@(Module coms moduleName' _ exps)) : ms') = do
241− lift $ progress $ "Compiling " ++ runModuleName moduleName'
242− (Module _ _ elaborated _, env') <- lift . runCheck' env $ typeCheckModule Nothing m
243− regrouped <- createBindingGroups moduleName' . collapseBindingGroups $ elaborated
244− let mod' = Module coms moduleName' regrouped exps
245− corefn = CoreFn.moduleToCoreFn env' mod'
246− [renamed] = renameInModules [corefn]
247− exts = moduleToPs mod' env'
248− nextVar <- fresh
249− lift $ codegen renamed env' nextVar exts
250− go env' ms'
251−
252− rebuildIfNecessary :: M.Map ModuleName [ModuleName] -> S.Set ModuleName -> [Module] -> m [(Bool, Module)]
253− rebuildIfNecessary _ _ [] = return []
254− rebuildIfNecessary graph toRebuild (m@(Module _ moduleName' _ _) : ms') | moduleName' `S.member` toRebuild = do
255− let deps = fromMaybe [] $ moduleName' `M.lookup` graph
256− toRebuild' = toRebuild `S.union` S.fromList deps
257− (:) (True, m) <$> rebuildIfNecessary graph toRebuild' ms'
258− rebuildIfNecessary graph toRebuild (Module _ moduleName' _ _ : ms') = do
259− (path, externs) <- readExterns moduleName'
260− externsModules <- fmap (map snd) . alterErrors $ P.parseModulesFromFiles id [(path, externs)]
261− case externsModules of
262− [m'@(Module _ moduleName'' _ _)] | moduleName'' == moduleName' -> (:) (False, m') <$> rebuildIfNecessary graph toRebuild ms'
263− _ -> throwError . errorMessage . InvalidExternsFile $ path
264− where
265− alterErrors = flip catchError $ \(MultipleErrors errs) ->
266− throwError . MultipleErrors $ flip map errs $ \e -> case e of
267− SimpleErrorWrapper (ErrorParsingModule err) -> SimpleErrorWrapper (ErrorParsingExterns err)
268− _ -> e
269−
270−reverseDependencies :: ModuleGraph -> M.Map ModuleName [ModuleName]
271−reverseDependencies g = combine [ (dep, mn) | (mn, deps) <- g, dep <- deps ]
272− where
273− combine :: (Ord a) => [(a, b)] -> M.Map a [b]
274− combine = M.fromList . map ((fst . head) &&& map snd) . groupBy ((==) `on` fst) . sortBy (compare `on` fst)
275−
276−-- |
277−-- Add an import declaration for a module if it does not already explicitly import it.
278−--
279−addDefaultImport :: ModuleName -> Module -> Module
280−addDefaultImport toImport m@(Module coms mn decls exps) =
281− if isExistingImport `any` decls || mn == toImport then m
282− else Module coms mn (ImportDeclaration toImport Implicit Nothing : decls) exps
283− where
284− isExistingImport (ImportDeclaration mn' _ _) | mn' == toImport = True
285− isExistingImport (PositionedDeclaration _ _ d) = isExistingImport d
286− isExistingImport _ = False
287−
288−importPrim :: Module -> Module
289−importPrim = addDefaultImport (ModuleName [ProperName C.prim])
290−
29148version :: Version
29249version = Paths.version
src/Language/PureScript/AST/Binders.hs+1−1
@@ -69,7 +69,7 @@ data Binder
6969 -- |
7070 -- A binder with source position information
7171 --
72− | PositionedBinder SourceSpan [Comment] Binder deriving (Show, D.Data, D.Typeable)
72+ | PositionedBinder SourceSpan [Comment] Binder deriving (Show, Eq, D.Data, D.Typeable)
7373
7474-- |
7575-- Collect all names introduced in binders in an expression
src/Language/PureScript/AST/Declarations.hs+7−1
@@ -17,6 +17,7 @@
1717module Language.PureScript.AST.Declarations where
1818
1919import qualified Data.Data as D
20+import qualified Data.Map as M
2021
2122import Language.PureScript.AST.Binders
2223import Language.PureScript.AST.Operators
@@ -60,6 +61,10 @@ data DeclarationRef
6061 --
6162 | TypeInstanceRef Ident
6263 -- |
64+ -- A module, in its entirety
65+ --
66+ | ModuleRef ModuleName
67+ -- |
6368 -- A declaration reference with source position information
6469 --
6570 | PositionedDeclarationRef SourceSpan [Comment] DeclarationRef
@@ -70,6 +75,7 @@ instance Eq DeclarationRef where
7075 (ValueRef name) == (ValueRef name') = name == name'
7176 (TypeClassRef name) == (TypeClassRef name') = name == name'
7277 (TypeInstanceRef name) == (TypeInstanceRef name') = name == name'
78+ (ModuleRef name) == (ModuleRef name') = name == name'
7379 (PositionedDeclarationRef _ _ r) == r' = r == r'
7480 r == (PositionedDeclarationRef _ _ r') = r == r'
7581 _ == _ = False
@@ -360,7 +366,7 @@ data Expr
360366 -- at superclass implementations when searching for a dictionary, the type class name and
361367 -- instance type, and the type class dictionaries in scope.
362368 --
363− | TypeClassDictionary Bool Constraint [TypeClassDictionaryInScope]
369+ | TypeClassDictionary Bool Constraint (M.Map (Maybe ModuleName) (M.Map (Qualified ProperName) (M.Map (Qualified Ident) TypeClassDictionaryInScope)))
364370 -- |
365371 -- A typeclass dictionary accessor, the implementation is left unspecified until CoreFn desugaring.
366372 --
src/Language/PureScript/AST/Exported.hs+12−8
@@ -98,8 +98,10 @@ typeInstanceConstituents _ = []
9898
9999
100100-- |
101−-- Test if a declaration is exported, given a module's export list. Prefer
102−-- 'exportedDeclarations' to this function, where possible.
101+-- Test if a declaration is exported, given a module's export list. Note that
102+-- this function does not account for type instance declarations of
103+-- non-exported types, or non-exported data constructors. Therefore, you should
104+-- prefer 'exportedDeclarations' to this function, where possible.
103105--
104106isExported :: Maybe [DeclarationRef] -> Declaration -> Bool
105107isExported Nothing _ = True
@@ -107,13 +109,15 @@ isExported _ TypeInstanceDeclaration{} = True
107109isExported exps (PositionedDeclaration _ _ d) = isExported exps d
108110isExported (Just exps) decl = any (matches decl) exps
109111 where
110− matches (TypeDeclaration ident _) (ValueRef ident') = ident == ident'
111− matches (ValueDeclaration ident _ _ _) (ValueRef ident') = ident == ident'
112− matches (ExternDeclaration ident _) (ValueRef ident') = ident == ident'
113− matches (DataDeclaration _ ident _ _) (TypeRef ident' _) = ident == ident'
114− matches (ExternDataDeclaration ident _) (TypeRef ident' _) = ident == ident'
115− matches (TypeSynonymDeclaration ident _ _) (TypeRef ident' _) = ident == ident'
112+ matches (TypeDeclaration ident _) (ValueRef ident') = ident == ident'
113+ matches (ValueDeclaration ident _ _ _) (ValueRef ident') = ident == ident'
114+ matches (ExternDeclaration ident _) (ValueRef ident') = ident == ident'
115+ matches (FixityDeclaration _ name) (ValueRef ident') = name == runIdent ident'
116+ matches (DataDeclaration _ ident _ _) (TypeRef ident' _) = ident == ident'
117+ matches (ExternDataDeclaration ident _) (TypeRef ident' _) = ident == ident'
118+ matches (TypeSynonymDeclaration ident _ _) (TypeRef ident' _) = ident == ident'
116119 matches (TypeClassDeclaration ident _ _ _) (TypeClassRef ident') = ident == ident'
120+
117121 matches (PositionedDeclaration _ _ d) r = d `matches` r
118122 matches d (PositionedDeclarationRef _ _ r) = d `matches` r
119123 matches _ _ = False
src/Language/PureScript/AST/Operators.hs+14−2
@@ -12,11 +12,14 @@
1212--
1313-----------------------------------------------------------------------------
1414
15+{-# LANGUAGE OverloadedStrings #-}
1516{-# LANGUAGE DeriveDataTypeable #-}
1617
1718module Language.PureScript.AST.Operators where
1819
1920import qualified Data.Data as D
21+import Data.Aeson ((.=))
22+import qualified Data.Aeson as A
2023
2124-- |
2225-- A precedence level for an infix operator
@@ -26,14 +29,23 @@ type Precedence = Integer
2629-- |
2730-- Associativity for infix operators
2831--
29−data Associativity = Infixl | Infixr | Infix deriving (D.Data, D.Typeable)
32+data Associativity = Infixl | Infixr | Infix deriving (Eq, Ord, D.Data, D.Typeable)
3033
3134instance Show Associativity where
3235 show Infixl = "infixl"
3336 show Infixr = "infixr"
3437 show Infix = "infix"
3538
39+instance A.ToJSON Associativity where
40+ toJSON = A.toJSON . show
41+
3642-- |
3743-- Fixity data for infix operators
3844--
39−data Fixity = Fixity Associativity Precedence deriving (Show, D.Data, D.Typeable)
45+data Fixity = Fixity Associativity Precedence deriving (Show, Eq, Ord, D.Data, D.Typeable)
46+
47+instance A.ToJSON Fixity where
48+ toJSON (Fixity associativity precedence) =
49+ A.object [ "associativity" .= associativity
50+ , "precedence" .= precedence
51+ ]
src/Language/PureScript/AST/SourcePos.hs+6−2
@@ -57,11 +57,15 @@ data SourceSpan = SourceSpan
5757 , spanEnd :: SourcePos
5858 } deriving (Eq, Ord, Show, D.Data, D.Typeable)
5959
60+displayStartEndPos :: SourceSpan -> String
61+displayStartEndPos sp =
62+ displaySourcePos (spanStart sp) ++ " - " ++
63+ displaySourcePos (spanEnd sp)
64+
6065displaySourceSpan :: SourceSpan -> String
6166displaySourceSpan sp =
6267 spanName sp ++ " " ++
63− displaySourcePos (spanStart sp) ++ " - " ++
64− displaySourcePos (spanEnd sp)
68+ displayStartEndPos sp
6569
6670instance A.ToJSON SourceSpan where
6771 toJSON SourceSpan{..} =
src/Language/PureScript/Bundle.hsnew file+545
@@ -0,0 +1,545 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : psc-bundle
4+-- Copyright : (c) Phil Freeman 2015
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- | Bundles compiled PureScript modules for the browser.
12+--
13+-- This module takes as input the individual generated modules from 'Language.PureScript.Make' and
14+-- performs dead code elimination, filters empty modules,
15+-- and generates the final Javascript bundle.
16+-----------------------------------------------------------------------------
17+
18+{-# LANGUAGE PatternGuards #-}
19+{-# LANGUAGE FlexibleContexts #-}
20+{-# LANGUAGE ScopedTypeVariables #-}
21+{-# LANGUAGE TupleSections #-}
22+{-# LANGUAGE RecordWildCards #-}
23+
24+module Language.PureScript.Bundle (
25+ bundle
26+ , ModuleIdentifier(..)
27+ , moduleName
28+ , ModuleType(..)
29+ , ErrorMessage(..)
30+ , printErrorMessage
31+) where
32+
33+import Data.List (nub)
34+import Data.Maybe (mapMaybe, catMaybes)
35+import Data.Generics (everything, everywhere, mkQ, mkT)
36+import Data.Graph
37+import Data.Version (showVersion)
38+
39+import qualified Data.Set as S
40+
41+import Control.Applicative
42+import Control.Monad
43+import Control.Monad.Error.Class
44+import Language.JavaScript.Parser
45+
46+import qualified Paths_purescript as Paths
47+
48+-- | The type of error messages. We separate generation and rendering of errors using a data
49+-- type, in case we need to match on error types later.
50+data ErrorMessage
51+ = UnsupportedModulePath String
52+ | InvalidTopLevel
53+ | UnableToParseModule String
54+ | UnsupportedExport
55+ | ErrorInModule ModuleIdentifier ErrorMessage
56+ deriving Show
57+
58+-- | Modules are either "regular modules" (i.e. those generated by psc) or foreign modules.
59+data ModuleType
60+ = Regular
61+ | Foreign
62+ deriving (Show, Eq, Ord)
63+
64+-- | A module is identified by its module name and its type.
65+data ModuleIdentifier = ModuleIdentifier String ModuleType deriving (Show, Eq, Ord)
66+
67+moduleName :: ModuleIdentifier -> String
68+moduleName (ModuleIdentifier name _) = name
69+
70+-- | A piece of code is identified by its module and its name. These keys are used to label vertices
71+-- in the dependency graph.
72+type Key = (ModuleIdentifier, String)
73+
74+-- | An export is either a "regular export", which exports a name from the regular module we are in,
75+-- or a reexport of a declaration in the corresponding foreign module.
76+--
77+-- Regular exports are labelled, since they might re-export an operator with another name.
78+data ExportType
79+ = RegularExport String
80+ | ForeignReexport
81+ deriving (Show, Eq, Ord)
82+
83+-- | There are four types of module element we are interested in:
84+--
85+-- 1) Require statements
86+-- 2) Member declarations
87+-- 3) Export lists
88+-- 4) Everything else
89+--
90+-- Each is labelled with the original AST node which generated it, so that we can dump it back
91+-- into the output during codegen.
92+data ModuleElement
93+ = Require JSNode String ModuleIdentifier
94+ | Member JSNode Bool String [JSNode] [Key]
95+ | ExportsList [(ExportType, String, JSNode, [Key])]
96+ | Other JSNode
97+ deriving Show
98+
99+-- | A module is just a list of elements of the types listed above.
100+data Module = Module ModuleIdentifier [ModuleElement] deriving Show
101+
102+-- | Prepare an error message for consumption by humans.
103+printErrorMessage :: ErrorMessage -> [String]
104+printErrorMessage (UnsupportedModulePath s) =
105+ [ "A CommonJS module has an unsupported name (" ++ show s ++ ")."
106+ , "The following file names are supported:"
107+ , " 1) index.js (psc native modules)"
108+ , " 2) foreign.js (psc foreign modules)"
109+ ]
110+printErrorMessage InvalidTopLevel =
111+ [ "Expected a list of source elements at the top level." ]
112+printErrorMessage (UnableToParseModule err) =
113+ [ "The module could not be parsed:"
114+ , err
115+ ]
116+printErrorMessage UnsupportedExport =
117+ [ "An export was unsupported. Exports can be defined in one of two ways: "
118+ , " 1) exports.name = ..."
119+ , " 2) exports = { ... }"
120+ ]
121+printErrorMessage (ErrorInModule mid e) =
122+ ("Error in module " ++ displayIdentifier mid ++ ":")
123+ : ""
124+ : map (" " ++) (printErrorMessage e)
125+ where
126+ displayIdentifier (ModuleIdentifier name ty) =
127+ name ++ " (" ++ show ty ++ ")"
128+
129+-- | Unpack the node inside a JSNode. This is useful when pattern matching.
130+node :: JSNode -> Node
131+node (NN n) = n
132+node (NT n _ _) = n
133+
134+-- | Calculate the ModuleIdentifier which a require(...) statement imports.
135+checkImportPath :: String -> ModuleIdentifier -> S.Set String -> Maybe ModuleIdentifier
136+checkImportPath "./foreign" m _ =
137+ Just (ModuleIdentifier (moduleName m) Foreign)
138+checkImportPath name _ names
139+ | name `S.member` names = Just (ModuleIdentifier name Regular)
140+checkImportPath _ _ _ = Nothing
141+
142+-- | Compute the dependencies of all elements in a module, and add them to the tree.
143+--
144+-- Members and exports can have dependencies. A dependency is of one of the following forms:
145+--
146+-- 1) module.name or member["name"]
147+--
148+-- where module was imported using
149+--
150+-- var module = require("Module.Name");
151+--
152+-- 2) name
153+--
154+-- where name is the name of a member defined in the current module.
155+withDeps :: Module -> Module
156+withDeps (Module modulePath es) = Module modulePath (map expandDeps es)
157+ where
158+ -- | Collects all modules which are imported, so that we can identify dependencies of the first type.
159+ imports :: [(String, ModuleIdentifier)]
160+ imports = mapMaybe toImport es
161+ where
162+ toImport :: ModuleElement -> Maybe (String, ModuleIdentifier)
163+ toImport (Require _ nm mid) = Just (nm, mid)
164+ toImport _ = Nothing
165+
166+ -- | Collects all member names in scope, so that we can identify dependencies of the second type.
167+ boundNames :: [String]
168+ boundNames = mapMaybe toBoundName es
169+ where
170+ toBoundName :: ModuleElement -> Maybe String
171+ toBoundName (Member _ _ nm _ _) = Just nm
172+ toBoundName _ = Nothing
173+
174+ -- | Calculate dependencies and add them to the current element.
175+ expandDeps :: ModuleElement -> ModuleElement
176+ expandDeps (Member n f nm decl _) = Member n f nm decl (nub (concatMap (dependencies modulePath) decl))
177+ expandDeps (ExportsList exps) = ExportsList (map expand exps)
178+ where
179+ expand (ty, nm, n1, _) = (ty, nm, n1, nub (dependencies modulePath n1))
180+ expandDeps other = other
181+
182+ dependencies :: ModuleIdentifier -> JSNode -> [(ModuleIdentifier, String)]
183+ dependencies m = everything (++) (mkQ [] toReference)
184+ where
185+ toReference :: Node -> [(ModuleIdentifier, String)]
186+ toReference (JSMemberDot [ mn ] _ nm)
187+ | JSIdentifier mn' <- node mn
188+ , JSIdentifier nm' <- node nm
189+ , Just mid <- lookup mn' imports
190+ = [(mid, nm')]
191+ toReference (JSMemberSquare [ mn ] _ nm _)
192+ | JSIdentifier mn' <- node mn
193+ , JSExpression [ s ] <- node nm
194+ , JSStringLiteral _ nm' <- node s
195+ , Just mid <- lookup mn' imports
196+ = [(mid, nm')]
197+ toReference (JSIdentifier nm)
198+ | nm `elem` boundNames
199+ = [(m, nm)]
200+ toReference _ = []
201+
202+-- | Attempt to create a Module from a Javascript AST.
203+--
204+-- Each type of module element is matched using pattern guards, and everything else is bundled into the
205+-- Other constructor.
206+toModule :: forall m. (Applicative m, MonadError ErrorMessage m) => S.Set String -> ModuleIdentifier -> JSNode -> m Module
207+toModule mids mid top
208+ | JSSourceElementsTop ns <- node top = Module mid <$> mapM toModuleElement ns
209+ | otherwise = err InvalidTopLevel
210+ where
211+ err = throwError . ErrorInModule mid
212+
213+ toModuleElement :: JSNode -> m ModuleElement
214+ toModuleElement n
215+ | JSVariables var [ varIntro ] _ <- node n
216+ , JSLiteral "var" <- node var
217+ , JSVarDecl impN [ eq, req, impP ] <- node varIntro
218+ , JSIdentifier importName <- node impN
219+ , JSLiteral "=" <- node eq
220+ , JSIdentifier "require" <- node req
221+ , JSArguments _ [ impS ] _ <- node impP
222+ , JSStringLiteral _ importPath <- node impS
223+ , Just importPath' <- checkImportPath importPath mid mids
224+ = pure (Require n importName importPath')
225+ toModuleElement n
226+ | JSVariables var [ varIntro ] _ <- node n
227+ , JSLiteral "var" <- node var
228+ , JSVarDecl declN (eq : decl) <- node varIntro
229+ , JSIdentifier name <- node declN
230+ , JSLiteral "=" <- node eq
231+ = pure (Member n False name decl [])
232+ toModuleElement n
233+ | JSExpression (e : op : decl) <- node n
234+ , Just name <- accessor (node e)
235+ , JSOperator eq <- node op
236+ , JSLiteral "=" <- node eq
237+ = pure (Member n True name decl [])
238+ where
239+ accessor :: Node -> Maybe String
240+ accessor (JSMemberDot [ exports ] _ nm)
241+ | JSIdentifier "exports" <- node exports
242+ , JSIdentifier name <- node nm
243+ = Just name
244+ accessor (JSMemberSquare [ exports ] _ nm _)
245+ | JSIdentifier "exports" <- node exports
246+ , JSExpression [e] <- node nm
247+ , JSStringLiteral _ name <- node e
248+ = Just name
249+ accessor _ = Nothing
250+ toModuleElement n
251+ | JSExpression (mnExp : op : obj: _) <- node n
252+ , JSMemberDot [ mn ] _ e <- node mnExp
253+ , JSIdentifier "module" <- node mn
254+ , JSIdentifier "exports" <- node e
255+ , JSOperator eq <- node op
256+ , JSLiteral "=" <- node eq
257+ , JSObjectLiteral _ props _ <- node obj
258+ = ExportsList <$> mapM toExport (filter (not . isSeparator) (map node props))
259+ where
260+ toExport :: Node -> m (ExportType, String, JSNode, [Key])
261+ toExport (JSPropertyNameandValue name _ [val] ) =
262+ (,,val,[]) <$> exportType (node val)
263+ <*> extractLabel (node name)
264+ toExport _ = err UnsupportedExport
265+
266+ exportType :: Node -> m ExportType
267+ exportType (JSMemberDot [f] _ _)
268+ | JSIdentifier "$foreign" <- node f
269+ = pure ForeignReexport
270+ exportType (JSMemberSquare [f] _ _ _)
271+ | JSIdentifier "$foreign" <- node f
272+ = pure ForeignReexport
273+ exportType (JSIdentifier s) = pure (RegularExport s)
274+ exportType _ = err UnsupportedExport
275+
276+ extractLabel :: Node -> m String
277+ extractLabel (JSStringLiteral _ nm) = pure nm
278+ extractLabel (JSIdentifier nm) = pure nm
279+ extractLabel _ = err UnsupportedExport
280+
281+ isSeparator :: Node -> Bool
282+ isSeparator (JSLiteral ",") = True
283+ isSeparator _ = False
284+ toModuleElement other = pure (Other other)
285+
286+-- | Eliminate unused code based on the specified entry point set.
287+compile :: [Module] -> [ModuleIdentifier] -> [Module]
288+compile modules [] = modules
289+compile modules entryPoints = filteredModules
290+ where
291+ (graph, _, vertexFor) = graphFromEdges verts
292+
293+ -- | The vertex set
294+ verts :: [(ModuleElement, Key, [Key])]
295+ verts = do
296+ Module mid els <- modules
297+ concatMap (toVertices mid) els
298+ where
299+ -- | Create a set of vertices for a module element.
300+ --
301+ -- Some special cases worth commenting on:
302+ --
303+ -- 1) Regular exports which simply export their own name do not count as dependencies.
304+ -- Regular exports which rename and reexport an operator do count, however.
305+ --
306+ -- 2) Require statements don't contribute towards dependencies, since they effectively get
307+ -- inlined wherever they are used inside other module elements.
308+ toVertices :: ModuleIdentifier -> ModuleElement -> [(ModuleElement, Key, [Key])]
309+ toVertices p m@(Member _ _ nm _ deps) = [(m, (p, nm), deps)]
310+ toVertices p m@(ExportsList exps) = mapMaybe toVertex exps
311+ where
312+ toVertex (ForeignReexport, nm, _, ks) = Just (m, (p, nm), ks)
313+ toVertex (RegularExport nm, nm1, _, ks) | nm /= nm1 = Just (m, (p, nm1), ks)
314+ toVertex _ = Nothing
315+ toVertices _ _ = []
316+
317+ -- | The set of vertices whose connected components we are interested in keeping.
318+ entryPointVertices :: [Vertex]
319+ entryPointVertices = catMaybes $ do
320+ (_, k@(mid, _), _) <- verts
321+ guard $ mid `elem` entryPoints
322+ return (vertexFor k)
323+
324+ -- | The set of vertices reachable from an entry point
325+ reachableSet :: S.Set Vertex
326+ reachableSet = S.fromList (concatMap (reachable graph) entryPointVertices)
327+
328+ filteredModules :: [Module]
329+ filteredModules = map filterUsed modules
330+ where
331+ filterUsed :: Module -> Module
332+ filterUsed (Module mid ds) = Module mid (map filterExports (go ds))
333+ where
334+ go :: [ModuleElement] -> [ModuleElement]
335+ go [] = []
336+ go (d : Other semi : rest)
337+ | JSLiteral ";" <- node semi
338+ , not (isDeclUsed d)
339+ = go rest
340+ go (d : rest)
341+ | not (isDeclUsed d) = go rest
342+ | otherwise = d : go rest
343+
344+ -- | Filter out the exports for members which aren't used.
345+ filterExports :: ModuleElement -> ModuleElement
346+ filterExports (ExportsList exps) = ExportsList (filter (\(_, nm, _, _) -> isKeyUsed (mid, nm)) exps)
347+ filterExports me = me
348+
349+ isDeclUsed :: ModuleElement -> Bool
350+ isDeclUsed (Member _ _ nm _ _) = isKeyUsed (mid, nm)
351+ isDeclUsed _ = True
352+
353+ isKeyUsed :: Key -> Bool
354+ isKeyUsed k
355+ | Just me <- vertexFor k = me `S.member` reachableSet
356+ | otherwise = False
357+
358+-- | Topologically sort the module dependency graph, so that when we generate code, modules can be
359+-- defined in the right order.
360+sortModules :: [Module] -> [Module]
361+sortModules modules = map (\v -> case nodeFor v of (n, _, _) -> n) (reverse (topSort graph))
362+ where
363+ (graph, nodeFor, _) = graphFromEdges $ do
364+ m@(Module mid els) <- modules
365+ return (m, mid, mapMaybe getKey els)
366+
367+ getKey :: ModuleElement -> Maybe ModuleIdentifier
368+ getKey (Require _ _ mi) = Just mi
369+ getKey _ = Nothing
370+
371+-- | A module is empty if it contains no exported members (in other words,
372+-- if the only things left after dead code elimination are module imports and
373+-- "other" foreign code).
374+--
375+-- If a module is empty, we don't want to generate code for it.
376+isModuleEmpty :: Module -> Bool
377+isModuleEmpty (Module _ els) = all isElementEmpty els
378+ where
379+ isElementEmpty :: ModuleElement -> Bool
380+ isElementEmpty (ExportsList exps) = null exps
381+ isElementEmpty (Require _ _ _) = True
382+ isElementEmpty (Other _) = True
383+ isElementEmpty _ = False
384+
385+-- | Generate code for a set of modules, including a call to main().
386+--
387+-- Modules get defined on the global PS object, as follows:
388+--
389+-- var PS = { };
390+-- (function(exports) {
391+-- ...
392+-- })(PS["Module.Name"] = PS["Module.Name"] || {});
393+--
394+-- In particular, a module and its foreign imports share the same namespace inside PS.
395+-- This saves us from having to generate unique names for a module and its foreign imports,
396+-- and is safe since a module shares a namespace with its foreign imports in PureScript as well
397+-- (so there is no way to have overlaps in code generated by psc).
398+codeGen :: Maybe String -- ^ main module
399+ -> String -- ^ namespace
400+ -> [Module] -- ^ input modules
401+ -> String
402+codeGen optionsMainModule optionsNamespace ms = renderToString (NN (JSSourceElementsTop (prelude ++ concatMap moduleToJS ms ++ maybe [] runMain optionsMainModule)))
403+ where
404+ moduleToJS :: Module -> [JSNode]
405+ moduleToJS (Module mn ds) = wrap (moduleName mn) (indent (concatMap declToJS ds))
406+ where
407+ declToJS :: ModuleElement -> [JSNode]
408+ declToJS (Member n _ _ _ _) = [n]
409+ declToJS (Other n) = [n]
410+ declToJS (Require _ nm req) =
411+ [ NN (JSVariables (NT (JSLiteral "var") tokenPosnEmpty [ WhiteSpace tokenPosnEmpty "\n " ])
412+ [ NN (JSVarDecl (sp (JSIdentifier nm))
413+ [ sp (JSLiteral "=")
414+ , moduleReference sp (moduleName req)
415+ ])
416+ ]
417+ (nt (JSLiteral ";"))) ]
418+ declToJS (ExportsList exps) = map toExport exps
419+
420+ where
421+ toExport :: (ExportType, String, JSNode, [Key]) -> JSNode
422+ toExport (_, nm, val, _) =
423+ NN (JSExpression [ NN (JSMemberSquare [ NT (JSIdentifier "exports") tokenPosnEmpty [ WhiteSpace tokenPosnEmpty "\n " ] ]
424+ (nt (JSLiteral "["))
425+ (NN (JSExpression [ nt (JSStringLiteral '"' nm) ]))
426+ (nt (JSLiteral "]")))
427+ , NN (JSOperator (sp (JSLiteral "=")))
428+ , reindent val
429+ , nt (JSLiteral ";")
430+ ])
431+
432+ reindent :: JSNode -> JSNode
433+ reindent (NT n _ _) = sp n
434+ reindent nn = nn
435+
436+ indent :: [JSNode] -> [JSNode]
437+ indent = everywhere (mkT squash)
438+ where
439+ squash (NT n pos ann) = NT n (keepCol pos) (map splat ann)
440+ squash nn = nn
441+
442+ splat (CommentA pos s) = CommentA (keepCol pos) s
443+ splat (WhiteSpace pos w) = WhiteSpace (keepCol pos) w
444+ splat ann = ann
445+
446+ keepCol (TokenPn _ _ c) = TokenPn 0 0 (c + 2)
447+
448+ prelude :: [JSNode]
449+ prelude =
450+ [ NN (JSVariables (NT (JSLiteral "var") tokenPosnEmpty [ CommentA tokenPosnEmpty ("// Generated by psc-bundle " ++ showVersion Paths.version)
451+ , WhiteSpace tokenPosnEmpty "\n"
452+ ])
453+ [ NN (JSVarDecl (sp (JSIdentifier optionsNamespace))
454+ [ sp (JSLiteral "=")
455+ , NN (JSObjectLiteral (sp (JSLiteral "{"))
456+ []
457+ (sp (JSLiteral "}")))
458+ ])
459+ ]
460+ (nt (JSLiteral ";")))
461+ , lf
462+ ]
463+
464+ moduleReference :: (Node -> JSNode) -> String -> JSNode
465+ moduleReference f mn =
466+ NN (JSMemberSquare [ f (JSIdentifier optionsNamespace) ]
467+ (nt (JSLiteral "["))
468+ (NN (JSExpression [ nt (JSStringLiteral '"' mn) ]))
469+ (nt (JSLiteral "]")))
470+
471+ wrap :: String -> [JSNode] -> [JSNode]
472+ wrap mn ds =
473+ [ NN (JSExpression [ NN (JSExpressionParen (nt (JSLiteral "("))
474+ (NN (JSExpression [ NN (JSFunctionExpression (nt (JSLiteral "function"))
475+ []
476+ (nt (JSLiteral "(") ) [nt (JSIdentifier "exports")] (nt (JSLiteral ")"))
477+ (NN (JSBlock [sp (JSLiteral "{")]
478+ (lf : ds)
479+ [nl (JSLiteral "}")])))]))
480+ (nt (JSLiteral ")")))
481+ , NN (JSArguments (nt (JSLiteral "("))
482+ [ NN (JSExpression [ moduleReference nt mn
483+ , NN (JSOperator (sp (JSLiteral "=")))
484+ , NN (JSExpressionBinary "||"
485+ [ moduleReference sp mn ]
486+ (sp (JSLiteral "||"))
487+ [ emptyObj ])
488+ ])
489+ ]
490+ (nt (JSLiteral ")")))
491+ ])
492+ , nt (JSLiteral ";")
493+ , lf
494+ ]
495+ where
496+ emptyObj = NN (JSObjectLiteral (sp (JSLiteral "{")) [] (nt (JSLiteral "}")))
497+
498+ runMain :: String -> [JSNode]
499+ runMain mn =
500+ [ NN (JSExpression [ NN (JSMemberDot [ NN (JSMemberSquare [ nl (JSIdentifier optionsNamespace) ]
501+ (nt (JSLiteral "["))
502+ (NN (JSExpression [ nt (JSStringLiteral '"' mn) ]))
503+ (nt (JSLiteral "]")))
504+ ]
505+ (nt (JSLiteral "."))
506+ (nt (JSIdentifier "main")))
507+ , NN (JSArguments (nt (JSLiteral "(")) [] (nt (JSLiteral ")")))
508+ ])
509+ , nt (JSLiteral ";")
510+ ]
511+
512+ nt :: Node -> JSNode
513+ nt n = NT n tokenPosnEmpty []
514+
515+ lf :: JSNode
516+ lf = NT (JSLiteral "") tokenPosnEmpty [ WhiteSpace tokenPosnEmpty "\n" ]
517+
518+ sp :: Node -> JSNode
519+ sp n = NT n tokenPosnEmpty [ WhiteSpace tokenPosnEmpty " " ]
520+
521+ nl :: Node -> JSNode
522+ nl n = NT n tokenPosnEmpty [ WhiteSpace tokenPosnEmpty "\n" ]
523+
524+-- | The bundling function.
525+-- This function performs dead code elimination, filters empty modules
526+-- and generates and prints the final Javascript bundle.
527+bundle :: forall m. (Applicative m, MonadError ErrorMessage m)
528+ => [(ModuleIdentifier, String)] -- ^ The input modules. Each module should be javascript rendered from 'Language.PureScript.Make' or @psc@.
529+ -> [ModuleIdentifier] -- ^ Entry points. These module identifiers are used as the roots for dead-code elimination
530+ -> Maybe String -- ^ An optional main module.
531+ -> String -- ^ The namespace (e.g. PS).
532+ -> m String
533+bundle inputStrs entryPoints mainModule namespace = do
534+ input <- forM inputStrs $ \(ident, js) -> do
535+ ast <- either (throwError . ErrorInModule ident . UnableToParseModule) pure $ parse js (moduleName ident)
536+ return (ident, ast)
537+
538+ let mids = S.fromList (map (moduleName . fst) input)
539+
540+ modules <- mapM (fmap withDeps . uncurry (toModule mids)) input
541+
542+ let compiled = compile modules entryPoints
543+ sorted = sortModules (filter (not . isModuleEmpty) compiled)
544+
545+ return (codeGen mainModule namespace sorted)
src/Language/PureScript/CodeGen/Externs.hs+17−2
@@ -38,11 +38,24 @@ import Language.PureScript.Types
3838moduleToPs :: Module -> Environment -> String
3939moduleToPs (Module _ _ _ Nothing) _ = error "Module exports were not elaborated in moduleToPs"
4040moduleToPs (Module _ moduleName ds (Just exts)) env = intercalate "\n" . execWriter $ do
41− tell [ "module " ++ runModuleName moduleName ++ " where"]
41+ let exps = listExports exts
42+ tell ["module " ++ runModuleName moduleName ++ (if null exps then "" else " (" ++ exps ++ ")") ++ " where"]
4243 mapM_ declToPs ds
4344 mapM_ exportToPs exts
4445 where
4546
47+ listExports :: [DeclarationRef] -> String
48+ listExports = intercalate ", " . mapMaybe listExport
49+
50+ listExport :: DeclarationRef -> Maybe String
51+ listExport (PositionedDeclarationRef _ _ d) = listExport d
52+ listExport (TypeRef name Nothing) = Just $ show name ++ "()"
53+ listExport (TypeRef name (Just dctors)) = Just $ show name ++ "(" ++ intercalate ", " (map show dctors) ++ ")"
54+ listExport (ValueRef name) = Just $ show name
55+ listExport (TypeClassRef name) = Just $ show name
56+ listExport (ModuleRef name) = Just $ "module " ++ show name
57+ listExport _ = Nothing
58+
4659 declToPs :: Declaration -> Writer [String] ()
4760 declToPs (ImportDeclaration mn _ _) = tell ["import " ++ show mn ++ " ()"]
4861 declToPs (FixityDeclaration (Fixity assoc prec) op) =
@@ -107,12 +120,14 @@ moduleToPs (Module _ moduleName ds (Just exts)) env = intercalate "\n" . execWri
107120
108121 exportToPs (TypeInstanceRef ident) = do
109122 let TypeClassDictionaryInScope { tcdClassName = className, tcdInstanceTypes = tys, tcdDependencies = deps} =
110− fromMaybe (error $ "Type class instance has no dictionary in exportToPs") . find (\tcd -> tcdName tcd == Qualified (Just moduleName) ident && tcdType tcd == TCDRegular) $ M.elems $ typeClassDictionaries env
123+ fromMaybe (error $ "Type class instance has no dictionary in exportToPs") . find (\tcd -> tcdName tcd == Qualified (Just moduleName) ident && tcdType tcd == TCDRegular) . maybe [] (M.elems >=> M.elems) . M.lookup (Just moduleName) $ typeClassDictionaries env
111124 let constraintsText = case fromMaybe [] deps of
112125 [] -> ""
113126 cs -> "(" ++ intercalate ", " (map (\(pn, tys') -> show pn ++ " " ++ unwords (map prettyPrintTypeAtom tys')) cs) ++ ") => "
114127 tell ["foreign import instance " ++ show ident ++ " :: " ++ constraintsText ++ show className ++ " " ++ unwords (map prettyPrintTypeAtom tys)]
115128
129+ exportToPs (ModuleRef _) = return ()
130+
116131 toTypeVar :: (String, Maybe Kind) -> Type
117132 toTypeVar (s, Nothing) = TypeVar s
118133 toTypeVar (s, Just k) = KindedType (TypeVar s) k
src/Language/PureScript/CodeGen/JS.hs+7−17
@@ -44,18 +44,18 @@ import Language.PureScript.Options
4444import Language.PureScript.Traversals (sndM)
4545import qualified Language.PureScript.Constants as C
4646
47+import System.FilePath.Posix ((</>))
48+
4749-- |
4850-- Generate code in the simplified Javascript intermediate representation for all declarations in a
4951-- module.
5052--
51−moduleToJs :: forall m mode. (Applicative m, Monad m, MonadReader (Options mode) m, MonadSupply m)
53+moduleToJs :: forall m. (Applicative m, Monad m, MonadReader Options m, MonadSupply m)
5254 => Module Ann -> Maybe JS -> m [JS]
5355moduleToJs (Module coms mn imps exps foreigns decls) foreign = do
54− additional <- asks optionsAdditional
5556 jsImports <- T.traverse importToJs . delete (ModuleName [ProperName C.prim]) . (\\ [mn]) $ imps
5657 jsDecls <- mapM bindToJs decls
5758 optimized <- T.traverse (T.traverse optimize) jsDecls
58− let isModuleEmpty = null exps
5959 comments <- not <$> asks optionsNoComments
6060 let strict = JSStringLiteral "use strict"
6161 let header = if comments && not (null coms) then JSComment coms strict else strict
@@ -65,15 +65,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign = do
6565 let standardExps = exps \\ foreignExps
6666 let exps' = JSObjectLiteral $ map (runIdent &&& JSVar . identToJs) standardExps
6767 ++ map (runIdent &&& foreignIdent) foreignExps
68− return $ case additional of
69− MakeOptions -> moduleBody ++ [JSAssignment (JSAccessor "exports" (JSVar "module")) exps']
70− CompileOptions ns _ _ | not isModuleEmpty ->
71− [ JSVariableIntroduction ns
72− (Just (JSBinary Or (JSVar ns) (JSObjectLiteral [])) )
73− , JSAssignment (JSAccessor (moduleNameToJs mn) (JSVar ns))
74− (JSApp (JSFunction Nothing [] (JSBlock (moduleBody ++ [JSReturn exps']))) [])
75− ]
76− _ -> []
68+ return $ moduleBody ++ [JSAssignment (JSAccessor "exports" (JSVar "module")) exps']
7769
7870 where
7971
@@ -82,10 +74,8 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign = do
8274 --
8375 importToJs :: ModuleName -> m JS
8476 importToJs mn' = do
85− additional <- asks optionsAdditional
86− let moduleBody = case additional of
87− MakeOptions -> JSApp (JSVar "require") [JSStringLiteral (runModuleName mn')]
88− CompileOptions ns _ _ -> JSAccessor (moduleNameToJs mn') (JSVar ns)
77+ path <- asks optionsRequirePath
78+ let moduleBody = JSApp (JSVar "require") [JSStringLiteral (maybe id (</>) path $ runModuleName mn')]
8979 return $ JSVariableIntroduction (moduleNameToJs mn') (Just moduleBody)
9080
9181 -- |
@@ -284,7 +274,7 @@ moduleToJs (Module coms mn imps exps foreigns decls) foreign = do
284274 failedPatternError names = JSUnary JSNew $ JSApp (JSVar "Error") [JSBinary Add (JSStringLiteral errorMessage) (JSArrayLiteral $ zipWith valueError names vals)]
285275
286276 errorMessage :: String
287− errorMessage = "Failed pattern match" ++ maybe "" ((" at " ++) . displaySourceSpan) maybeSpan ++ ": "
277+ errorMessage = "Failed pattern match" ++ maybe "" (((" at " ++ runModuleName mn ++ " ") ++) . displayStartEndPos) maybeSpan ++ ": "
288278
289279 valueError :: String -> JS -> JS
290280 valueError _ l@(JSNumericLiteral _) = l
src/Language/PureScript/CodeGen/JS/AST.hs+2−1
@@ -23,6 +23,7 @@ import Data.Data
2323import Data.Traversable (traverse)
2424
2525import Language.PureScript.Comments
26+import Language.PureScript.Traversals
2627
2728-- |
2829-- Built-in unary operators
@@ -294,7 +295,7 @@ everywhereOnJSTopDownM f = f >=> go
294295 go (JSBinary op j1 j2) = JSBinary op <$> f' j1 <*> f' j2
295296 go (JSArrayLiteral js) = JSArrayLiteral <$> traverse f' js
296297 go (JSIndexer j1 j2) = JSIndexer <$> f' j1 <*> f' j2
297− go (JSObjectLiteral js) = JSObjectLiteral <$> traverse (traverse f') js
298+ go (JSObjectLiteral js) = JSObjectLiteral <$> traverse (sndM f') js
298299 go (JSAccessor prop j) = JSAccessor prop <$> f' j
299300 go (JSFunction name args j) = JSFunction name args <$> f' j
300301 go (JSApp j js) = JSApp <$> f' j <*> traverse f' js
src/Language/PureScript/CodeGen/JS/Optimizer.hs+2−2
@@ -55,12 +55,12 @@ import Language.PureScript.CodeGen.JS.Optimizer.Blocks
5555-- |
5656-- Apply a series of optimizer passes to simplified Javascript code
5757--
58−optimize :: (Monad m, MonadReader (Options mode) m, Applicative m, MonadSupply m) => JS -> m JS
58+optimize :: (Monad m, MonadReader Options m, Applicative m, MonadSupply m) => JS -> m JS
5959optimize js = do
6060 noOpt <- asks optionsNoOptimizations
6161 if noOpt then return js else optimize' js
6262
63−optimize' :: (Monad m, MonadReader (Options mode) m, Applicative m, MonadSupply m) => JS -> m JS
63+optimize' :: (Monad m, MonadReader Options m, Applicative m, MonadSupply m) => JS -> m JS
6464optimize' js = do
6565 opts <- ask
6666 untilFixedPoint (inlineArrComposition . applyAll
src/Language/PureScript/CodeGen/JS/Optimizer/Inliner.hs+12−15
@@ -156,11 +156,11 @@ inlineCommonOperators = applyAll $
156156 , binary semigroupString (C.<>) Add
157157 , binary semigroupString (C.++) Add
158158
159− , binary latticeBoolean (C.&&) And
160− , binary latticeBoolean (C.||) Or
161− , binaryFunction latticeBoolean C.inf And
162− , binaryFunction latticeBoolean C.sup Or
163− , unary complementedLatticeBoolean C.not Not
159+ , binary booleanAlgebraBoolean (C.&&) And
160+ , binary booleanAlgebraBoolean (C.||) Or
161+ , binaryFunction booleanAlgebraBoolean C.conj And
162+ , binaryFunction booleanAlgebraBoolean C.disj Or
163+ , unary booleanAlgebraBoolean C.not Not
164164
165165 , binary' C.dataIntBits (C..|.) BitwiseOr
166166 , binary' C.dataIntBits (C..&.) BitwiseAnd
@@ -269,25 +269,25 @@ semiringNumber :: (String, String)
269269semiringNumber = (C.prelude, C.semiringNumber)
270270
271271semiringInt :: (String, String)
272−semiringInt = (C.dataInt, C.semiringInt)
272+semiringInt = (C.prelude, C.semiringInt)
273273
274274ringNumber :: (String, String)
275275ringNumber = (C.prelude, C.ringNumber)
276276
277277ringInt :: (String, String)
278−ringInt = (C.dataInt, C.ringInt)
278+ringInt = (C.prelude, C.ringInt)
279279
280280moduloSemiringNumber :: (String, String)
281281moduloSemiringNumber = (C.prelude, C.moduloSemiringNumber)
282282
283283moduloSemiringInt :: (String, String)
284−moduloSemiringInt = (C.dataInt, C.moduloSemiringInt)
284+moduloSemiringInt = (C.prelude, C.moduloSemiringInt)
285285
286286eqNumber :: (String, String)
287287eqNumber = (C.prelude, C.eqNumber)
288288
289289eqInt :: (String, String)
290−eqInt = (C.dataInt, C.eqInt)
290+eqInt = (C.prelude, C.eqInt)
291291
292292eqString :: (String, String)
293293eqString = (C.prelude, C.eqNumber)
@@ -299,7 +299,7 @@ ordNumber :: (String, String)
299299ordNumber = (C.prelude, C.ordNumber)
300300
301301ordInt :: (String, String)
302−ordInt = (C.dataInt, C.ordInt)
302+ordInt = (C.prelude, C.ordInt)
303303
304304semigroupString :: (String, String)
305305semigroupString = (C.prelude, C.semigroupString)
@@ -307,11 +307,8 @@ semigroupString = (C.prelude, C.semigroupString)
307307boundedBoolean :: (String, String)
308308boundedBoolean = (C.prelude, C.boundedBoolean)
309309
310−latticeBoolean :: (String, String)
311−latticeBoolean = (C.prelude, C.latticeBoolean)
312−
313−complementedLatticeBoolean :: (String, String)
314−complementedLatticeBoolean = (C.prelude, C.complementedLatticeBoolean)
310+booleanAlgebraBoolean :: (String, String)
311+booleanAlgebraBoolean = (C.prelude, C.booleanAlgebraBoolean)
315312
316313semigroupoidArr :: (String, String)
317314semigroupoidArr = (C.prelude, C.semigroupoidArr)
src/Language/PureScript/CodeGen/JS/Optimizer/MagicDo.hs+3−3
@@ -27,7 +27,7 @@ import Language.PureScript.Names
2727import Language.PureScript.Options
2828import qualified Language.PureScript.Constants as C
2929
30−magicDo :: Options mode -> JS -> JS
30+magicDo :: Options -> JS -> JS
3131magicDo opts | optionsNoMagicDo opts = id
3232 | otherwise = inlineST . magicDo'
3333
@@ -81,8 +81,8 @@ magicDo' = everywhereOnJS undo . everywhereOnJSTopDown convert
8181 isPure (JSApp purePoly [effDict]) | isPurePoly purePoly && isEffDict C.applicativeEffDictionary effDict = True
8282 isPure _ = False
8383 -- Check if an expression represents the polymorphic >>= function
84− isBindPoly (JSAccessor prop (JSVar prelude)) = prelude == C.prelude && prop == identToJs (Op (C.>>=))
85− isBindPoly (JSIndexer (JSStringLiteral bind) (JSVar prelude)) = prelude == C.prelude && bind == (C.>>=)
84+ isBindPoly (JSAccessor prop (JSVar prelude)) = prelude == C.prelude && (prop `elem` map identToJs [Ident C.bind, Op (C.>>=)])
85+ isBindPoly (JSIndexer (JSStringLiteral bind) (JSVar prelude)) = prelude == C.prelude && (bind `elem` [C.bind, (C.>>=)])
8686 isBindPoly _ = False
8787 -- Check if an expression represents the polymorphic return function
8888 isRetPoly (JSAccessor returnEscaped (JSVar prelude)) = prelude == C.prelude && returnEscaped == C.returnEscaped
src/Language/PureScript/CodeGen/JS/Optimizer/TCO.hs+1−1
@@ -23,7 +23,7 @@ import Language.PureScript.CodeGen.JS.AST
2323-- |
2424-- Eliminate tail calls
2525--
26−tco :: Options mode -> JS -> JS
26+tco :: Options -> JS -> JS
2727tco opts | optionsNoTco opts = id
2828 | otherwise = tco'
2929
src/Language/PureScript/Constants.hs+9−12
@@ -71,6 +71,9 @@ module Language.PureScript.Constants where
7171(||) :: String
7272(||) = "||"
7373
74+bind :: String
75+bind = "bind"
76+
7477unsafeIndex :: String
7578unsafeIndex = "unsafeIndex"
7679
@@ -94,11 +97,11 @@ negate = "negate"
9497not :: String
9598not = "not"
9699
97−sup :: String
98−sup = "sup"
100+conj :: String
101+conj = "conj"
99102
100−inf :: String
101−inf = "inf"
103+disj :: String
104+disj = "disj"
102105
103106mod :: String
104107mod = "mod"
@@ -226,11 +229,8 @@ eqBoolean = "eqBoolean"
226229boundedBoolean :: String
227230boundedBoolean = "boundedBoolean"
228231
229−latticeBoolean :: String
230−latticeBoolean = "latticeBoolean"
231−
232−complementedLatticeBoolean :: String
233−complementedLatticeBoolean = "complementedLatticeBoolean"
232+booleanAlgebraBoolean :: String
233+booleanAlgebraBoolean = "booleanAlgebraBoolean"
234234
235235semigroupString :: String
236236semigroupString = "semigroupString"
@@ -271,8 +271,5 @@ st = "Control_Monad_ST"
271271dataFunction :: String
272272dataFunction = "Data_Function"
273273
274−dataInt :: String
275−dataInt = "Data_Int"
276−
277274dataIntBits :: String
278275dataIntBits = "Data_Int_Bits"
src/Language/PureScript/DeadCodeElimination.hsdeleted−102
@@ -1,102 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Language.PureScript.DeadCodeElimination
4−-- Copyright : (c) 2014 Phil Freeman
5−-- License : MIT
6−--
7−-- Maintainer : Phil Freeman <paf31@cantab.net>
8−-- Stability : experimental
9−-- Portability :
10−--
11−-- | Dead code elimination.
12−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.DeadCodeElimination (
16− eliminateDeadCode
17−) where
18−
19−import Data.Graph
20−import Data.List
21−import Data.Maybe (mapMaybe)
22−
23−import Language.PureScript.CoreFn
24−import Language.PureScript.Names
25−
26−-- |
27−-- Eliminate all declarations which are not a transitive dependency of the entry point module
28−--
29−eliminateDeadCode :: [ModuleName] -> [Module a] -> [Module a]
30−eliminateDeadCode entryPoints ms = map go ms
31− where
32− go (Module coms mn imps exps foreigns ds) = Module coms mn imps exps' foreigns' ds'
33− where
34− ds' = filter (isUsed mn graph vertexFor entryPointVertices) ds
35− foreigns' = filter (isUsed' mn graph vertexFor entryPointVertices . foreignIdent) foreigns
36− names = concatMap bindIdents ds' ++ map foreignIdent foreigns'
37− exps' = filter (`elem` names) exps
38− declarations = concatMap declarationsByModule ms
39− (graph, _, vertexFor) = graphFromEdges $ map (\(key, deps) -> (key, key, deps)) declarations
40− entryPointVertices = mapMaybe (vertexFor . fst) . filter (\((mn, _), _) -> mn `elem` entryPoints) $ declarations
41−
42−-- |
43−-- Extract declaration names for a binding group.
44−--
45−bindIdents :: Bind a -> [Ident]
46−bindIdents (NonRec name _) = [name]
47−bindIdents (Rec names) = map fst names
48−
49−-- |
50−-- Extract the ident for a foreign declaration.
51−--
52−foreignIdent :: ForeignDecl -> Ident
53−foreignIdent = fst
54−
55−-- |
56−-- Key type to use in graph
57−--
58−type Key = (ModuleName, Ident)
59−
60−-- |
61−-- Find dependencies for each member in a module.
62−--
63−declarationsByModule :: Module a -> [(Key, [Key])]
64−declarationsByModule (Module _ mn _ _ fs ds) =
65− let fs' = map ((\name -> ((mn, name), [])) . foreignIdent) fs
66− in fs' ++ concatMap go ds
67− where
68− go :: Bind a -> [(Key, [Key])]
69− go d@(NonRec name _) = [((mn, name), dependencies d)]
70− go d@(Rec names') = map (\(name, _) -> ((mn, name), dependencies d)) names'
71−
72−-- |
73−-- Find all referenced values within a binding group.
74−--
75−dependencies :: Bind a -> [Key]
76−dependencies =
77− let (f, _, _, _) = everythingOnValues (++) (const []) values binders (const [])
78− in nub . f
79− where
80− values :: Expr a -> [Key]
81− values (Var _ (Qualified (Just mn) ident)) = [(mn, ident)]
82− values _ = []
83− binders :: Binder a -> [Key]
84− binders (ConstructorBinder _ _ (Qualified (Just mn) ident) _) = [(mn, Ident $ runProperName ident)]
85− binders _ = []
86−
87−-- |
88−-- Check whether a binding group is used.
89−--
90−isUsed :: ModuleName -> Graph -> (Key -> Maybe Vertex) -> [Vertex] -> Bind a -> Bool
91−isUsed mn graph vertexFor entryPointVertices (NonRec name _) =
92− isUsed' mn graph vertexFor entryPointVertices name
93−isUsed mn graph vertexFor entryPointVertices (Rec ds) =
94− any (isUsed' mn graph vertexFor entryPointVertices . fst) ds
95−
96−-- |
97−-- Check whether a named declaration is used.
98−--
99−isUsed' :: ModuleName -> Graph -> (Key -> Maybe Vertex) -> [Vertex] -> Ident -> Bool
100−isUsed' mn graph vertexFor entryPointVertices name =
101− let Just v' = vertexFor (mn, name)
102− in any (\v -> path graph v v') entryPointVertices
src/Language/PureScript/Docs.hs+1
@@ -9,5 +9,6 @@ module Language.PureScript.Docs (
99import Language.PureScript.Docs.Types as Docs
1010import Language.PureScript.Docs.RenderedCode.Types as Docs
1111import Language.PureScript.Docs.RenderedCode.Render as Docs
12+import Language.PureScript.Docs.Convert as Docs
1213import Language.PureScript.Docs.Render as Docs
1314import Language.PureScript.Docs.ParseAndDesugar as Docs
src/Language/PureScript/Docs/AsMarkdown.hs+45−22
@@ -12,6 +12,7 @@ import qualified Language.PureScript as P
1212
1313import Language.PureScript.Docs.Types
1414import Language.PureScript.Docs.RenderedCode
15+import qualified Language.PureScript.Docs.Convert as Convert
1516import qualified Language.PureScript.Docs.Render as Render
1617
1718-- |
@@ -20,37 +21,43 @@ import qualified Language.PureScript.Docs.Render as Render
2021--
2122renderModulesAsMarkdown :: [P.Module] -> String
2223renderModulesAsMarkdown =
23− runDocs . modulesAsMarkdown . map Render.renderModule
24+ runDocs . modulesAsMarkdown . map Convert.convertModule
2425
25−modulesAsMarkdown :: [RenderedModule] -> Docs
26+modulesAsMarkdown :: [Module] -> Docs
2627modulesAsMarkdown = mapM_ moduleAsMarkdown
2728
28−moduleAsMarkdown :: RenderedModule -> Docs
29−moduleAsMarkdown RenderedModule{..} = do
30− headerLevel 2 $ "Module " ++ rmName
29+moduleAsMarkdown :: Module -> Docs
30+moduleAsMarkdown Module{..} = do
31+ headerLevel 2 $ "Module " ++ modName
3132 spacer
32− for_ rmComments tell'
33− mapM_ declAsMarkdown rmDeclarations
33+ for_ modComments tell'
34+ mapM_ declAsMarkdown modDeclarations
3435 spacer
3536
36−declAsMarkdown :: RenderedDeclaration -> Docs
37−declAsMarkdown RenderedDeclaration{..} = do
38− headerLevel 4 (ticks rdTitle)
37+declAsMarkdown :: Declaration -> Docs
38+declAsMarkdown decl@Declaration{..} = do
39+ headerLevel 4 (ticks declTitle)
3940 spacer
4041
41− let (instances, children) = partition ((==) ChildInstance . rcdType) rdChildren
42+ let (instances, children) = partition (isChildInstance . cdeclInfo) declChildren
4243 fencedBlock $ do
43− tell' (codeToString rdCode)
44+ tell' (codeToString $ Render.renderDeclaration decl)
4445 zipWithM_ (\f c -> tell' (childToString f c)) (First : repeat NotFirst) children
4546 spacer
4647
47− for_ rdComments tell'
48+ for_ declFixity (\fixity -> fixityAsMarkdown fixity >> spacer)
49+
50+ for_ declComments tell'
4851
4952 unless (null instances) $ do
5053 headerLevel 5 "Instances"
5154 fencedBlock $ mapM_ (tell' . childToString NotFirst) instances
5255 spacer
5356
57+ where
58+ isChildInstance (ChildInstance _ _) = True
59+ isChildInstance _ = False
60+
5461codeToString :: RenderedCode -> String
5562codeToString = outputWith elemAsMarkdown
5663 where
@@ -61,16 +68,32 @@ codeToString = outputWith elemAsMarkdown
6168 elemAsMarkdown (Keyword x) = x
6269 elemAsMarkdown Space = " "
6370
64−childToString :: First -> RenderedChildDeclaration -> String
65−childToString f RenderedChildDeclaration{..} =
66− case rcdType of
67− ChildDataConstructor ->
71+fixityAsMarkdown :: P.Fixity -> Docs
72+fixityAsMarkdown (P.Fixity associativity precedence) =
73+ tell' $ concat [ "_"
74+ , associativityStr
75+ , " / precedence "
76+ , show precedence
77+ , "_"
78+ ]
79+ where
80+ associativityStr = case associativity of
81+ P.Infixl -> "left-associative"
82+ P.Infixr -> "right-associative"
83+ P.Infix -> "non-associative"
84+
85+childToString :: First -> ChildDeclaration -> String
86+childToString f decl@ChildDeclaration{..} =
87+ case cdeclInfo of
88+ ChildDataConstructor _ ->
6889 let c = if f == First then "=" else "|"
69− in " " ++ c ++ " " ++ codeToString rcdCode
70− ChildTypeClassMember ->
71− " " ++ codeToString rcdCode
72− ChildInstance ->
73− codeToString rcdCode
90+ in " " ++ c ++ " " ++ str
91+ ChildTypeClassMember _ ->
92+ " " ++ str
93+ ChildInstance _ _ ->
94+ str
95+ where
96+ str = codeToString $ Render.renderChildDeclaration decl
7497
7598data First
7699 = First
src/Language/PureScript/Docs/Convert.hsnew file+228
@@ -0,0 +1,228 @@
1+{-# LANGUAGE TupleSections #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE RecordWildCards #-}
4+{-# LANGUAGE ViewPatterns #-}
5+
6+-- | Functions for converting PureScript ASTs into values of the data types
7+-- from Language.PureScript.Docs.
8+
9+module Language.PureScript.Docs.Convert
10+ ( convertModule
11+ , collectBookmarks
12+ ) where
13+
14+import Control.Monad
15+import Control.Category ((>>>))
16+import Data.Either
17+import Data.Maybe (mapMaybe, isNothing)
18+import Data.List (nub, isPrefixOf, isSuffixOf)
19+
20+import qualified Language.PureScript as P
21+
22+import Language.PureScript.Docs.Types
23+
24+-- |
25+-- Convert a single Module.
26+--
27+convertModule :: P.Module -> Module
28+convertModule m@(P.Module coms moduleName _ _) =
29+ Module (show moduleName) comments (declarations m)
30+ where
31+ comments = convertComments coms
32+ declarations =
33+ P.exportedDeclarations
34+ >>> mapMaybe (\d -> getDeclarationTitle d >>= convertDeclaration d)
35+ >>> augmentDeclarations
36+ >>> map addDefaultFixity
37+
38+-- | The data type for an intermediate stage which we go through during
39+-- converting.
40+--
41+-- In the first pass, we take all top level declarations in the module, and
42+-- collect other information which will later be used to augment the top level
43+-- declarations. These two situation correspond to the Right and Left
44+-- constructors, respectively.
45+--
46+-- In the second pass, we go over all of the Left values and augment the
47+-- relevant declarations, leaving only the augmented Right values.
48+--
49+-- Note that in the Left case, we provide a [String] as well as augment
50+-- information. The [String] value should be a list of titles of declarations
51+-- that the augmentation should apply to. For example, for a type instance
52+-- declaration, that would be any types or type classes mentioned in the
53+-- instance. For a fixity declaration, it would be just the relevant operator's
54+-- name.
55+type IntermediateDeclaration
56+ = Either ([String], DeclarationAugment) Declaration
57+
58+-- | Some data which will be used to augment a Declaration in the
59+-- output.
60+--
61+-- The AugmentChild constructor allows us to move all children under their
62+-- respective parents. It is only necessary for type instance declarations,
63+-- since they appear at the top level in the AST, and since they might need to
64+-- appear as children in two places (for example, if a data type defined in a
65+-- module is an instance of a type class also defined in that module).
66+--
67+-- The AugmentFixity constructor allows us to augment operator definitions
68+-- with their associativity and precedence.
69+data DeclarationAugment
70+ = AugmentChild ChildDeclaration
71+ | AugmentFixity P.Fixity
72+
73+-- | Augment top-level declarations; the second pass. See the comments under
74+-- the type synonym IntermediateDeclaration for more information.
75+augmentDeclarations :: [IntermediateDeclaration] -> [Declaration]
76+augmentDeclarations (partitionEithers -> (augments, toplevels)) =
77+ foldl go toplevels augments
78+ where
79+ go ds (parentTitles, a) =
80+ map (\d ->
81+ if declTitle d `elem` parentTitles
82+ then augmentWith a d
83+ else d) ds
84+
85+ augmentWith a d =
86+ case a of
87+ AugmentChild child ->
88+ d { declChildren = declChildren d ++ [child] }
89+ AugmentFixity fixity ->
90+ d { declFixity = Just fixity }
91+
92+-- | Add the default operator fixity for operators which do not have associated
93+-- fixity declarations.
94+--
95+-- TODO: This may no longer be necessary after issue 806 is resolved, hopefully
96+-- in 0.8.
97+addDefaultFixity :: Declaration -> Declaration
98+addDefaultFixity decl@Declaration{..}
99+ | isOp declTitle && isNothing declFixity =
100+ decl { declFixity = Just defaultFixity }
101+ | otherwise =
102+ decl
103+ where
104+ isOp :: String -> Bool
105+ isOp str = "(" `isPrefixOf` str && ")" `isSuffixOf` str
106+ defaultFixity = P.Fixity P.Infixl (-1)
107+
108+getDeclarationTitle :: P.Declaration -> Maybe String
109+getDeclarationTitle (P.TypeDeclaration name _) = Just (show name)
110+getDeclarationTitle (P.ExternDeclaration name _) = Just (show name)
111+getDeclarationTitle (P.DataDeclaration _ name _ _) = Just (show name)
112+getDeclarationTitle (P.ExternDataDeclaration name _) = Just (show name)
113+getDeclarationTitle (P.TypeSynonymDeclaration name _ _) = Just (show name)
114+getDeclarationTitle (P.TypeClassDeclaration name _ _ _) = Just (show name)
115+getDeclarationTitle (P.TypeInstanceDeclaration name _ _ _ _) = Just (show name)
116+getDeclarationTitle (P.FixityDeclaration _ name) = Just ("(" ++ name ++ ")")
117+getDeclarationTitle (P.PositionedDeclaration _ _ d) = getDeclarationTitle d
118+getDeclarationTitle _ = Nothing
119+
120+-- | Create a basic Declaration value.
121+mkDeclaration :: String -> DeclarationInfo -> Declaration
122+mkDeclaration title info =
123+ Declaration { declTitle = title
124+ , declComments = Nothing
125+ , declSourceSpan = Nothing
126+ , declChildren = []
127+ , declFixity = Nothing
128+ , declInfo = info
129+ }
130+
131+basicDeclaration :: String -> DeclarationInfo -> Maybe IntermediateDeclaration
132+basicDeclaration title info = Just $ Right $ mkDeclaration title info
133+
134+convertDeclaration :: P.Declaration -> String -> Maybe IntermediateDeclaration
135+convertDeclaration (P.TypeDeclaration _ ty) title =
136+ basicDeclaration title (ValueDeclaration ty)
137+convertDeclaration (P.ExternDeclaration _ ty) title =
138+ basicDeclaration title (ValueDeclaration ty)
139+convertDeclaration (P.DataDeclaration dtype _ args ctors) title =
140+ Just (Right (mkDeclaration title info) { declChildren = children })
141+ where
142+ info = DataDeclaration dtype args
143+ children = map convertCtor ctors
144+ convertCtor (ctor', tys) =
145+ ChildDeclaration (show ctor') Nothing Nothing (ChildDataConstructor tys)
146+convertDeclaration (P.ExternDataDeclaration _ kind') title =
147+ basicDeclaration title (ExternDataDeclaration kind')
148+convertDeclaration (P.TypeSynonymDeclaration _ args ty) title =
149+ basicDeclaration title (TypeSynonymDeclaration args ty)
150+convertDeclaration (P.TypeClassDeclaration _ args implies ds) title = do
151+ Just (Right (mkDeclaration title info) { declChildren = children })
152+ where
153+ info = TypeClassDeclaration args implies
154+ children = map convertClassMember ds
155+ convertClassMember (P.PositionedDeclaration _ _ d) =
156+ convertClassMember d
157+ convertClassMember (P.TypeDeclaration ident' ty) =
158+ ChildDeclaration (show ident') Nothing Nothing (ChildTypeClassMember ty)
159+ convertClassMember _ =
160+ error "Invalid argument to convertClassMember."
161+convertDeclaration (P.TypeInstanceDeclaration _ constraints className tys _) title = do
162+ Just (Left (classNameString : typeNameStrings, AugmentChild childDecl))
163+ where
164+ classNameString = unQual className
165+ typeNameStrings = nub (concatMap (P.everythingOnTypes (++) extractProperNames) tys)
166+ unQual x = let (P.Qualified _ y) = x in show y
167+
168+ extractProperNames (P.TypeConstructor n) = [unQual n]
169+ extractProperNames (P.SaturatedTypeSynonym n _) = [unQual n]
170+ extractProperNames _ = []
171+
172+ childDecl = ChildDeclaration title Nothing Nothing (ChildInstance constraints classApp)
173+ classApp = foldl P.TypeApp (P.TypeConstructor className) tys
174+convertDeclaration (P.FixityDeclaration fixity _) title =
175+ Just (Left ([title], AugmentFixity fixity))
176+convertDeclaration (P.PositionedDeclaration srcSpan com d') title =
177+ fmap (addComments . addSourceSpan) (convertDeclaration d' title)
178+ where
179+ addComments (Right d) =
180+ Right (d { declComments = convertComments com })
181+ addComments (Left augment) =
182+ Left (withAugmentChild (\d -> d { cdeclComments = convertComments com })
183+ augment)
184+
185+ addSourceSpan (Right d) =
186+ Right (d { declSourceSpan = Just srcSpan })
187+ addSourceSpan (Left augment) =
188+ Left (withAugmentChild (\d -> d { cdeclSourceSpan = Just srcSpan })
189+ augment)
190+
191+ withAugmentChild f (t, a) =
192+ case a of
193+ AugmentChild d -> (t, AugmentChild (f d))
194+ _ -> (t, a)
195+convertDeclaration _ _ = Nothing
196+
197+convertComments :: [P.Comment] -> Maybe String
198+convertComments cs = do
199+ let raw = concatMap toLines cs
200+ guard (all hasPipe raw && not (null raw))
201+ return (go raw)
202+ where
203+ go = unlines . map stripPipes
204+
205+ toLines (P.LineComment s) = [s]
206+ toLines (P.BlockComment s) = lines s
207+
208+ hasPipe s = case dropWhile (== ' ') s of { ('|':_) -> True; _ -> False }
209+
210+ stripPipes = dropPipe . dropWhile (== ' ')
211+
212+ dropPipe ('|':' ':s) = s
213+ dropPipe ('|':s) = s
214+ dropPipe s = s
215+
216+-- | Go through a PureScript module and extract a list of Bookmarks; references
217+-- to data types or values, to be used as a kind of index. These are used for
218+-- generating links in the HTML documentation, for example.
219+collectBookmarks :: InPackage P.Module -> [Bookmark]
220+collectBookmarks (Local m) = map Local (collectBookmarks' m)
221+collectBookmarks (FromDep pkg m) = map (FromDep pkg) (collectBookmarks' m)
222+
223+collectBookmarks' :: P.Module -> [(P.ModuleName, String)]
224+collectBookmarks' m =
225+ map (P.getModuleName m, )
226+ (mapMaybe getDeclarationTitle
227+ (P.exportedDeclarations m))
228+
src/Language/PureScript/Docs/ParseAndDesugar.hs+33−12
@@ -19,7 +19,7 @@ import Web.Bower.PackageMeta (PackageName)
1919import qualified Language.PureScript as P
2020import qualified Language.PureScript.Constants as C
2121import Language.PureScript.Docs.Types
22−import Language.PureScript.Docs.Render
22+import Language.PureScript.Docs.Convert (collectBookmarks)
2323
2424data ParseDesugarError
2525 = ParseError P.MultipleErrors
@@ -53,20 +53,41 @@ parseAndDesugar inputFiles depsFiles callback = do
5353 depsFiles' <- mapM (\(pkgName, f) -> parseAs (FromDep pkgName) f) depsFiles
5454
5555 runExceptT $ do
56− let eParsed = P.parseModulesFromFiles fileInfoToString (inputFiles' ++ depsFiles')
57− ms <- throwLeft ParseError eParsed
56+ ms <- parseFiles (inputFiles' ++ depsFiles')
57+ ms' <- sortModules (map snd ms)
58+ (bs, ms'') <- desugarWithBookmarks ms ms'
59+ liftIO $ callback bs ms''
60+
61+parseFiles ::
62+ [(FileInfo, FilePath)]
63+ -> ExceptT ParseDesugarError IO [(FileInfo, P.Module)]
64+parseFiles =
65+ throwLeft ParseError . P.parseModulesFromFiles fileInfoToString
66+
67+sortModules ::
68+ [P.Module]
69+ -> ExceptT ParseDesugarError IO [P.Module]
70+sortModules =
71+ fmap fst . throwLeft SortModulesError . sortModules' . map importPrim
72+ where
73+ sortModules' :: [P.Module] -> Either P.MultipleErrors ([P.Module], P.ModuleGraph)
74+ sortModules' = P.sortModules
5875
59− let depsModules = getDepsModuleNames (map (\(fp, m) -> (,m) <$> fp) ms)
60− let eSorted = P.sortModules . map (importPrim . snd) $ ms
61− (ms', _) <- throwLeft SortModulesError eSorted
76+desugarWithBookmarks ::
77+ [(FileInfo, P.Module)]
78+ -> [P.Module]
79+ -> ExceptT ParseDesugarError IO ([Bookmark], [P.Module])
80+desugarWithBookmarks msInfo msSorted = do
81+ msDesugared <- throwLeft DesugarError (desugar msSorted)
6282
63− modules <- throwLeft DesugarError (desugar ms')
64− let modules' = map (addPackage depsModules) modules
65− bookmarks = concatMap collectBookmarks modules'
66− liftIO (callback bookmarks (takeLocals modules'))
83+ let msDeps = getDepsModuleNames (map (\(fp, m) -> (,m) <$> fp) msInfo)
84+ msPackages = map (addPackage msDeps) msDesugared
85+ bookmarks = concatMap collectBookmarks msPackages
6786
68− where
69− throwLeft f = either (throwError . f) return
87+ return (bookmarks, takeLocals msPackages)
88+
89+throwLeft :: (MonadError e m) => (l -> e) -> Either l r -> m r
90+throwLeft f = either (throwError . f) return
7091
7192-- | Specifies whether a PureScript source file is considered as:
7293--
src/Language/PureScript/Docs/Render.hs+100−212
@@ -1,239 +1,127 @@
1−{-# LANGUAGE TupleSections #-}
2−{-# LANGUAGE OverloadedStrings #-}
31{-# LANGUAGE RecordWildCards #-}
4−{-# LANGUAGE ViewPatterns #-}
52
6−-- | Functions for rendering documentation generated from PureScript code.
3+-- | Functions for creating `RenderedCode` values from data types in
4+-- Language.PureScript.Docs.Types.
5+--
6+-- These functions are the ones that are used in markdown/html documentation
7+-- generation, but the intention is that you are able to supply your own
8+-- instead if necessary. For example, the Hoogle input file generator
9+-- substitutes some of these
710
8−module Language.PureScript.Docs.Render (
9− renderModule,
10− collectBookmarks
11−) where
11+module Language.PureScript.Docs.Render where
1212
13−import Control.Monad
14−import Data.Either
1513import Data.Monoid ((<>))
16−import Data.Maybe (mapMaybe)
17−import Data.List (nub)
18−
1914import qualified Language.PureScript as P
2015
21−import Language.PureScript.Docs.RenderedCode
2216import Language.PureScript.Docs.Types
17+import Language.PureScript.Docs.RenderedCode
2318import Language.PureScript.Docs.Utils.MonoidExtras
2419
25−-- |
26−-- Render a single Module.
27−--
28−renderModule :: P.Module -> RenderedModule
29−renderModule m@(P.Module coms moduleName _ _) =
30− RenderedModule (show moduleName) comments declarations
31− where
32− comments = renderComments coms
33− declarations = groupChildren declarationsWithChildren
34− declarationsWithChildren = mapMaybe go (P.exportedDeclarations m)
35− go decl = getDeclarationTitle decl
36− >>= renderDeclaration decl
20+renderDeclaration :: Declaration -> RenderedCode
21+renderDeclaration = renderDeclarationWithOptions defaultRenderTypeOptions
3722
38−-- | An intermediate stage which we go through during rendering.
39−--
40−-- In the first pass, we take all top level declarations in the module, and
41−-- render those which should appear at the top level in the output, as well as
42−-- those which should appear as children of other declarations in the output.
43−--
44−-- In the second pass, we move all children under their respective parents,
45−-- or discard them if none are found.
46−--
47−-- This two-pass system is only necessary for type instance declarations, since
48−-- they appear at the top level in the AST, and since they might need to appear
49−-- as children in two places (for example, if a data type defined in a module
50−-- is an instance of a type class also defined in that module).
51−--
52−-- This data type is used as an intermediate type between the two stages. The
53−-- Left case is a child declaration, together with a list of parent declaration
54−-- titles which this may appear as a child of.
55−--
56−-- The Right case is a top level declaration which should pass straight through
57−-- the second stage; the only way it might change is if child declarations are
58−-- added to it.
59−type IntermediateDeclaration
60− = Either ([String], RenderedChildDeclaration) RenderedDeclaration
61−
62−-- | Move child declarations into their respective parents; the second pass.
63−-- See the comments under the type synonym IntermediateDeclaration for more
64−-- information.
65−groupChildren :: [IntermediateDeclaration] -> [RenderedDeclaration]
66−groupChildren (partitionEithers -> (children, toplevels)) =
67− foldl go toplevels children
68− where
69− go ds (parentTitles, child) =
70− map (\d ->
71− if rdTitle d `elem` parentTitles
72− then d { rdChildren = rdChildren d ++ [child] }
73− else d) ds
74−
75−getDeclarationTitle :: P.Declaration -> Maybe String
76−getDeclarationTitle (P.TypeDeclaration name _) = Just (show name)
77−getDeclarationTitle (P.ExternDeclaration name _) = Just (show name)
78−getDeclarationTitle (P.DataDeclaration _ name _ _) = Just (show name)
79−getDeclarationTitle (P.ExternDataDeclaration name _) = Just (show name)
80−getDeclarationTitle (P.TypeSynonymDeclaration name _ _) = Just (show name)
81−getDeclarationTitle (P.TypeClassDeclaration name _ _ _) = Just (show name)
82−getDeclarationTitle (P.TypeInstanceDeclaration name _ _ _ _) = Just (show name)
83−getDeclarationTitle (P.PositionedDeclaration _ _ d) = getDeclarationTitle d
84−getDeclarationTitle _ = Nothing
85−
86−basicDeclaration :: String -> RenderedCode -> Maybe IntermediateDeclaration
87−basicDeclaration title code = Just (Right (RenderedDeclaration title Nothing code Nothing []))
88−
89−renderDeclaration :: P.Declaration -> String -> Maybe IntermediateDeclaration
90−renderDeclaration (P.TypeDeclaration ident' ty) title =
91− basicDeclaration title code
92− where
93− code = ident (show ident')
94− <> sp <> syntax "::" <> sp
95− <> renderType ty
96−renderDeclaration (P.ExternDeclaration ident' ty) title =
97− basicDeclaration title code
98− where
99− code = ident (show ident')
100− <> sp <> syntax "::" <> sp
101− <> renderType ty
102−renderDeclaration (P.DataDeclaration dtype name args ctors) title =
103− Just (Right (RenderedDeclaration title Nothing code Nothing children))
104− where
105− typeApp = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing name)) (map toTypeVar args)
106− code = keyword (show dtype) <> sp <> renderType typeApp
107− children = map renderCtor ctors
108− -- TODO: Comments for data constructors?
109− renderCtor (ctor', tys) =
110− let typeApp' = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing ctor')) tys
111− childCode = renderType typeApp'
112− in RenderedChildDeclaration (show ctor') Nothing childCode Nothing ChildDataConstructor
113−renderDeclaration (P.ExternDataDeclaration name kind') title =
114− basicDeclaration title code
115− where
116− code = keywordData <> sp
117− <> renderType (P.TypeConstructor (P.Qualified Nothing name))
118− <> sp <> syntax "::" <> sp
119− <> renderKind kind'
120−renderDeclaration (P.TypeSynonymDeclaration name args ty) title =
121− basicDeclaration title code
122− where
123− typeApp = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing name)) (map toTypeVar args)
124− code = mintersperse sp
125− [ keywordType
126− , renderType typeApp
127− , syntax "="
128− , renderType ty
129− ]
130−renderDeclaration (P.TypeClassDeclaration name args implies ds) title = do
131− Just (Right (RenderedDeclaration title Nothing code Nothing children))
132− where
133− code = mintersperse sp $
134− [keywordClass]
135− ++ maybe [] (:[]) superclasses
136− ++ [renderType classApp]
137− ++ if (not (null ds)) then [keywordWhere] else []
138−
139− superclasses
140− | null implies = Nothing
141− | otherwise = Just $
142− syntax "("
143− <> mintersperse (syntax "," <> sp) (map renderImplies implies)
144− <> syntax ") <="
145−
146− renderImplies (pn, tys) =
147− let supApp = foldl P.TypeApp (P.TypeConstructor pn) tys
148− in renderType supApp
149−
150− classApp = foldl P.TypeApp (P.TypeConstructor (P.Qualified Nothing name)) (map toTypeVar args)
151−
152− children = map renderClassMember ds
153−
154− -- TODO: Comments for type class members
155− renderClassMember (P.PositionedDeclaration _ _ d) = renderClassMember d
156− renderClassMember (P.TypeDeclaration ident' ty) =
157− let childCode =
158− mintersperse sp
159− [ ident (show ident')
160− , syntax "::"
161− , renderType ty
162− ]
163− in RenderedChildDeclaration (show ident') Nothing childCode Nothing ChildTypeClassMember
164− renderClassMember _ = error "Invalid argument to renderClassMember."
165−renderDeclaration (P.TypeInstanceDeclaration name constraints className tys _) title = do
166− Just (Left (classNameString : typeNameStrings, childDecl))
23+renderDeclarationWithOptions :: RenderTypeOptions -> Declaration -> RenderedCode
24+renderDeclarationWithOptions opts Declaration{..} =
25+ mintersperse sp $ case declInfo of
26+ ValueDeclaration ty ->
27+ [ ident declTitle
28+ , syntax "::"
29+ , renderType' ty
30+ ]
31+ DataDeclaration dtype args ->
32+ [ keyword (show dtype)
33+ , renderType' (typeApp declTitle args)
34+ ]
35+ ExternDataDeclaration kind' ->
36+ [ keywordData
37+ , renderType' (P.TypeConstructor (notQualified declTitle))
38+ , syntax "::"
39+ , renderKind kind'
40+ ]
41+ TypeSynonymDeclaration args ty ->
42+ [ keywordType
43+ , renderType' (typeApp declTitle args)
44+ , syntax "="
45+ , renderType' ty
46+ ]
47+ TypeClassDeclaration args implies ->
48+ [ keywordClass ]
49+ ++ maybe [] (:[]) superclasses
50+ ++ [renderType' (typeApp declTitle args)]
51+ ++ if any (isTypeClassMember . cdeclInfo) declChildren
52+ then [keywordWhere]
53+ else []
54+
55+ where
56+ superclasses
57+ | null implies = Nothing
58+ | otherwise = Just $
59+ syntax "("
60+ <> mintersperse (syntax "," <> sp) (map renderConstraint implies)
61+ <> syntax ")" <> sp <> syntax "<="
62+
63+ isTypeClassMember (ChildTypeClassMember _) = True
64+ isTypeClassMember _ = False
16765 where
168− classNameString = unQual className
169− typeNameStrings = nub (concatMap (P.everythingOnTypes (++) extractProperNames) tys)
170− unQual x = let (P.Qualified _ y) = x in show y
171−
172− extractProperNames (P.TypeConstructor n) = [unQual n]
173− extractProperNames (P.SaturatedTypeSynonym n _) = [unQual n]
174− extractProperNames _ = []
66+ renderType' = renderTypeWithOptions opts
17567
176− childDecl = RenderedChildDeclaration title Nothing code Nothing ChildInstance
68+renderChildDeclaration :: ChildDeclaration -> RenderedCode
69+renderChildDeclaration = renderChildDeclarationWithOptions defaultRenderTypeOptions
17770
178− code =
179− mintersperse sp $
71+renderChildDeclarationWithOptions :: RenderTypeOptions -> ChildDeclaration -> RenderedCode
72+renderChildDeclarationWithOptions opts ChildDeclaration{..} =
73+ mintersperse sp $ case cdeclInfo of
74+ ChildInstance constraints ty ->
18075 [ keywordInstance
181− , ident (show name)
76+ , ident cdeclTitle
18277 , syntax "::"
183− ] ++ maybe [] (:[]) constraints'
184− ++ [ renderType classApp ]
78+ ] ++ maybe [] (:[]) (renderConstraints constraints)
79+ ++ [ renderType' ty ]
80+ ChildDataConstructor args ->
81+ [ renderType' typeApp' ]
82+ where
83+ typeApp' = foldl P.TypeApp ctor' args
84+ ctor' = P.TypeConstructor (notQualified cdeclTitle)
85+
86+ ChildTypeClassMember ty ->
87+ [ ident cdeclTitle
88+ , syntax "::"
89+ , renderType' ty
90+ ]
91+ where
92+ renderType' = renderTypeWithOptions opts
18593
186− constraints'
187− | null constraints = Nothing
188− | otherwise = Just (syntax "(" <> renderedConstraints <> syntax ") =>")
94+renderConstraint :: (P.Qualified P.ProperName, [P.Type]) -> RenderedCode
95+renderConstraint = renderConstraintWithOptions defaultRenderTypeOptions
18996
190− renderedConstraints = mintersperse (syntax "," <> sp) (map renderConstraint constraints)
97+renderConstraintWithOptions :: RenderTypeOptions -> (P.Qualified P.ProperName, [P.Type]) -> RenderedCode
98+renderConstraintWithOptions opts (pn, tys) =
99+ renderTypeWithOptions opts $ foldl P.TypeApp (P.TypeConstructor pn) tys
191100
192− renderConstraint (pn, tys') =
193− let supApp = foldl P.TypeApp (P.TypeConstructor pn) tys'
194− in renderType supApp
101+renderConstraints :: [P.Constraint] -> Maybe RenderedCode
102+renderConstraints = renderConstraintsWithOptions defaultRenderTypeOptions
195103
196− classApp = foldl P.TypeApp (P.TypeConstructor className) tys
197−renderDeclaration (P.PositionedDeclaration srcSpan com d') title =
198− fmap (addComments . addSourceSpan) (renderDeclaration d' title)
199− where
200− addComments (Left (t, d)) = Left (t, d { rcdComments = renderComments com })
201− addComments (Right d) = Right (d { rdComments = renderComments com })
202−
203− addSourceSpan (Left (t, d)) = Left (t, d { rcdSourceSpan = Just srcSpan })
204− addSourceSpan (Right d) = Right (d { rdSourceSpan = Just srcSpan })
205−renderDeclaration _ _ = Nothing
206−
207−renderComments :: [P.Comment] -> Maybe String
208−renderComments cs = do
209− let raw = concatMap toLines cs
210− guard (all hasPipe raw && not (null raw))
211− return (go raw)
104+renderConstraintsWithOptions :: RenderTypeOptions -> [P.Constraint] -> Maybe RenderedCode
105+renderConstraintsWithOptions opts constraints
106+ | null constraints = Nothing
107+ | otherwise = Just $
108+ syntax "("
109+ <> renderedConstraints
110+ <> syntax ")" <> sp <> syntax "=>"
212111 where
213− go = unlines . map stripPipes
214−
215− toLines (P.LineComment s) = [s]
216− toLines (P.BlockComment s) = lines s
217−
218− hasPipe s = case dropWhile (== ' ') s of { ('|':_) -> True; _ -> False }
112+ renderedConstraints =
113+ mintersperse (syntax "," <> sp)
114+ (map (renderConstraintWithOptions opts) constraints)
219115
220− stripPipes = dropPipe . dropWhile (== ' ')
116+notQualified :: String -> P.Qualified P.ProperName
117+notQualified = P.Qualified Nothing . P.ProperName
221118
222− dropPipe ('|':' ':s) = s
223− dropPipe ('|':s) = s
224− dropPipe s = s
119+typeApp :: String -> [(String, Maybe P.Kind)] -> P.Type
120+typeApp title typeArgs =
121+ foldl P.TypeApp
122+ (P.TypeConstructor (notQualified title))
123+ (map toTypeVar typeArgs)
225124
226125toTypeVar :: (String, Maybe P.Kind) -> P.Type
227126toTypeVar (s, Nothing) = P.TypeVar s
228127toTypeVar (s, Just k) = P.KindedType (P.TypeVar s) k
229−
230−collectBookmarks :: InPackage P.Module -> [Bookmark]
231−collectBookmarks (Local m) = map Local (collectBookmarks' m)
232−collectBookmarks (FromDep pkg m) = map (FromDep pkg) (collectBookmarks' m)
233−
234−collectBookmarks' :: P.Module -> [(P.ModuleName, String)]
235−collectBookmarks' m =
236− map (P.getModuleName m, )
237− (mapMaybe getDeclarationTitle
238− (P.exportedDeclarations m))
239−
src/Language/PureScript/Docs/RenderedCode/Render.hs+26−12
@@ -5,7 +5,10 @@ module Language.PureScript.Docs.RenderedCode.Render (
55 renderType,
66 renderTypeAtom,
77 renderRow,
8− renderKind
8+ renderKind,
9+ RenderTypeOptions(..),
10+ defaultRenderTypeOptions,
11+ renderTypeWithOptions
912) where
1013
1114import Data.Monoid ((<>), mconcat, mempty)
@@ -119,9 +122,9 @@ forall_ = mkPattern match
119122 match (PrettyPrintForAll idents ty) = Just (idents, ty)
120123 match _ = Nothing
121124
122−insertPlaceholders :: Type -> Type
123−insertPlaceholders =
124− everywhereOnTypesTopDown convertForAlls . everywhereOnTypes convert
125+insertPlaceholders :: RenderTypeOptions -> Type -> Type
126+insertPlaceholders opts =
127+ everywhereOnTypesTopDown convertForAlls . everywhereOnTypes (convert opts)
125128
126129dePrim :: Type -> Type
127130dePrim ty@(TypeConstructor (Qualified _ name))
@@ -129,10 +132,10 @@ dePrim ty@(TypeConstructor (Qualified _ name))
129132 TypeConstructor $ Qualified Nothing name
130133dePrim other = other
131134
132−convert :: Type -> Type
133−convert (TypeApp (TypeApp f arg) ret) | f == tyFunction = PrettyPrintFunction arg ret
134−convert (TypeApp o r) | o == tyObject = PrettyPrintObject r
135−convert other = other
135+convert :: RenderTypeOptions -> Type -> Type
136+convert _ (TypeApp (TypeApp f arg) ret) | f == tyFunction = PrettyPrintFunction arg ret
137+convert opts (TypeApp o r) | o == tyObject && prettyPrintObjects opts = PrettyPrintObject r
138+convert _ other = other
136139
137140convertForAlls :: Type -> Type
138141convertForAlls (ForAll i ty _) = go [i] ty
@@ -141,8 +144,8 @@ convertForAlls (ForAll i ty _) = go [i] ty
141144 go idents other = PrettyPrintForAll idents other
142145convertForAlls other = other
143146
144−preprocessType :: Type -> Type
145−preprocessType = dePrim . insertPlaceholders
147+preprocessType :: RenderTypeOptions -> Type -> Type
148+preprocessType opts = dePrim . insertPlaceholders opts
146149
147150-- |
148151-- Render code representing a Kind
@@ -154,12 +157,23 @@ renderKind = kind . prettyPrintKind
154157-- Render code representing a Type, as it should appear inside parentheses
155158--
156159renderTypeAtom :: Type -> RenderedCode
157−renderTypeAtom = fromMaybe (error "Incomplete pattern") . pattern matchTypeAtom () . preprocessType
160+renderTypeAtom =
161+ fromMaybe (error "Incomplete pattern") . pattern matchTypeAtom () . preprocessType defaultRenderTypeOptions
158162
159163
160164-- |
161165-- Render code representing a Type
162166--
163167renderType :: Type -> RenderedCode
164−renderType = fromMaybe (error "Incomplete pattern") . pattern matchType () . preprocessType
168+renderType = renderTypeWithOptions defaultRenderTypeOptions
165169
170+data RenderTypeOptions = RenderTypeOptions
171+ { prettyPrintObjects :: Bool
172+ }
173+
174+defaultRenderTypeOptions :: RenderTypeOptions
175+defaultRenderTypeOptions = RenderTypeOptions { prettyPrintObjects = True }
176+
177+renderTypeWithOptions :: RenderTypeOptions -> Type -> RenderedCode
178+renderTypeWithOptions opts =
179+ fromMaybe (error "Incomplete pattern") . pattern matchType () . preprocessType opts
src/Language/PureScript/Docs/Types.hs+274−98
@@ -10,9 +10,9 @@ module Language.PureScript.Docs.Types
1010 where
1111
1212import Control.Arrow (first, (***))
13−import Control.Applicative ((<$>), (<*>))
13+import Control.Applicative ((<$>), (<*>), pure)
14+import Control.Monad (when)
1415import Data.Functor ((<$))
15−import Data.Char
1616import Data.Maybe (mapMaybe)
1717import Data.Version
1818import Data.Aeson ((.=))
@@ -23,7 +23,7 @@ import Data.Text (Text)
2323import Data.ByteString.Lazy (ByteString)
2424import qualified Data.Text as T
2525
26−import Web.Bower.PackageMeta hiding (Version)
26+import Web.Bower.PackageMeta hiding (Version, displayError)
2727
2828import qualified Language.PureScript as P
2929
@@ -39,11 +39,14 @@ data Package a = Package
3939 { pkgMeta :: PackageMeta
4040 , pkgVersion :: Version
4141 , pkgVersionTag :: String
42− , pkgModules :: [RenderedModule]
42+ , pkgModules :: [Module]
4343 , pkgBookmarks :: [Bookmark]
4444 , pkgResolvedDependencies :: [(PackageName, Version)]
4545 , pkgGithub :: (GithubUser, GithubRepo)
4646 , pkgUploader :: a
47+ , pkgCompilerVersion :: Version
48+ -- ^ The version of the PureScript compiler which was used to generate
49+ -- this data. We store this in order to reject packages which are too old.
4750 }
4851 deriving (Show, Eq, Ord)
4952
@@ -63,50 +66,105 @@ verifyPackage verifiedUser Package{..} =
6366 pkgResolvedDependencies
6467 pkgGithub
6568 verifiedUser
69+ pkgCompilerVersion
6670
6771packageName :: Package a -> PackageName
6872packageName = bowerName . pkgMeta
6973
70−data RenderedModule = RenderedModule
71− { rmName :: String
72− , rmComments :: Maybe String
73− , rmDeclarations :: [RenderedDeclaration]
74+data Module = Module
75+ { modName :: String
76+ , modComments :: Maybe String
77+ , modDeclarations :: [Declaration]
7478 }
7579 deriving (Show, Eq, Ord)
7680
77−data RenderedDeclaration = RenderedDeclaration
78− { rdTitle :: String
79− , rdComments :: Maybe String
80− , rdCode :: RenderedCode
81− , rdSourceSpan :: Maybe P.SourceSpan
82− , rdChildren :: [RenderedChildDeclaration]
81+data Declaration = Declaration
82+ { declTitle :: String
83+ , declComments :: Maybe String
84+ , declSourceSpan :: Maybe P.SourceSpan
85+ , declChildren :: [ChildDeclaration]
86+ , declFixity :: Maybe P.Fixity
87+ , declInfo :: DeclarationInfo
8388 }
8489 deriving (Show, Eq, Ord)
8590
86−data RenderedChildDeclaration = RenderedChildDeclaration
87− { rcdTitle :: String
88− , rcdComments :: Maybe String
89− , rcdCode :: RenderedCode
90− , rcdSourceSpan :: Maybe P.SourceSpan
91− , rcdType :: RenderedChildDeclarationType
92− }
91+-- |
92+-- A value of this type contains information that is specific to a particular
93+-- kind of declaration (as opposed to information which exists in all kinds of
94+-- declarations, which goes into the 'Declaration' type directly).
95+--
96+-- Many of the constructors are very similar to their equivalents in the real
97+-- PureScript AST, except that they have their name elided, since this is
98+-- already available via the rdTitle field of 'Declaration'.
99+--
100+data DeclarationInfo
101+ -- |
102+ -- A value declaration, with its type.
103+ --
104+ = ValueDeclaration P.Type
105+
106+ -- |
107+ -- A data/newtype declaration, with the kind of declaration (data or
108+ -- newtype) and its type arguments. Constructors are represented as child
109+ -- declarations.
110+ --
111+ | DataDeclaration P.DataDeclType [(String, Maybe P.Kind)]
112+
113+ -- |
114+ -- A data type foreign import, with its kind.
115+ --
116+ | ExternDataDeclaration P.Kind
117+
118+ -- |
119+ -- A type synonym, with its type arguments and its type.
120+ --
121+ | TypeSynonymDeclaration [(String, Maybe P.Kind)] P.Type
122+
123+ -- |
124+ -- A type class, with its type arguments and its superclasses. Instances and
125+ -- members are represented as child declarations.
126+ --
127+ | TypeClassDeclaration [(String, Maybe P.Kind)] [P.Constraint]
93128 deriving (Show, Eq, Ord)
94129
95−data RenderedChildDeclarationType
96− = ChildInstance
97− | ChildDataConstructor
98− | ChildTypeClassMember
99− deriving (Show, Eq, Ord, Bounded, Enum)
130+declInfoToString :: DeclarationInfo -> String
131+declInfoToString (ValueDeclaration _) = "value"
132+declInfoToString (DataDeclaration _ _) = "data"
133+declInfoToString (ExternDataDeclaration _) = "externData"
134+declInfoToString (TypeSynonymDeclaration _ _) = "typeSynonym"
135+declInfoToString (TypeClassDeclaration _ _) = "typeClass"
136+
137+data ChildDeclaration = ChildDeclaration
138+ { cdeclTitle :: String
139+ , cdeclComments :: Maybe String
140+ , cdeclSourceSpan :: Maybe P.SourceSpan
141+ , cdeclInfo :: ChildDeclarationInfo
142+ }
143+ deriving (Show, Eq, Ord)
100144
101−childDeclTypeToString :: RenderedChildDeclarationType -> String
102−childDeclTypeToString = withHead toLower . drop 5 . show
103− where
104− withHead f (x:xs) = f x : xs
105− withHead _ [] = []
145+data ChildDeclarationInfo
146+ -- |
147+ -- A type instance declaration, with its dependencies and its type.
148+ --
149+ = ChildInstance [P.Constraint] P.Type
150+
151+ -- |
152+ -- A data constructor, with its type arguments.
153+ --
154+ | ChildDataConstructor [P.Type]
155+
156+ -- |
157+ -- A type class member, with its type. Note that the type does not include
158+ -- the type class constraint; this may be added manually if desired. For
159+ -- example, `pure` from `Applicative` would be `forall a. a -> f a`.
160+ --
161+ | ChildTypeClassMember P.Type
162+ deriving (Show, Eq, Ord)
106163
107−childDeclarationTypes :: [(String, RenderedChildDeclarationType)]
108−childDeclarationTypes =
109− map (\t -> (childDeclTypeToString t, t)) [minBound .. maxBound]
164+childDeclInfoToString :: ChildDeclarationInfo -> String
165+childDeclInfoToString (ChildInstance _ _) = "instance"
166+childDeclInfoToString (ChildDataConstructor _) = "dataConstructor"
167+childDeclInfoToString (ChildTypeClassMember _) = "typeClassMember"
110168
111169newtype GithubUser
112170 = GithubUser { runGithubUser :: String }
@@ -117,10 +175,16 @@ newtype GithubRepo
117175 deriving (Show, Eq, Ord)
118176
119177data PackageError
120− = ErrorInPackageMeta BowerError
178+ = CompilerTooOld Version Version
179+ -- ^ Minimum allowable version for generating data with the current
180+ -- parser, and actual version used.
181+ | ErrorInPackageMeta BowerError
121182 | InvalidVersion
122− | InvalidDeclarationType
123− | InvalidRenderedCode String
183+ | InvalidDeclarationType String
184+ | InvalidChildDeclarationType String
185+ | InvalidFixity
186+ | InvalidKind String
187+ | InvalidDataDeclType String
124188 deriving (Show, Eq, Ord)
125189
126190type Bookmark = InPackage (P.ModuleName, String)
@@ -148,25 +212,33 @@ ignorePackage (FromDep _ x) = x
148212----------------------
149213-- Parsing
150214
151−parseUploadedPackage :: ByteString -> Either (ParseError PackageError) UploadedPackage
152−parseUploadedPackage = parse asUploadedPackage
215+parseUploadedPackage :: Version -> ByteString -> Either (ParseError PackageError) UploadedPackage
216+parseUploadedPackage minVersion = parse $ asUploadedPackage minVersion
217+
218+parseVerifiedPackage :: Version -> ByteString -> Either (ParseError PackageError) VerifiedPackage
219+parseVerifiedPackage minVersion = parse $ asVerifiedPackage minVersion
153220
154−parseVerifiedPackage :: ByteString -> Either (ParseError PackageError) VerifiedPackage
155−parseVerifiedPackage = parse asVerifiedPackage
221+asPackage :: Version -> (forall e. Parse e a) -> Parse PackageError (Package a)
222+asPackage minimumVersion uploader = do
223+ -- If the compilerVersion key is missing, we can be sure that it was produced
224+ -- with 0.7.0.0, since that is the only released version that included the
225+ -- psc-publish tool before this key was added.
226+ compilerVersion <- keyOrDefault "compilerVersion" (Version [0,7,0,0] []) asVersion
227+ when (compilerVersion < minimumVersion)
228+ (throwCustomError $ CompilerTooOld minimumVersion compilerVersion)
156229
157−asPackage :: (forall e. Parse e a) -> Parse PackageError (Package a)
158−asPackage uploader =
159230 Package <$> key "packageMeta" asPackageMeta .! ErrorInPackageMeta
160231 <*> key "version" asVersion
161232 <*> key "versionTag" asString
162− <*> key "modules" (eachInArray asRenderedModule)
233+ <*> key "modules" (eachInArray asModule)
163234 <*> key "bookmarks" asBookmarks .! ErrorInPackageMeta
164235 <*> key "resolvedDependencies" asResolvedDependencies
165236 <*> key "github" asGithub
166237 <*> key "uploader" uploader
238+ <*> pure compilerVersion
167239
168−asUploadedPackage :: Parse PackageError UploadedPackage
169−asUploadedPackage = asPackage asNotYetKnown
240+asUploadedPackage :: Version -> Parse PackageError UploadedPackage
241+asUploadedPackage minVersion = asPackage minVersion asNotYetKnown
170242
171243asNotYetKnown :: Parse e NotYetKnown
172244asNotYetKnown = NotYetKnown <$ asNull
@@ -174,8 +246,35 @@ asNotYetKnown = NotYetKnown <$ asNull
174246instance A.FromJSON NotYetKnown where
175247 parseJSON = toAesonParser' asNotYetKnown
176248
177−asVerifiedPackage :: Parse PackageError VerifiedPackage
178−asVerifiedPackage = asPackage asGithubUser
249+asVerifiedPackage :: Version -> Parse PackageError VerifiedPackage
250+asVerifiedPackage minVersion = asPackage minVersion asGithubUser
251+
252+displayPackageError :: PackageError -> Text
253+displayPackageError e = case e of
254+ CompilerTooOld minV usedV ->
255+ "Expecting data produced by at least version " <> T.pack (showVersion minV)
256+ <> " of the compiler, but it appears that " <> T.pack (showVersion usedV)
257+ <> " was used."
258+ ErrorInPackageMeta err ->
259+ "Error in package metadata: " <> showBowerError err
260+ InvalidVersion ->
261+ "Invalid version"
262+ InvalidDeclarationType str ->
263+ "Invalid declaration type: \"" <> T.pack str <> "\""
264+ InvalidChildDeclarationType str ->
265+ "Invalid child declaration type: \"" <> T.pack str <> "\""
266+ InvalidFixity ->
267+ "Invalid fixity"
268+ InvalidKind str ->
269+ "Invalid kind: \"" <> T.pack str <> "\""
270+ InvalidDataDeclType str ->
271+ "Invalid data declaration type: \"" <> T.pack str <> "\""
272+ where
273+ (<>) = T.append
274+
275+instance A.FromJSON a => A.FromJSON (Package a) where
276+ parseJSON = toAesonParser displayPackageError
277+ (asPackage (Version [0,0,0,0] []) fromAesonParser)
179278
180279asGithubUser :: Parse e GithubUser
181280asGithubUser = GithubUser <$> asString
@@ -183,11 +282,6 @@ asGithubUser = GithubUser <$> asString
183282instance A.FromJSON GithubUser where
184283 parseJSON = toAesonParser' asGithubUser
185284
186−instance A.FromJSON a => A.FromJSON (Package a) where
187− -- TODO: actual error display
188− parseJSON = toAesonParser (T.pack . show)
189− (asPackage fromAesonParser)
190−
191285asVersion :: Parse PackageError Version
192286asVersion = withString (maybe (Left InvalidVersion) Right . parseVersion')
193287
@@ -197,39 +291,105 @@ parseVersion' str =
197291 [(vers, "")] -> Just vers
198292 _ -> Nothing
199293
200−asRenderedModule :: Parse PackageError RenderedModule
201−asRenderedModule =
202− RenderedModule <$> key "name" asString
203− <*> key "comments" (perhaps asString)
204− <*> key "declarations" (eachInArray asDeclaration)
294+asModule :: Parse PackageError Module
295+asModule =
296+ Module <$> key "name" asString
297+ <*> key "comments" (perhaps asString)
298+ <*> key "declarations" (eachInArray asDeclaration)
205299
206−asDeclaration :: Parse PackageError RenderedDeclaration
300+asDeclaration :: Parse PackageError Declaration
207301asDeclaration =
208− RenderedDeclaration <$> key "title" asString
209− <*> key "comments" (perhaps asString)
210− <*> key "code" asRenderedCode .! InvalidRenderedCode
211− <*> key "sourceSpan" (perhaps asSourceSpan)
212− <*> key "children" (eachInArray asRenderedChildDeclaration)
213−
214−asRenderedChildDeclaration :: Parse PackageError RenderedChildDeclaration
215−asRenderedChildDeclaration =
216− RenderedChildDeclaration <$> key "title" asString
217− <*> key "comments" (perhaps asString)
218− <*> key "code" asRenderedCode .! InvalidRenderedCode
219− <*> key "sourceSpan" (perhaps asSourceSpan)
220− <*> key "type" asRenderedChildDeclarationType .!! InvalidDeclarationType
302+ Declaration <$> key "title" asString
303+ <*> key "comments" (perhaps asString)
304+ <*> key "sourceSpan" (perhaps asSourceSpan)
305+ <*> key "children" (eachInArray asChildDeclaration)
306+ <*> key "fixity" (perhaps asFixity)
307+ <*> key "info" asDeclarationInfo
308+
309+asFixity :: Parse PackageError P.Fixity
310+asFixity = P.Fixity <$> key "associativity" asAssociativity
311+ <*> key "precedence" asIntegral
312+
313+parseAssociativity :: String -> Maybe P.Associativity
314+parseAssociativity str = case str of
315+ "infix" -> Just P.Infix
316+ "infixl" -> Just P.Infixl
317+ "infixr" -> Just P.Infixr
318+ _ -> Nothing
319+
320+asAssociativity :: Parse PackageError P.Associativity
321+asAssociativity = withString (maybe (Left InvalidFixity) Right . parseAssociativity)
322+
323+asDeclarationInfo :: Parse PackageError DeclarationInfo
324+asDeclarationInfo = do
325+ ty <- key "declType" asString
326+ case ty of
327+ "value" ->
328+ ValueDeclaration <$> key "type" asType
329+ "data" ->
330+ DataDeclaration <$> key "dataDeclType" asDataDeclType
331+ <*> key "typeArguments" asTypeArguments
332+ "externData" ->
333+ ExternDataDeclaration <$> key "kind" asKind
334+ "typeSynonym" ->
335+ TypeSynonymDeclaration <$> key "arguments" asTypeArguments
336+ <*> key "type" asType
337+ "typeClass" ->
338+ TypeClassDeclaration <$> key "arguments" asTypeArguments
339+ <*> key "superclasses" (eachInArray asConstraint)
340+ other ->
341+ throwCustomError (InvalidDeclarationType other)
342+
343+asTypeArguments :: Parse PackageError [(String, Maybe P.Kind)]
344+asTypeArguments = eachInArray asTypeArgument
221345 where
222− p .!! err = p .! const err
346+ asTypeArgument = (,) <$> nth 0 asString <*> nth 1 (perhaps asKind)
347+
348+asKind :: Parse e P.Kind
349+asKind = fromAesonParser
350+
351+asType :: Parse e P.Type
352+asType = fromAesonParser
353+
354+asDataDeclType :: Parse PackageError P.DataDeclType
355+asDataDeclType =
356+ withString $ \s -> case s of
357+ "data" -> Right P.Data
358+ "newtype" -> Right P.Newtype
359+ other -> Left (InvalidDataDeclType other)
223360
224−asRenderedChildDeclarationType :: Parse PackageError RenderedChildDeclarationType
225−asRenderedChildDeclarationType =
226− withString (maybe (Left InvalidDeclarationType) Right .
227− flip lookup childDeclarationTypes)
361+asChildDeclaration :: Parse PackageError ChildDeclaration
362+asChildDeclaration =
363+ ChildDeclaration <$> key "title" asString
364+ <*> key "comments" (perhaps asString)
365+ <*> key "sourceSpan" (perhaps asSourceSpan)
366+ <*> key "info" asChildDeclarationInfo
367+
368+asChildDeclarationInfo :: Parse PackageError ChildDeclarationInfo
369+asChildDeclarationInfo = do
370+ ty <- key "declType" asString
371+ case ty of
372+ "instance" ->
373+ ChildInstance <$> key "dependencies" (eachInArray asConstraint)
374+ <*> key "type" asType
375+ "dataConstructor" ->
376+ ChildDataConstructor <$> key "arguments" (eachInArray asType)
377+ "typeClassMember" ->
378+ ChildTypeClassMember <$> key "type" asType
379+ other ->
380+ throwCustomError $ InvalidChildDeclarationType other
228381
229382asSourcePos :: Parse e P.SourcePos
230383asSourcePos = P.SourcePos <$> nth 0 asIntegral
231384 <*> nth 1 asIntegral
232385
386+asConstraint :: Parse PackageError P.Constraint
387+asConstraint = (,) <$> nth 0 asQualifiedProperName
388+ <*> nth 1 (eachInArray asType)
389+
390+asQualifiedProperName :: Parse e (P.Qualified P.ProperName)
391+asQualifiedProperName = fromAesonParser
392+
233393asBookmarks :: Parse BowerError [Bookmark]
234394asBookmarks = eachInArray asBookmark
235395
@@ -274,38 +434,54 @@ instance A.ToJSON a => A.ToJSON (Package a) where
274434 pkgResolvedDependencies
275435 , "github" .= pkgGithub
276436 , "uploader" .= pkgUploader
437+ , "compilerVersion" .= showVersion P.version
277438 ]
278439
279440instance A.ToJSON NotYetKnown where
280441 toJSON _ = A.Null
281442
282−instance A.ToJSON RenderedModule where
283− toJSON RenderedModule{..} =
284− A.object [ "name" .= rmName
285− , "comments" .= rmComments
286− , "declarations" .= rmDeclarations
443+instance A.ToJSON Module where
444+ toJSON Module{..} =
445+ A.object [ "name" .= modName
446+ , "comments" .= modComments
447+ , "declarations" .= modDeclarations
287448 ]
288449
289−instance A.ToJSON RenderedDeclaration where
290− toJSON RenderedDeclaration{..} =
291− A.object [ "title" .= rdTitle
292− , "comments" .= rdComments
293− , "code" .= rdCode
294− , "sourceSpan" .= rdSourceSpan
295− , "children" .= rdChildren
450+instance A.ToJSON Declaration where
451+ toJSON Declaration{..} =
452+ A.object [ "title" .= declTitle
453+ , "comments" .= declComments
454+ , "sourceSpan" .= declSourceSpan
455+ , "children" .= declChildren
456+ , "fixity" .= declFixity
457+ , "info" .= declInfo
296458 ]
297459
298−instance A.ToJSON RenderedChildDeclaration where
299− toJSON RenderedChildDeclaration{..} =
300− A.object [ "title" .= rcdTitle
301− , "comments" .= rcdComments
302− , "code" .= rcdCode
303− , "sourceSpan" .= rcdSourceSpan
304− , "type" .= rcdType
460+instance A.ToJSON ChildDeclaration where
461+ toJSON ChildDeclaration{..} =
462+ A.object [ "title" .= cdeclTitle
463+ , "comments" .= cdeclComments
464+ , "sourceSpan" .= cdeclSourceSpan
465+ , "info" .= cdeclInfo
305466 ]
306467
307−instance A.ToJSON RenderedChildDeclarationType where
308− toJSON = A.toJSON . childDeclTypeToString
468+instance A.ToJSON DeclarationInfo where
469+ toJSON info = A.object $ "declType" .= declInfoToString info : props
470+ where
471+ props = case info of
472+ ValueDeclaration ty -> ["type" .= ty]
473+ DataDeclaration ty args -> ["dataDeclType" .= ty, "typeArguments" .= args]
474+ ExternDataDeclaration kind -> ["kind" .= kind]
475+ TypeSynonymDeclaration args ty -> ["arguments" .= args, "type" .= ty]
476+ TypeClassDeclaration args super -> ["arguments" .= args, "superclasses" .= super]
477+
478+instance A.ToJSON ChildDeclarationInfo where
479+ toJSON info = A.object $ "declType" .= childDeclInfoToString info : props
480+ where
481+ props = case info of
482+ ChildInstance deps ty -> ["dependencies" .= deps, "type" .= ty]
483+ ChildDataConstructor args -> ["arguments" .= args]
484+ ChildTypeClassMember ty -> ["type" .= ty]
309485
310486instance A.ToJSON GithubUser where
311487 toJSON = A.toJSON . runGithubUser
src/Language/PureScript/Environment.hs+25−4
@@ -13,12 +13,15 @@
1313-----------------------------------------------------------------------------
1414
1515{-# LANGUAGE DeriveDataTypeable #-}
16+{-# LANGUAGE OverloadedStrings #-}
1617
1718module Language.PureScript.Environment where
1819
1920import Data.Data
2021import Data.Maybe (fromMaybe)
2122import qualified Data.Map as M
23+import qualified Data.Text as T
24+import qualified Data.Aeson as A
2225
2326import Language.PureScript.Kinds
2427import Language.PureScript.Names
@@ -49,7 +52,7 @@ data Environment = Environment {
4952 -- |
5053 -- Available type class dictionaries
5154 --
52− , typeClassDictionaries :: M.Map (Qualified Ident, Maybe ModuleName) TypeClassDictionaryInScope
55+ , typeClassDictionaries :: M.Map (Maybe ModuleName) (M.Map (Qualified ProperName) (M.Map (Qualified Ident) TypeClassDictionaryInScope))
5356 -- |
5457 -- Type classes
5558 --
@@ -137,6 +140,16 @@ instance Show DataDeclType where
137140 show Data = "data"
138141 show Newtype = "newtype"
139142
143+instance A.ToJSON DataDeclType where
144+ toJSON = A.toJSON . show
145+
146+instance A.FromJSON DataDeclType where
147+ parseJSON = A.withText "DataDeclType" $ \str ->
148+ case str of
149+ "data" -> return Data
150+ "newtype" -> return Newtype
151+ other -> fail $ "invalid type: '" ++ T.unpack other ++ "'"
152+
140153-- |
141154-- Construct a ProperName in the Prim module
142155--
@@ -201,9 +214,17 @@ tyObject = primTy "Object"
201214-- Check whether a type is an object
202215--
203216isObject :: Type -> Bool
204−isObject = (==) tyObject . extract
205− where extract (TypeApp t _) = t
206− extract t = t
217+isObject = isTypeOrApplied tyObject
218+
219+-- |
220+-- Check whether a type is a function
221+--
222+isFunction :: Type -> Bool
223+isFunction = isTypeOrApplied tyFunction
224+
225+isTypeOrApplied :: Type -> Type -> Bool
226+isTypeOrApplied t1 (TypeApp t2 _) = t1 == t2
227+isTypeOrApplied t1 t2 = t1 == t2
207228
208229-- |
209230-- Smart constructor for function types
src/Language/PureScript/Errors.hs+70−37
@@ -19,7 +19,7 @@
1919module Language.PureScript.Errors where
2020
2121import Data.Either (lefts, rights)
22−import Data.List (intercalate)
22+import Data.List (intercalate, transpose)
2323import Data.Function (on)
2424import Data.Monoid
2525import Data.Foldable (fold, foldMap)
@@ -35,7 +35,7 @@ import Control.Monad.Trans.State.Lazy
3535import Control.Arrow(first)
3636
3737import Language.PureScript.AST
38−import Language.PureScript.Environment (isObject)
38+import Language.PureScript.Environment (isObject, isFunction)
3939import Language.PureScript.Pretty
4040import Language.PureScript.Types
4141import Language.PureScript.Names
@@ -107,6 +107,7 @@ data SimpleErrorMessage
107107 | ArgListLengthsDiffer Ident
108108 | OverlappingArgNames (Maybe Ident)
109109 | MissingClassMember Ident
110+ | ExtraneousClassMember Ident
110111 | ExpectedType Kind
111112 | IncorrectConstructorArity (Qualified ProperName)
112113 | SubsumptionCheckFailed
@@ -119,6 +120,8 @@ data SimpleErrorMessage
119120 | TransitiveExportError DeclarationRef [DeclarationRef]
120121 | ShadowedName Ident
121122 | WildcardInferredType Type
123+ | NotExhaustivePattern [[Binder]] Bool
124+ | OverlappingPattern [[Binder]] Bool
122125 | ClassOperator ProperName Ident
123126 deriving (Show)
124127
@@ -215,6 +218,7 @@ errorCode em = case unwrapErrorMessage em of
215218 (ArgListLengthsDiffer _) -> "ArgListLengthsDiffer"
216219 (OverlappingArgNames _) -> "OverlappingArgNames"
217220 (MissingClassMember _) -> "MissingClassMember"
221+ (ExtraneousClassMember _) -> "ExtraneousClassMember"
218222 (ExpectedType _) -> "ExpectedType"
219223 (IncorrectConstructorArity _) -> "IncorrectConstructorArity"
220224 SubsumptionCheckFailed -> "SubsumptionCheckFailed"
@@ -227,6 +231,8 @@ errorCode em = case unwrapErrorMessage em of
227231 (TransitiveExportError _ _) -> "TransitiveExportError"
228232 (ShadowedName _) -> "ShadowedName"
229233 (WildcardInferredType _) -> "WildcardInferredType"
234+ (NotExhaustivePattern _ _) -> "NotExhaustivePattern"
235+ (OverlappingPattern _ _) -> "OverlappingPattern"
230236 (ClassOperator _ _) -> "ClassOperator"
231237
232238-- |
@@ -236,10 +242,10 @@ newtype MultipleErrors = MultipleErrors
236242 { runMultipleErrors :: [ErrorMessage] } deriving (Show, Monoid)
237243
238244instance UnificationError Type MultipleErrors where
239− occursCheckFailed = occursCheckFailed
245+ occursCheckFailed t = MultipleErrors [occursCheckFailed t]
240246
241247instance UnificationError Kind MultipleErrors where
242− occursCheckFailed = occursCheckFailed
248+ occursCheckFailed k = MultipleErrors [occursCheckFailed k]
243249
244250-- | Check whether a collection of errors is empty or not.
245251nonEmpty :: MultipleErrors -> Bool
@@ -270,6 +276,9 @@ data LabelType = TypeLabel | SkolemLabel String deriving (Show, Eq, Ord)
270276-- | A map from rigid type variable name/unknown variable pairs to new variables.
271277type UnknownMap = M.Map (LabelType, Unknown) Unknown
272278
279+-- | How critical the issue is
280+data Level = Error | Warning deriving Show
281+
273282-- |
274283-- Extract nested error messages from wrapper errors
275284--
@@ -342,8 +351,8 @@ onTypesInErrorMessageM f = g
342351-- |
343352-- Pretty print a single error, simplifying if necessary
344353--
345−prettyPrintSingleError :: Bool -> ErrorMessage -> State UnknownMap Box.Box
346−prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
354+prettyPrintSingleError :: Bool -> Level -> ErrorMessage -> State UnknownMap Box.Box
355+prettyPrintSingleError full level e = prettyPrintErrorMessage <$> onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
347356 where
348357 -- |
349358 -- Pretty print an ErrorMessage
@@ -371,7 +380,7 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
371380 , indent . line $ path
372381 ]
373382 goSimple (ErrorParsingExterns err) =
374− paras [ line "Error parsing externs files: "
383+ paras [ lineWithLevel "parsing externs files: "
375384 , indent . line . show $ err
376385 ]
377386 goSimple (ErrorParsingFFIModule path) =
@@ -436,9 +445,9 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
436445 goSimple (UnknownDataConstructor dc tc) =
437446 line $ "Unknown data constructor " ++ show dc ++ foldMap ((" for type constructor " ++) . show) tc
438447 goSimple (ConflictingImport nm mn) =
439− line $ "Cannot declare `" ++ nm ++ "` since another declaration of that name was imported from `" ++ show mn ++ "`"
448+ line $ "Cannot declare " ++ show nm ++ " since another declaration of that name was imported from " ++ show mn
440449 goSimple (ConflictingImports nm m1 m2) =
441− line $ "Conflicting imports for " ++ nm ++ " from modules " ++ show m1 ++ " and " ++ show m2
450+ line $ "Conflicting imports for " ++ show nm ++ " from modules " ++ show m1 ++ " and " ++ show m2
442451 goSimple (ConflictingTypeDecls nm) =
443452 line $ "Conflicting type declarations for " ++ show nm
444453 goSimple (ConflictingCtorDecls nm) =
@@ -513,6 +522,8 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
513522 line $ "Overlapping names in function/binder" ++ foldMap ((" in declaration" ++) . show) ident
514523 goSimple (MissingClassMember ident) =
515524 line $ "Member " ++ show ident ++ " has not been implemented"
525+ goSimple (ExtraneousClassMember ident) =
526+ line $ "Member " ++ show ident ++ " is not a member of the class being instantiated"
516527 goSimple (ExpectedType kind) =
517528 line $ "Expected type of kind *, was " ++ prettyPrintKind kind
518529 goSimple (IncorrectConstructorArity nm) =
@@ -552,56 +563,66 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
552563 ]
553564 goSimple (WildcardInferredType ty) =
554565 line $ "The wildcard type definition has the inferred type " ++ prettyPrintType ty
566+ goSimple (NotExhaustivePattern bs b) =
567+ indent $ paras $ [ line "Pattern could not be determined to cover all cases."
568+ , line $ "The definition has the following uncovered cases:\n"
569+ , Box.hsep 1 Box.left (map (paras . map (line . prettyPrintBinderAtom)) (transpose bs))
570+ ] ++ if not b then [line "..."] else []
571+ goSimple (OverlappingPattern bs b) =
572+ indent $ paras $ [ line "Redundant cases have been detected."
573+ , line $ "The definition has the following redundant cases:\n"
574+ , Box.hsep 1 Box.left (map (paras . map (line . prettyPrintBinderAtom)) (transpose bs))
575+ ] ++ if not b then [line "..."] else []
555576 go (NotYetDefined names err) =
556577 paras [ line $ "The following are not yet defined here: " ++ intercalate ", " (map show names) ++ ":"
557578 , indent $ go err
558579 ]
559580 go (ErrorUnifyingTypes t1 t2 err) =
560− paras [ line "Error unifying type "
581+ paras [ lineWithLevel "unifying type "
561582 , indent $ line $ prettyPrintType t1
562583 , line "with type"
563584 , indent $ line $ prettyPrintType t2
564585 , go err
565586 ]
566587 go (ErrorInExpression expr err) =
567− paras [ line "Error in expression:"
588+ paras [ lineWithLevel "in expression:"
568589 , indent $ line $ prettyPrintValue expr
569590 , go err
570591 ]
571592 go (ErrorInModule mn err) =
572− paras [ line $ "Error in module " ++ show mn ++ ":"
593+ paras [ lineWithLevel $ "in module " ++ show mn ++ ":"
573594 , go err
574595 ]
575596 go (ErrorInSubsumption t1 t2 err) =
576− paras [ line "Error checking that type "
597+ paras [ lineWithLevel "checking that type "
577598 , indent $ line $ prettyPrintType t1
578599 , line "subsumes type"
579600 , indent $ line $ prettyPrintType t2
580601 , go err
581602 ]
582603 go (ErrorInInstance name ts err) =
583− paras [ line $ "Error in type class instance " ++ show name ++ " " ++ unwords (map prettyPrintTypeAtom ts) ++ ":"
604+ paras [ lineWithLevel $ "in type class instance " ++ show name ++ " " ++ unwords (map prettyPrintTypeAtom ts) ++ ":"
584605 , go err
585606 ]
586607 go (ErrorCheckingKind ty err) =
587− paras [ line "Error checking kind of type "
608+ paras [ lineWithLevel "checking kind of type "
588609 , indent $ line $ prettyPrintType ty
589610 , go err
590611 ]
591612 go (ErrorInferringType expr err) =
592− paras [ line "Error inferring type of value "
613+ paras [ lineWithLevel "inferring type of value "
593614 , indent $ line $ prettyPrintValue expr
594615 , go err
595616 ]
596617 go (ErrorCheckingType expr ty err) =
597− paras [ line "Error checking that value "
618+ paras [ lineWithLevel "checking that value "
598619 , indent $ line $ prettyPrintValue expr
599620 , line "has type"
600621 , indent $ line $ prettyPrintType ty
601622 , go err
602623 ]
603624 go (ErrorInApplication f t a err) =
604− paras [ line "Error applying function"
625+ paras [ lineWithLevel "applying function"
605626 , indent $ line $ prettyPrintValue f
606627 , line "of type"
607628 , indent $ line $ prettyPrintType t
@@ -610,35 +631,35 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
610631 , go err
611632 ]
612633 go (ErrorInDataConstructor nm err) =
613− paras [ line $ "Error in data constructor " ++ show nm ++ ":"
634+ paras [ lineWithLevel $ "in data constructor " ++ show nm ++ ":"
614635 , go err
615636 ]
616637 go (ErrorInTypeConstructor nm err) =
617− paras [ line $ "Error in type constructor " ++ show nm ++ ":"
638+ paras [ lineWithLevel $ "in type constructor " ++ show nm ++ ":"
618639 , go err
619640 ]
620641 go (ErrorInBindingGroup nms err) =
621− paras [ line $ "Error in binding group " ++ intercalate ", " (map show nms) ++ ":"
642+ paras [ lineWithLevel $ "in binding group " ++ intercalate ", " (map show nms) ++ ":"
622643 , go err
623644 ]
624645 go (ErrorInDataBindingGroup err) =
625− paras [ line $ "Error in data binding group:"
646+ paras [ lineWithLevel $ "in data binding group:"
626647 , go err
627648 ]
628649 go (ErrorInTypeSynonym name err) =
629− paras [ line $ "Error in type synonym " ++ show name ++ ":"
650+ paras [ lineWithLevel $ "in type synonym " ++ show name ++ ":"
630651 , go err
631652 ]
632653 go (ErrorInValueDeclaration n err) =
633− paras [ line $ "Error in value declaration " ++ show n ++ ":"
654+ paras [ lineWithLevel $ "in value declaration " ++ show n ++ ":"
634655 , go err
635656 ]
636657 go (ErrorInForeignImport nm err) =
637− paras [ line $ "Error in foreign import " ++ show nm ++ ":"
658+ paras [ lineWithLevel $ "in foreign import " ++ show nm ++ ":"
638659 , go err
639660 ]
640661 go (PositionedError srcSpan err) =
641− paras [ line $ "Error at " ++ displaySourceSpan srcSpan ++ ":"
662+ paras [ lineWithLevel $ "at " ++ displaySourceSpan srcSpan ++ ":"
642663 , indent $ go err
643664 ]
644665 go (SimpleErrorWrapper sem) = goSimple sem
@@ -646,14 +667,17 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
646667 line :: String -> Box.Box
647668 line = Box.text
648669
670+ lineWithLevel :: String -> Box.Box
671+ lineWithLevel text = line $ show level ++ " " ++ text
672+
649673 suggestions :: ErrorMessage -> [Box.Box]
650674 suggestions = suggestions' . unwrapErrorMessage
651675 where
652− suggestions' (ConflictingImport nm im) = [ line $ "Possible fix: hide `" ++ nm ++ "` when importing `" ++ show im ++ "`:"
676+ suggestions' (ConflictingImport nm im) = [ line $ "Possible fix: hide " ++ show nm ++ " when importing " ++ show im ++ ":"
653677 , indent . line $ "import " ++ show im ++ " hiding (" ++ nm ++ ")"
654678 ]
655679 suggestions' (TypesDoNotUnify t1 t2)
656− | any isObject [t1, t2] = [line "Note that function composition in PureScript is defined using `(<<<)`"]
680+ | isObject t1 && isFunction t2 = [line "Note that function composition in PureScript is defined using (<<<)"]
657681 | otherwise = []
658682 suggestions' _ = []
659683
@@ -684,6 +708,7 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
684708 prettyPrintExport (ValueRef ident) = show ident
685709 prettyPrintExport (TypeClassRef pn) = show pn
686710 prettyPrintExport (TypeInstanceRef ident) = show ident
711+ prettyPrintExport (ModuleRef name) = "module " ++ show name
687712 prettyPrintExport (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref
688713
689714 -- |
@@ -722,24 +747,32 @@ prettyPrintSingleError full e = prettyPrintErrorMessage <$> onTypesInErrorMessag
722747-- Pretty print multiple errors
723748--
724749prettyPrintMultipleErrors :: Bool -> MultipleErrors -> String
725−prettyPrintMultipleErrors full = flip evalState M.empty . prettyPrintMultipleErrorsWith "Error:" "Multiple errors:" full
750+prettyPrintMultipleErrors full = renderBox . prettyPrintMultipleErrorsBox full
726751
727752-- |
728753-- Pretty print multiple warnings
729754--
730755prettyPrintMultipleWarnings :: Bool -> MultipleErrors -> String
731−prettyPrintMultipleWarnings full = flip evalState M.empty . prettyPrintMultipleErrorsWith "Warning:" "Multiple warnings:" full
756+prettyPrintMultipleWarnings full = renderBox . prettyPrintMultipleWarningsBox full
757+
758+-- | Pretty print warnings as a Box
759+prettyPrintMultipleWarningsBox :: Bool -> MultipleErrors -> Box.Box
760+prettyPrintMultipleWarningsBox full = flip evalState M.empty . prettyPrintMultipleErrorsWith Warning "Warning found:" "Multiple warnings found:" full
761+
762+-- | Pretty print errors as a Box
763+prettyPrintMultipleErrorsBox :: Bool -> MultipleErrors -> Box.Box
764+prettyPrintMultipleErrorsBox full = flip evalState M.empty . prettyPrintMultipleErrorsWith Error "Error found:" "Multiple errors found:" full
732765
733−prettyPrintMultipleErrorsWith :: String -> String -> Bool -> MultipleErrors -> State UnknownMap String
734−prettyPrintMultipleErrorsWith intro _ full (MultipleErrors [e]) = do
735− result <- prettyPrintSingleError full e
736− return $ renderBox $
766+prettyPrintMultipleErrorsWith :: Level -> String -> String -> Bool -> MultipleErrors -> State UnknownMap Box.Box
767+prettyPrintMultipleErrorsWith level intro _ full (MultipleErrors [e]) = do
768+ result <- prettyPrintSingleError full level e
769+ return $
737770 Box.vcat Box.left [ Box.text intro
738771 , result
739772 ]
740−prettyPrintMultipleErrorsWith _ intro full (MultipleErrors es) = do
741− result <- forM es $ (liftM $ Box.moveRight 2) . prettyPrintSingleError full
742− return $ renderBox $
773+prettyPrintMultipleErrorsWith level _ intro full (MultipleErrors es) = do
774+ result <- forM es $ (liftM $ Box.moveRight 2) . prettyPrintSingleError full level
775+ return $
743776 Box.vcat Box.left [ Box.text intro
744777 , Box.vsep 1 Box.left result
745778 ]
src/Language/PureScript/Kinds.hs+5−1
@@ -13,10 +13,12 @@
1313-----------------------------------------------------------------------------
1414
1515{-# LANGUAGE DeriveDataTypeable #-}
16+{-# LANGUAGE TemplateHaskell #-}
1617
1718module Language.PureScript.Kinds where
1819
1920import Data.Data
21+import qualified Data.Aeson.TH as A
2022
2123import Control.Applicative
2224import Control.Monad.Unify (Unknown)
@@ -44,7 +46,9 @@ data Kind
4446 -- |
4547 -- Function kinds
4648 --
47− | FunKind Kind Kind deriving (Show, Eq, Data, Typeable)
49+ | FunKind Kind Kind deriving (Show, Eq, Ord, Data, Typeable)
50+
51+$(A.deriveJSON A.defaultOptions ''Kind)
4852
4953everywhereOnKinds :: (Kind -> Kind) -> Kind -> Kind
5054everywhereOnKinds f = go
src/Language/PureScript/Linter.hs+8−2
@@ -16,7 +16,7 @@
1616{-# LANGUAGE FlexibleContexts #-}
1717{-# LANGUAGE ScopedTypeVariables #-}
1818
19−module Language.PureScript.Linter (lint) where
19+module Language.PureScript.Linter (lint, module L) where
2020
2121import Data.List (mapAccumL, nub)
2222import Data.Maybe (mapMaybe)
@@ -30,6 +30,7 @@ import Control.Monad.Writer.Class
3030import Language.PureScript.AST
3131import Language.PureScript.Names
3232import Language.PureScript.Errors
33+import Language.PureScript.Linter.Exhaustive as L
3334
3435-- | Lint the PureScript AST.
3536-- |
@@ -52,7 +53,12 @@ lint (Module _ mn ds _) = censor (onErrorMessages (ErrorInModule mn)) $ mapM_ li
5253 lintDeclaration :: Declaration -> m ()
5354 lintDeclaration d =
5455 let (f, _, _, _, _) = everythingWithContextOnValues moduleNames mempty mappend stepD stepE stepB def def
55− in tell (f d)
56+
57+ f' :: Declaration -> MultipleErrors
58+ f' (PositionedDeclaration pos _ dec) = onErrorMessages (PositionedError pos) (f' dec)
59+ f' dec = f dec
60+
61+ in tell (f' d)
5662 where
5763 def s _ = (s, mempty)
5864
src/Language/PureScript/Linter/Exhaustive.hsnew file+285
@@ -0,0 +1,285 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Exhaustive
4+-- Copyright : (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+-- | Module for exhaustivity checking over pattern matching definitions
13+-- | The algorithm analyses the clauses of a definition one by one from top
14+-- | to bottom, where in each step it has the cases already missing (uncovered),
15+-- | and it generates the new set of missing cases.
16+--
17+-----------------------------------------------------------------------------
18+
19+{-# LANGUAGE FlexibleContexts #-}
20+{-# LANGUAGE ScopedTypeVariables #-}
21+
22+module Language.PureScript.Linter.Exhaustive
23+ ( checkExhaustive
24+ , checkExhaustiveModule
25+ ) where
26+
27+import qualified Data.Map as M
28+import Data.Maybe (fromMaybe)
29+import Data.List (foldl', sortBy, nub)
30+import Data.Function (on)
31+
32+import Control.Monad (unless)
33+import Control.Applicative
34+import Control.Arrow (first, second)
35+import Control.Monad.Writer.Class
36+
37+import Language.PureScript.AST.Binders
38+import Language.PureScript.AST.Declarations
39+import Language.PureScript.Environment
40+import Language.PureScript.Names as P
41+import Language.PureScript.Kinds
42+import Language.PureScript.Types as P
43+import Language.PureScript.Errors
44+
45+import Language.PureScript.AST.Traversals (everywhereOnValuesTopDownM)
46+
47+-- |
48+-- Qualifies a propername from a given qualified propername and a default module name
49+--
50+qualifyName :: a -> ModuleName -> Qualified a -> Qualified a
51+qualifyName n defmn qn = Qualified (Just mn) n
52+ where
53+ (mn, _) = qualify defmn qn
54+
55+-- |
56+-- Given an environment and a datatype or newtype name,
57+-- this function returns the associated data constructors if it is the case of a datatype
58+-- where: - ProperName is the name of the constructor (for example, "Nothing" in Maybe)
59+-- - [Type] is the list of arguments, if it has (for example, "Just" has [TypeVar "a"])
60+--
61+getConstructors :: Environment -> ModuleName -> (Qualified ProperName) -> [(ProperName, [Type])]
62+getConstructors env defmn n = extractConstructors lnte
63+ where
64+ qpn :: Qualified ProperName
65+ qpn = getConsDataName n
66+
67+ getConsDataName :: (Qualified ProperName) -> (Qualified ProperName)
68+ getConsDataName con = qualifyName nm defmn con
69+ where
70+ nm = case getConsInfo con of
71+ Nothing -> error $ "ProperName " ++ show con ++ " not in the scope of the current environment in getConsDataName."
72+ Just (_, pm, _, _) -> pm
73+
74+ getConsInfo :: (Qualified ProperName) -> Maybe (DataDeclType, ProperName, Type, [Ident])
75+ getConsInfo con = M.lookup con dce
76+ where
77+ dce :: M.Map (Qualified ProperName) (DataDeclType, ProperName, Type, [Ident])
78+ dce = dataConstructors env
79+
80+ lnte :: Maybe (Kind, TypeKind)
81+ lnte = M.lookup qpn (types env)
82+
83+ extractConstructors :: Maybe (Kind, TypeKind) -> [(ProperName, [Type])]
84+ extractConstructors (Just (_, DataType _ pt)) = pt
85+ extractConstructors _ = error "Data name not in the scope of the current environment in extractConstructors"
86+
87+-- |
88+-- Replicates a wildcard binder
89+--
90+initialize :: Int -> [Binder]
91+initialize l = replicate l NullBinder
92+
93+-- |
94+-- Applies a function over two lists of tuples that may lack elements
95+--
96+genericMerge :: Ord a =>
97+ (a -> Maybe b -> Maybe c -> d) ->
98+ [(a, b)] ->
99+ [(a, c)] ->
100+ [d]
101+genericMerge _ [] [] = []
102+genericMerge f bs [] = map (\(s, b) -> f s (Just b) Nothing) bs
103+genericMerge f [] bs = map (\(s, b) -> f s Nothing (Just b)) bs
104+genericMerge f bsl@((s, b):bs) bsr@((s', b'):bs')
105+ | s < s' = (f s (Just b) Nothing) : genericMerge f bs bsr
106+ | s > s' = (f s' Nothing (Just b')) : genericMerge f bsl bs'
107+ | otherwise = (f s (Just b) (Just b')) : genericMerge f bs bs'
108+
109+-- |
110+-- Find the uncovered set between two binders:
111+-- the first binder is the case we are trying to cover, the second one is the matching binder
112+--
113+missingCasesSingle :: Environment -> ModuleName -> Binder -> Binder -> ([Binder], Maybe Bool)
114+missingCasesSingle _ _ _ NullBinder = ([], Just True)
115+missingCasesSingle _ _ _ (VarBinder _) = ([], Just True)
116+missingCasesSingle env mn (VarBinder _) b = missingCasesSingle env mn NullBinder b
117+missingCasesSingle env mn br (NamedBinder _ bl) = missingCasesSingle env mn br bl
118+missingCasesSingle env mn NullBinder cb@(ConstructorBinder con _) =
119+ (concatMap (\cp -> fst $ missingCasesSingle env mn cp cb) allPatterns, Just True)
120+ where
121+ allPatterns = map (\(p, t) -> ConstructorBinder (qualifyName p mn con) (initialize $ length t))
122+ $ getConstructors env mn con
123+missingCasesSingle env mn cb@(ConstructorBinder con bs) (ConstructorBinder con' bs')
124+ | con == con' = let (bs'', pr) = missingCasesMultiple env mn bs bs' in (map (ConstructorBinder con) bs'', pr)
125+ | otherwise = ([cb], Just False)
126+missingCasesSingle env mn NullBinder (ObjectBinder bs) =
127+ (map (ObjectBinder . zip (map fst bs)) allMisses, pr)
128+ where
129+ (allMisses, pr) = missingCasesMultiple env mn (initialize $ length bs) (map snd bs)
130+missingCasesSingle env mn (ObjectBinder bs) (ObjectBinder bs') =
131+ (map (ObjectBinder . zip sortedNames) allMisses, pr)
132+ where
133+ (allMisses, pr) = uncurry (missingCasesMultiple env mn) (unzip binders)
134+
135+ sortNames = sortBy (compare `on` fst)
136+
137+ (sbs, sbs') = (sortNames bs, sortNames bs')
138+
139+ compB :: a -> Maybe a -> Maybe a -> (a, a)
140+ compB e b b' = (fm b, fm b')
141+ where
142+ fm = fromMaybe e
143+
144+ compBS :: Eq a => b -> a -> Maybe b -> Maybe b -> (a, (b, b))
145+ compBS e s b b' = (s, compB e b b')
146+
147+ (sortedNames, binders) = unzip $ genericMerge (compBS NullBinder) sbs sbs'
148+missingCasesSingle _ _ NullBinder (BooleanBinder b) = ([BooleanBinder $ not b], Just True)
149+missingCasesSingle _ _ (BooleanBinder bl) (BooleanBinder br)
150+ | bl == br = ([], Just True)
151+ | otherwise = ([BooleanBinder bl], Just False)
152+missingCasesSingle env mn b (PositionedBinder _ _ cb) = missingCasesSingle env mn b cb
153+missingCasesSingle _ _ b _ = ([b], Nothing)
154+
155+-- |
156+-- Returns the uncovered set of binders
157+-- the first argument is the list of uncovered binders at step i
158+-- the second argument is the (i+1)th clause of a pattern matching definition
159+--
160+-- The idea of the algorithm is as follows:
161+-- it processes each binder of the two lists (say, `x` and `y`) one by one
162+-- at each step two cases arises:
163+-- - there are no missing cases between `x` and `y`: this is very straightforward, it continues with the remaining cases
164+-- but keeps the uncovered binder in its position.
165+-- - there are missing cases, let us call it the set `U`: on the one hand, we mix each new uncovered case in `U`
166+-- with the current tail of uncovered set. On the other hand, it continues with the remaining cases: here we
167+-- can use `x` (but it will generate overlapping cases), or `y`, which will generate non-overlapping cases.
168+--
169+-- As an example, consider:
170+--
171+-- data N = Z | S N
172+-- f Z Z = Z --> {[S _, _], [Z, S _]} which are the right non-overlapping cases (GHC uses this).
173+--
174+-- if we use `x` instead of `y` (in this case, `y` stands for `Z` and `x` for `_`) we obtain:
175+-- f Z Z = Z --> {[S _, _], [_, S _]} you can see that both cases overlaps each other.
176+--
177+-- Up to now, we've decided to use `x` just because we expect to generate uncovered cases which might be
178+-- redundant or not, but uncovered at least. If we use `y` instead, we'll need to have a redundancy checker
179+-- (which ought to be available soon), or increase the complexity of the algorithm.
180+--
181+missingCasesMultiple :: Environment -> ModuleName -> [Binder] -> [Binder] -> ([[Binder]], Maybe Bool)
182+missingCasesMultiple env mn = go
183+ where
184+ go [] [] = ([], pure True)
185+ go (x:xs) (y:ys) = (map (: xs) miss1 ++ map (x :) miss2, liftA2 (&&) pr1 pr2)
186+ where
187+ (miss1, pr1) = missingCasesSingle env mn x y
188+ (miss2, pr2) = go xs ys
189+ go _ _ = error "Argument lengths did not match in missingCasesMultiple."
190+
191+-- |
192+-- Guard handling
193+--
194+-- We say a guard is exhaustive iff it has an `otherwise` (or `true`) expression.
195+-- Example:
196+-- f x | x < 0 = 0
197+-- | otherwise = 1
198+-- is exhaustive, whereas `f x | x < 0` is not
199+--
200+-- The function below say whether or not a guard has an `otherwise` expression
201+-- It is considered that `otherwise` is defined in Prelude
202+--
203+isExhaustiveGuard :: Either [(Guard, Expr)] Expr -> Bool
204+isExhaustiveGuard (Left gs) = not . null $ filter (\(g, _) -> isOtherwise g) gs
205+ where
206+ isOtherwise :: Expr -> Bool
207+ isOtherwise (TypedValue _ (BooleanLiteral True) _) = True
208+ isOtherwise (TypedValue _ (Var (Qualified (Just (ModuleName [ProperName "Prelude"])) (Ident "otherwise"))) _) = True
209+ isOtherwise _ = False
210+isExhaustiveGuard (Right _) = True
211+
212+-- |
213+-- Returns the uncovered set of case alternatives
214+--
215+missingCases :: Environment -> ModuleName -> [Binder] -> CaseAlternative -> ([[Binder]], Maybe Bool)
216+missingCases env mn uncovered ca = missingCasesMultiple env mn uncovered (caseAlternativeBinders ca)
217+
218+missingAlternative :: Environment -> ModuleName -> CaseAlternative -> [Binder] -> ([[Binder]], Maybe Bool)
219+missingAlternative env mn ca uncovered
220+ | isExhaustiveGuard (caseAlternativeResult ca) = mcases
221+ | otherwise = ([uncovered], snd mcases)
222+ where
223+ mcases = missingCases env mn uncovered ca
224+
225+-- |
226+-- Main exhaustivity checking function
227+-- Starting with the set `uncovered = { _ }` (nothing covered, one `_` for each function argument),
228+-- it partitions that set with the new uncovered cases, until it consumes the whole set of clauses.
229+-- Then, returns the uncovered set of case alternatives.
230+--
231+checkExhaustive :: forall m. (MonadWriter MultipleErrors m) => Environment -> ModuleName -> [CaseAlternative] -> m ()
232+checkExhaustive env mn cas = makeResult . first nub $ foldl' step ([initial], (pure True, [])) cas
233+ where
234+ step :: ([[Binder]], (Maybe Bool, [[Binder]])) -> CaseAlternative -> ([[Binder]], (Maybe Bool, [[Binder]]))
235+ step (uncovered, (nec, redundant)) ca =
236+ let (missed, pr) = unzip (map (missingAlternative env mn ca) uncovered)
237+ cond = or <$> sequenceA pr
238+ in (concat missed, (liftA2 (&&) cond nec,
239+ if fromMaybe True cond then redundant else caseAlternativeBinders ca : redundant))
240+ where
241+ sequenceA = foldr (liftA2 (:)) (pure [])
242+
243+ initial :: [Binder]
244+ initial = initialize numArgs
245+ where
246+ numArgs = length . caseAlternativeBinders . head $ cas
247+
248+ makeResult :: ([[Binder]], (Maybe Bool, [[Binder]])) -> m ()
249+ makeResult (bss, (_, bss')) =
250+ do unless (null bss) tellExhaustive
251+ unless (null bss') tellRedundant
252+ where
253+ tellExhaustive = tell . errorMessage . uncurry NotExhaustivePattern . second null . splitAt 5 $ bss
254+ tellRedundant = tell . errorMessage . uncurry OverlappingPattern . second null . splitAt 5 $ bss'
255+
256+-- |
257+-- Exhaustivity checking over a list of declarations
258+--
259+checkExhaustiveDecls :: forall m. (Applicative m, MonadWriter MultipleErrors m) => Environment -> ModuleName -> [Declaration] -> m ()
260+checkExhaustiveDecls env mn ds =
261+ let (f, _, _) = everywhereOnValuesTopDownM return checkExpr return
262+
263+ f' :: Declaration -> m Declaration
264+ f' d@(BindingGroupDeclaration bs) = mapM_ (f' . convert) bs >> return d
265+ where
266+ convert :: (Ident, NameKind, Expr) -> Declaration
267+ convert (name, nk, e) = ValueDeclaration name nk [] (Right e)
268+ f' d@(ValueDeclaration name _ _ _) = censor (onErrorMessages (ErrorInValueDeclaration name)) $ f d
269+ f' (PositionedDeclaration pos com dec) = PositionedDeclaration pos com <$> censor (onErrorMessages (PositionedError pos)) (f' dec)
270+ -- Don't generate two warnings for desugared dictionaries.
271+ f' d@TypeInstanceDeclaration{} = return d
272+ f' d = f d
273+
274+ in mapM_ f' ds
275+ where
276+ checkExpr :: Expr -> m Expr
277+ checkExpr c@(Case _ cas) = checkExhaustive env mn cas >> return c
278+ checkExpr other = return other
279+
280+-- |
281+-- Exhaustivity checking over a single module
282+--
283+checkExhaustiveModule :: forall m. (Applicative m, MonadWriter MultipleErrors m) => Environment -> Module -> m ()
284+checkExhaustiveModule env (Module _ mn ds _) = censor (onErrorMessages (ErrorInModule mn)) $ checkExhaustiveDecls env mn ds
285+
src/Language/PureScript/Make.hsnew file+318
@@ -0,0 +1,318 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Make
4+-- Copyright : (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+{-# LANGUAGE DataKinds #-}
16+{-# LANGUAGE FlexibleContexts #-}
17+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
18+{-# LANGUAGE TupleSections #-}
19+{-# LANGUAGE RankNTypes #-}
20+{-# LANGUAGE RecordWildCards #-}
21+{-# LANGUAGE ScopedTypeVariables #-}
22+
23+module Language.PureScript.Make
24+ (
25+ -- * Make API
26+ RebuildPolicy(..)
27+ , ProgressMessage(..), renderProgressMessage
28+ , MakeActions(..)
29+ , Externs()
30+ , make
31+
32+ -- * Implementation of Make API using files on disk
33+ , Make(..)
34+ , runMake
35+ , buildMakeActions
36+ ) where
37+
38+import Control.Applicative
39+import Control.Arrow ((&&&))
40+import Control.Monad
41+import Control.Monad.Error.Class (MonadError(..))
42+import Control.Monad.Trans.Except
43+import Control.Monad.Reader
44+import Control.Monad.Writer
45+import Control.Monad.Supply
46+
47+import Data.Function (on)
48+import Data.List (sortBy, groupBy)
49+import Data.Maybe (fromMaybe)
50+import Data.Time.Clock
51+import Data.Foldable (for_)
52+import Data.Traversable (traverse)
53+import Data.Version (showVersion)
54+import qualified Data.Map as M
55+import qualified Data.Set as S
56+
57+import System.Directory
58+ (doesFileExist, getModificationTime, createDirectoryIfMissing)
59+import System.FilePath ((</>), takeDirectory)
60+import System.IO.Error (tryIOError)
61+
62+
63+import Language.PureScript.AST
64+import Language.PureScript.CodeGen.Externs (moduleToPs)
65+import Language.PureScript.Environment
66+import Language.PureScript.Errors
67+import Language.PureScript.Linter
68+import Language.PureScript.ModuleDependencies
69+import Language.PureScript.Names
70+import Language.PureScript.Options
71+import Language.PureScript.Parser
72+import Language.PureScript.Pretty
73+import Language.PureScript.Renamer
74+import Language.PureScript.Sugar
75+import Language.PureScript.TypeChecker
76+import qualified Language.PureScript.Constants as C
77+
78+import qualified Language.PureScript.CodeGen.JS as J
79+import qualified Language.PureScript.CoreFn as CF
80+import qualified Paths_purescript as Paths
81+
82+-- | Progress messages from the make process
83+data ProgressMessage
84+ = CompilingModule ModuleName
85+ deriving (Show, Eq, Ord)
86+
87+-- | Render a progress message
88+renderProgressMessage :: ProgressMessage -> String
89+renderProgressMessage (CompilingModule mn) = "Compiling " ++ runModuleName mn
90+
91+-- | Actions that require implementations when running in "make" mode.
92+--
93+-- This type exists to make two things abstract:
94+--
95+-- * The particular backend being used (Javascript, C++11, etc.)
96+--
97+-- * The details of how files are read/written etc.
98+--
99+data MakeActions m = MakeActions {
100+ -- |
101+ -- Get the timestamp for the input file(s) for a module. If there are multiple
102+ -- files (.purs and foreign files, for example) the timestamp should be for
103+ -- the most recently modified file.
104+ --
105+ getInputTimestamp :: ModuleName -> m (Either RebuildPolicy (Maybe UTCTime))
106+ -- |
107+ -- Get the timestamp for the output files for a module. This should be the
108+ -- timestamp for the oldest modified file, or Nothing if any of the required
109+ -- output files are missing.
110+ --
111+ , getOutputTimestamp :: ModuleName -> m (Maybe UTCTime)
112+ -- |
113+ -- Read the externs file for a module as a string and also return the actual
114+ -- path for the file.
115+ , readExterns :: ModuleName -> m (FilePath, String)
116+ -- |
117+ -- Run the code generator for the module and write any required output files.
118+ --
119+ , codegen :: CF.Module CF.Ann -> Environment -> Externs -> SupplyT m ()
120+ -- |
121+ -- Respond to a progress update.
122+ --
123+ , progress :: ProgressMessage -> m ()
124+ }
125+
126+-- |
127+-- Generated code for an externs file.
128+--
129+type Externs = String
130+
131+-- |
132+-- Determines when to rebuild a module
133+--
134+data RebuildPolicy
135+ -- | Never rebuild this module
136+ = RebuildNever
137+ -- | Always rebuild this module
138+ | RebuildAlways deriving (Show, Eq, Ord)
139+
140+-- |
141+-- Compiles in "make" mode, compiling each module separately to a js files and an externs file
142+--
143+-- If timestamps have not changed, the externs file can be used to provide the module's types without
144+-- having to typecheck the module again.
145+--
146+make :: forall m. (Functor m, Applicative m, Monad m, MonadReader Options m, MonadError MultipleErrors m, MonadWriter MultipleErrors m)
147+ => MakeActions m
148+ -> [Module]
149+ -> m Environment
150+make MakeActions{..} ms = do
151+ (sorted, graph) <- sortModules $ map importPrim ms
152+ toRebuild <- foldM (\s (Module _ moduleName' _ _) -> do
153+ inputTimestamp <- getInputTimestamp moduleName'
154+ outputTimestamp <- getOutputTimestamp moduleName'
155+ return $ case (inputTimestamp, outputTimestamp) of
156+ (Right (Just t1), Just t2) | t1 < t2 -> s
157+ (Left RebuildNever, Just _) -> s
158+ _ -> S.insert moduleName' s) S.empty sorted
159+
160+ marked <- rebuildIfNecessary (reverseDependencies graph) toRebuild sorted
161+ for_ marked $ \(willRebuild, m) -> when willRebuild (lint m)
162+ (desugared, nextVar) <- runSupplyT 0 $ zip (map fst marked) <$> desugar (map snd marked)
163+ evalSupplyT nextVar $ go initEnvironment desugared
164+ where
165+
166+ go :: Environment -> [(Bool, Module)] -> SupplyT m Environment
167+ go env [] = return env
168+ go env ((False, m) : ms') = do
169+ (_, env') <- lift . runCheck' env $ typeCheckModule Nothing m
170+ go env' ms'
171+ go env ((True, m@(Module coms moduleName' _ exps)) : ms') = do
172+ lift . progress $ CompilingModule moduleName'
173+ (checked@(Module _ _ elaborated _), env') <- lift . runCheck' env $ typeCheckModule Nothing m
174+ checkExhaustiveModule env' checked
175+ regrouped <- createBindingGroups moduleName' . collapseBindingGroups $ elaborated
176+ let mod' = Module coms moduleName' regrouped exps
177+ corefn = CF.moduleToCoreFn env' mod'
178+ [renamed] = renameInModules [corefn]
179+ exts = moduleToPs mod' env'
180+ codegen renamed env' exts
181+ go env' ms'
182+
183+ rebuildIfNecessary :: M.Map ModuleName [ModuleName] -> S.Set ModuleName -> [Module] -> m [(Bool, Module)]
184+ rebuildIfNecessary _ _ [] = return []
185+ rebuildIfNecessary graph toRebuild (m@(Module _ moduleName' _ _) : ms') | moduleName' `S.member` toRebuild = do
186+ let deps = fromMaybe [] $ moduleName' `M.lookup` graph
187+ toRebuild' = toRebuild `S.union` S.fromList deps
188+ (:) (True, m) <$> rebuildIfNecessary graph toRebuild' ms'
189+ rebuildIfNecessary graph toRebuild (Module _ moduleName' _ _ : ms') = do
190+ (path, externs) <- readExterns moduleName'
191+ externsModules <- fmap (map snd) . alterErrors $ parseModulesFromFiles id [(path, externs)]
192+ case externsModules of
193+ [m'@(Module _ moduleName'' _ _)] | moduleName'' == moduleName' -> (:) (False, m') <$> rebuildIfNecessary graph toRebuild ms'
194+ _ -> throwError . errorMessage . InvalidExternsFile $ path
195+ where
196+ alterErrors = flip catchError $ \(MultipleErrors errs) ->
197+ throwError . MultipleErrors $ flip map errs $ \e -> case e of
198+ SimpleErrorWrapper (ErrorParsingModule err) -> SimpleErrorWrapper (ErrorParsingExterns err)
199+ _ -> e
200+
201+reverseDependencies :: ModuleGraph -> M.Map ModuleName [ModuleName]
202+reverseDependencies g = combine [ (dep, mn) | (mn, deps) <- g, dep <- deps ]
203+ where
204+ combine :: (Ord a) => [(a, b)] -> M.Map a [b]
205+ combine = M.fromList . map ((fst . head) &&& map snd) . groupBy ((==) `on` fst) . sortBy (compare `on` fst)
206+
207+-- |
208+-- Add an import declaration for a module if it does not already explicitly import it.
209+--
210+addDefaultImport :: ModuleName -> Module -> Module
211+addDefaultImport toImport m@(Module coms mn decls exps) =
212+ if isExistingImport `any` decls || mn == toImport then m
213+ else Module coms mn (ImportDeclaration toImport Implicit Nothing : decls) exps
214+ where
215+ isExistingImport (ImportDeclaration mn' _ _) | mn' == toImport = True
216+ isExistingImport (PositionedDeclaration _ _ d) = isExistingImport d
217+ isExistingImport _ = False
218+
219+importPrim :: Module -> Module
220+importPrim = addDefaultImport (ModuleName [ProperName C.prim])
221+
222+-- |
223+-- A monad for running make actions
224+--
225+newtype Make a = Make { unMake :: ReaderT Options (WriterT MultipleErrors (ExceptT MultipleErrors IO)) a }
226+ deriving (Functor, Applicative, Monad, MonadIO, MonadError MultipleErrors, MonadWriter MultipleErrors, MonadReader Options)
227+
228+-- |
229+-- Execute a 'Make' monad, returning either errors, or the result of the compile plus any warnings.
230+--
231+runMake :: Options -> Make a -> IO (Either MultipleErrors (a, MultipleErrors))
232+runMake opts = runExceptT . runWriterT . flip runReaderT opts . unMake
233+
234+makeIO :: (IOError -> ErrorMessage) -> IO a -> Make a
235+makeIO f io = do
236+ e <- liftIO $ tryIOError io
237+ either (throwError . singleError . f) return e
238+
239+-- Traverse (Either e) instance (base 4.7)
240+traverseEither :: Applicative f => (a -> f b) -> Either e a -> f (Either e b)
241+traverseEither _ (Left x) = pure (Left x)
242+traverseEither f (Right y) = Right <$> f y
243+
244+-- |
245+-- A set of make actions that read and write modules from the given directory.
246+--
247+buildMakeActions :: FilePath -- ^ the output directory
248+ -> M.Map ModuleName (Either RebuildPolicy String) -- ^ a map between module names and paths to the file containing the PureScript module
249+ -> M.Map ModuleName (FilePath, ForeignJS) -- ^ a map between module name and the file containing the foreign javascript for the module
250+ -> Bool -- ^ Generate a prefix comment?
251+ -> MakeActions Make
252+buildMakeActions outputDir filePathMap foreigns usePrefix =
253+ MakeActions getInputTimestamp getOutputTimestamp readExterns codegen progress
254+ where
255+
256+ getInputTimestamp :: ModuleName -> Make (Either RebuildPolicy (Maybe UTCTime))
257+ getInputTimestamp mn = do
258+ let path = fromMaybe (error "Module has no filename in 'make'") $ M.lookup mn filePathMap
259+ e1 <- traverseEither getTimestamp path
260+ fPath <- maybe (return Nothing) (getTimestamp . fst) $ M.lookup mn foreigns
261+ return $ fmap (max fPath) e1
262+
263+ getOutputTimestamp :: ModuleName -> Make (Maybe UTCTime)
264+ getOutputTimestamp mn = do
265+ let filePath = runModuleName mn
266+ jsFile = outputDir </> filePath </> "index.js"
267+ externsFile = outputDir </> filePath </> "externs.purs"
268+ min <$> getTimestamp jsFile <*> getTimestamp externsFile
269+
270+ readExterns :: ModuleName -> Make (FilePath, String)
271+ readExterns mn = do
272+ let path = outputDir </> runModuleName mn </> "externs.purs"
273+ (path, ) <$> readTextFile path
274+
275+ codegen :: CF.Module CF.Ann -> Environment -> Externs -> SupplyT Make ()
276+ codegen m _ exts = do
277+ let mn = CF.moduleName m
278+ foreignInclude <- case mn `M.lookup` foreigns of
279+ Just (path, _)
280+ | not $ requiresForeign m -> do
281+ tell $ errorMessage $ UnnecessaryFFIModule mn path
282+ return Nothing
283+ | otherwise -> return $ Just $ J.JSApp (J.JSVar "require") [J.JSStringLiteral "./foreign"]
284+ Nothing | requiresForeign m -> throwError . errorMessage $ MissingFFIModule mn
285+ | otherwise -> return Nothing
286+ pjs <- prettyPrintJS <$> J.moduleToJs m foreignInclude
287+ let filePath = runModuleName mn
288+ jsFile = outputDir </> filePath </> "index.js"
289+ externsFile = outputDir </> filePath </> "externs.purs"
290+ foreignFile = outputDir </> filePath </> "foreign.js"
291+ prefix = ["Generated by psc version " ++ showVersion Paths.version | usePrefix]
292+ js = unlines $ map ("// " ++) prefix ++ [pjs]
293+ lift $ do
294+ writeTextFile jsFile js
295+ maybe (return ()) (writeTextFile foreignFile . snd) $ mn `M.lookup` foreigns
296+ writeTextFile externsFile exts
297+
298+ requiresForeign :: CF.Module a -> Bool
299+ requiresForeign = not . null . CF.moduleForeign
300+
301+ getTimestamp :: FilePath -> Make (Maybe UTCTime)
302+ getTimestamp path = makeIO (const (SimpleErrorWrapper $ CannotGetFileInfo path)) $ do
303+ exists <- doesFileExist path
304+ traverse (const $ getModificationTime path) $ guard exists
305+
306+ readTextFile :: FilePath -> Make String
307+ readTextFile path = makeIO (const (SimpleErrorWrapper $ CannotReadFile path)) $ readFile path
308+
309+ writeTextFile :: FilePath -> String -> Make ()
310+ writeTextFile path text = makeIO (const (SimpleErrorWrapper $ CannotWriteFile path)) $ do
311+ mkdirp path
312+ writeFile path text
313+ where
314+ mkdirp :: FilePath -> IO ()
315+ mkdirp = createDirectoryIfMissing True . takeDirectory
316+
317+ progress :: ProgressMessage -> Make ()
318+ progress = liftIO . putStrLn . renderProgressMessage
src/Language/PureScript/Names.hs+18−1
@@ -13,12 +13,15 @@
1313--
1414-----------------------------------------------------------------------------
1515
16−{-# LANGUAGE DeriveDataTypeable, DeriveFunctor #-}
16+{-# LANGUAGE DeriveDataTypeable, DeriveFunctor, GADTs #-}
1717
1818module Language.PureScript.Names where
1919
2020import Data.List
2121import Data.Data
22+import Data.List.Split (splitOn)
23+import qualified Data.Aeson as A
24+import qualified Data.Text as T
2225
2326-- |
2427-- Names for value identifiers
@@ -77,6 +80,20 @@ instance (Show a) => Show (Qualified a) where
7780 show (Qualified Nothing a) = show a
7881 show (Qualified (Just name) a) = show name ++ "." ++ show a
7982
83+instance (a ~ ProperName) => A.ToJSON (Qualified a) where
84+ toJSON = A.toJSON . show
85+
86+instance (a ~ ProperName) => A.FromJSON (Qualified a) where
87+ parseJSON =
88+ A.withText "Qualified ProperName" $ \str ->
89+ return $ case reverse (splitOn "." (T.unpack str)) of
90+ [name] -> Qualified Nothing (ProperName name)
91+ (name:rest) -> Qualified (Just (reconstructModuleName rest)) (ProperName name)
92+ _ -> Qualified Nothing (ProperName "")
93+ where
94+ reconstructModuleName = moduleNameFromString . intercalate "." . reverse
95+
96+
8097-- |
8198-- Provide a default module name, if a name is unqualified
8299--
src/Language/PureScript/Options.hs+5−44
@@ -13,76 +13,37 @@
1313--
1414-----------------------------------------------------------------------------
1515
16−{-# LANGUAGE GADTs, DataKinds, StandaloneDeriving #-}
17−
1816module Language.PureScript.Options where
1917
20−-- |
21−-- Indicates the mode of the compiler. Lifted using DataKinds to refine the Options type.
22−--
23−data Mode = Compile | Make
24−
25−-- |
26−-- Per-mode options
27−--
28−data ModeOptions mode where
29− CompileOptions :: String -> [String] -> [String] -> ModeOptions Compile
30− MakeOptions :: ModeOptions Make
31−
32−browserNamespace :: ModeOptions Compile -> String
33−browserNamespace (CompileOptions ns _ _) = ns
34−
35−entryPointModules :: ModeOptions Compile -> [String]
36−entryPointModules (CompileOptions _ ms _) = ms
37−
38−codeGenModules :: ModeOptions Compile -> [String]
39−codeGenModules (CompileOptions _ _ ms) = ms
40−
41−deriving instance Show (ModeOptions mode)
42−
4318-- |
4419-- The data type of compiler options
4520--
46−data Options mode = Options {
21+data Options = Options {
4722 -- |
4823 -- Disable tail-call elimination
49− --
5024 optionsNoTco :: Bool
5125 -- |
5226 -- Disable inlining of calls to return and bind for the Eff monad
53− --
5427 , optionsNoMagicDo :: Bool
5528 -- |
5629 -- When specified, checks the type of `main` in the module, and generate a call to run main
5730 -- after the module definitions.
58− --
5931 , optionsMain :: Maybe String
6032 -- |
6133 -- Skip all optimizations
62− --
6334 , optionsNoOptimizations :: Bool
6435 -- |
6536 -- Verbose error message
66− --
6737 , optionsVerboseErrors :: Bool
6838 -- |
6939 -- Remove the comments from the generated js
7040 , optionsNoComments :: Bool
7141 -- |
72− -- Specify the namespace that PureScript modules will be exported to when running in the
73− -- browser.
74− --
75− , optionsAdditional :: ModeOptions mode
42+ -- The path to prepend to require statements
43+ , optionsRequirePath :: Maybe FilePath
7644 } deriving Show
7745
78−-- |
79−-- Default compiler options
80−--
81−defaultCompileOptions :: Options Compile
82−defaultCompileOptions = Options False False Nothing False False False (CompileOptions "PS" [] [])
83−
8446-- |
8547-- Default make options
86−--
87−defaultMakeOptions :: Options Make
88−defaultMakeOptions = Options False False Nothing False False False MakeOptions
48+defaultOptions :: Options
49+defaultOptions = Options False False Nothing False False False Nothing
src/Language/PureScript/Parser/Declarations.hs+9−1
@@ -186,11 +186,19 @@ parseImportDeclaration' = do
186186
187187
188188parseDeclarationRef :: TokenParser DeclarationRef
189−parseDeclarationRef = withSourceSpan PositionedDeclarationRef $
189+parseDeclarationRef =
190+ parseModuleRef <|> (
191+ withSourceSpan PositionedDeclarationRef $
190192 ValueRef <$> parseIdent
191193 <|> do name <- properName
192194 dctors <- P.optionMaybe $ parens (symbol' ".." *> pure Nothing <|> Just <$> commaSep properName)
193195 return $ maybe (TypeClassRef name) (TypeRef name) dctors
196+ )
197+ where
198+ parseModuleRef :: TokenParser DeclarationRef
199+ parseModuleRef = do
200+ name <- indented *> reserved "module" *> moduleName
201+ return $ ModuleRef name
194202
195203parseTypeClassDeclaration :: TokenParser Declaration
196204parseTypeClassDeclaration = do
src/Language/PureScript/Pretty/JS.hs+1
@@ -163,6 +163,7 @@ string s = '"' : concatMap encodeChar s ++ "\""
163163 encodeChar '\\' = "\\\\"
164164 encodeChar c | fromEnum c > 0xFFF = "\\u" ++ showHex (fromEnum c) ""
165165 encodeChar c | fromEnum c > 0xFF = "\\u0" ++ showHex (fromEnum c) ""
166+ encodeChar c | fromEnum c > 0x7E || fromEnum c < 0x20 = "\\x" ++ showHex (fromEnum c) ""
166167 encodeChar c = [c]
167168
168169conditional :: Pattern PrinterState JS ((JS, JS), JS)
src/Language/PureScript/Pretty/Values.hs+40−64
@@ -15,7 +15,8 @@
1515
1616module Language.PureScript.Pretty.Values (
1717 prettyPrintValue,
18− prettyPrintBinder
18+ prettyPrintBinder,
19+ prettyPrintBinderAtom
1920) where
2021
2122import Data.Maybe (fromMaybe)
@@ -40,11 +41,7 @@ literals = mkPattern' match
4041 match (CharLiteral c) = return $ show c
4142 match (BooleanLiteral True) = return "true"
4243 match (BooleanLiteral False) = return "false"
43− match (ArrayLiteral xs) = concat <$> sequence
44− [ return "[ "
45− , withIndent $ prettyPrintMany prettyPrintValue' xs
46− , return " ]"
47− ]
44+ match (ArrayLiteral xs) = return $ "[" ++ intercalate ", " (map prettyPrintValue xs) ++ "]"
4845 match (ObjectLiteral ps) = prettyPrintObject' $ second Just `map` ps
4946 match (ObjectConstructor ps) = prettyPrintObject' ps
5047 match (ObjectGetter prop) = return $ "(." ++ prop ++ ")"
@@ -71,7 +68,7 @@ literals = mkPattern' match
7168 ]
7269 match (Var ident) = return $ show ident
7370 match (Do els) = concat <$> sequence
74− [ return "do "
71+ [ return "do\n"
7572 , withIndent $ prettyPrintMany prettyPrintDoNotationElement els
7673 , currentIndent
7774 ]
@@ -95,11 +92,14 @@ prettyPrintDeclaration _ = error "Invalid argument to prettyPrintDeclaration"
9592prettyPrintCaseAlternative :: CaseAlternative -> StateT PrinterState Maybe String
9693prettyPrintCaseAlternative (CaseAlternative binders result) =
9794 concat <$> sequence
98− [ intercalate ", " <$> forM binders prettyPrintBinder'
95+ [ return (unwords (map prettyPrintBinderAtom binders))
9996 , prettyPrintResult result
10097 ]
10198 where
102− prettyPrintResult (Left gs) = concat <$> mapM prettyPrintGuardedValue gs
99+ prettyPrintResult (Left gs) = concat <$> sequence
100+ [ return "\n"
101+ , withIndent $ prettyPrintMany prettyPrintGuardedValue gs
102+ ]
103103 prettyPrintResult (Right v) = (" -> " ++) <$> prettyPrintValue' v
104104
105105 prettyPrintGuardedValue (grd, val) =
@@ -108,7 +108,6 @@ prettyPrintCaseAlternative (CaseAlternative binders result) =
108108 , prettyPrintValue' grd
109109 , return " -> "
110110 , prettyPrintValue' val
111− , return "\n"
112111 ]
113112
114113prettyPrintDoNotationElement :: DoNotationElement -> StateT PrinterState Maybe String
@@ -116,7 +115,7 @@ prettyPrintDoNotationElement (DoNotationValue val) =
116115 prettyPrintValue' val
117116prettyPrintDoNotationElement (DoNotationBind binder val) =
118117 concat <$> sequence
119− [ prettyPrintBinder' binder
118+ [ return (prettyPrintBinder binder)
120119 , return " <- "
121120 , prettyPrintValue' val
122121 ]
@@ -129,13 +128,10 @@ prettyPrintDoNotationElement (PositionedDoNotationElement _ _ el) = prettyPrintD
129128
130129prettyPrintObject' :: [(String, Maybe Expr)] -> StateT PrinterState Maybe String
131130prettyPrintObject' [] = return "{}"
132−prettyPrintObject' ps = concat <$> sequence
133− [ return "{\n"
134− , withIndent $ prettyPrintMany prettyPrintObjectProperty ps
135− , return "\n"
136− , currentIndent
137− , return "}"
138− ]
131+prettyPrintObject' ps = return $ "{ " ++ intercalate ", " (map prettyPrintObjectProperty ps) ++ "}"
132+ where
133+ prettyPrintObjectProperty :: (String, Maybe Expr) -> String
134+ prettyPrintObjectProperty (key, value) = prettyPrintObjectKey key ++ ": " ++ maybe "_" prettyPrintValue value
139135
140136ifThenElse :: Pattern PrinterState Expr ((Expr, Expr), Expr)
141137ifThenElse = mkPattern match
@@ -188,55 +184,35 @@ prettyPrintValue' = runKleisli $ runPattern matchValue
188184 , [ Wrap ifThenElse $ \(th, el) cond -> "if " ++ cond ++ " then " ++ prettyPrintValue th ++ " else " ++ prettyPrintValue el ]
189185 ]
190186
191−prettyPrintBinderAtom :: Pattern PrinterState Binder String
192−prettyPrintBinderAtom = mkPattern' match
187+prettyPrintBinderAtom :: Binder -> String
188+prettyPrintBinderAtom NullBinder = "_"
189+prettyPrintBinderAtom (StringBinder str) = show str
190+prettyPrintBinderAtom (CharBinder c) = show c
191+prettyPrintBinderAtom (NumberBinder num) = either show show num
192+prettyPrintBinderAtom (BooleanBinder True) = "true"
193+prettyPrintBinderAtom (BooleanBinder False) = "false"
194+prettyPrintBinderAtom (VarBinder ident) = show ident
195+prettyPrintBinderAtom (ConstructorBinder ctor []) = show ctor
196+prettyPrintBinderAtom (ObjectBinder bs) =
197+ "{ "
198+ ++ intercalate ", " (map prettyPrintObjectPropertyBinder bs)
199+ ++ " }"
193200 where
194− match :: Binder -> StateT PrinterState Maybe String
195− match NullBinder = return "_"
196− match (StringBinder str) = return $ show str
197− match (CharBinder c) = return $ show c
198− match (NumberBinder num) = return $ either show show num
199− match (BooleanBinder True) = return "true"
200− match (BooleanBinder False) = return "false"
201− match (VarBinder ident) = return $ show ident
202− match (ConstructorBinder ctor args) = concat <$> sequence
203− [ return $ show ctor ++ " "
204− , unwords <$> forM args match
205− ]
206− match (ObjectBinder bs) = concat <$> sequence
207− [ return "{\n"
208− , withIndent $ prettyPrintMany prettyPrintObjectPropertyBinder bs
209− , currentIndent
210− , return "}"
211− ]
212− match (ArrayBinder bs) = concat <$> sequence
213− [ return "["
214− , unwords <$> mapM prettyPrintBinder' bs
215− , return "]"
216− ]
217− match (NamedBinder ident binder) = ((show ident ++ "@") ++) <$> prettyPrintBinder' binder
218− match (PositionedBinder _ _ binder) = prettyPrintBinder' binder
201+ prettyPrintObjectPropertyBinder :: (String, Binder) -> String
202+ prettyPrintObjectPropertyBinder (key, binder) = prettyPrintObjectKey key ++ ": " ++ prettyPrintBinder binder
203+prettyPrintBinderAtom (ArrayBinder bs) =
204+ "[ "
205+ ++ intercalate ", " (map prettyPrintBinder bs)
206+ ++ " ]"
207+prettyPrintBinderAtom (NamedBinder ident binder) = show ident ++ "@" ++ prettyPrintBinder binder
208+prettyPrintBinderAtom (PositionedBinder _ _ binder) = prettyPrintBinderAtom binder
209+prettyPrintBinderAtom b = parens (prettyPrintBinder b)
219210
220211-- |
221212-- Generate a pretty-printed string representing a Binder
222213--
223214prettyPrintBinder :: Binder -> String
224−prettyPrintBinder = fromMaybe (error "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyPrintBinder'
225−
226−prettyPrintBinder' :: Binder -> StateT PrinterState Maybe String
227−prettyPrintBinder' = runKleisli $ runPattern matchBinder
228− where
229− matchBinder :: Pattern PrinterState Binder String
230− matchBinder = prettyPrintBinderAtom <+> fmap parens matchBinder
231−
232−prettyPrintObjectPropertyBinder :: (String, Binder) -> StateT PrinterState Maybe String
233−prettyPrintObjectPropertyBinder (key, binder) = concat <$> sequence
234− [ return $ prettyPrintObjectKey key ++ ": "
235− , prettyPrintBinder' binder
236− ]
237−
238−prettyPrintObjectProperty :: (String, Maybe Expr) -> StateT PrinterState Maybe String
239−prettyPrintObjectProperty (key, value) = concat <$> sequence
240− [ return $ prettyPrintObjectKey key ++ ": "
241− , maybe (pure "_") prettyPrintValue' value
242− ]
215+prettyPrintBinder (ConstructorBinder ctor []) = show ctor
216+prettyPrintBinder (ConstructorBinder ctor args) = show ctor ++ " " ++ unwords (map prettyPrintBinderAtom args)
217+prettyPrintBinder (PositionedBinder _ _ binder) = prettyPrintBinder binder
218+prettyPrintBinder b = prettyPrintBinderAtom b
src/Language/PureScript/Publish.hsnew file+361
@@ -0,0 +1,361 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE RecordWildCards #-}
3+{-# LANGUAGE TupleSections #-}
4+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5+
6+module Language.PureScript.Publish
7+ ( preparePackage
8+ , preparePackage'
9+ , PrepareM()
10+ , runPrepareM
11+ , PublishOptions(..)
12+ , defaultPublishOptions
13+ , getGitWorkingTreeStatus
14+ , requireCleanWorkingTree
15+ , getVersionFromGitTag
16+ , getBowerInfo
17+ , getModulesAndBookmarks
18+ , getResolvedDependencies
19+ ) where
20+
21+import Prelude hiding (userError)
22+
23+import Data.Maybe
24+import Data.Char (isSpace)
25+import Data.String (fromString)
26+import Data.List (stripPrefix, isSuffixOf, (\\), nubBy)
27+import Data.List.Split (splitOn)
28+import Data.List.NonEmpty (NonEmpty(..))
29+import Data.Version
30+import Data.Function (on)
31+import Safe (headMay)
32+import Data.Aeson.BetterErrors
33+import qualified Data.Text as T
34+
35+import Control.Applicative
36+import Control.Category ((>>>))
37+import Control.Arrow ((***))
38+import Control.Exception (catch, try)
39+import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
40+import Control.Monad.Trans.Except
41+import Control.Monad.Error.Class (MonadError(..))
42+import Control.Monad.Writer
43+
44+import System.Directory (doesFileExist, findExecutable)
45+import System.Process (readProcess)
46+import System.Exit (exitFailure)
47+import System.FilePath (pathSeparator)
48+import qualified System.FilePath.Glob as Glob
49+import qualified System.Info
50+
51+import Web.Bower.PackageMeta (PackageMeta(..), BowerError(..), PackageName,
52+ runPackageName, parsePackageName, Repository(..))
53+import qualified Web.Bower.PackageMeta as Bower
54+
55+import qualified Language.PureScript as P (version)
56+import qualified Language.PureScript.Docs as D
57+import Language.PureScript.Publish.Utils
58+import Language.PureScript.Publish.ErrorsWarnings
59+
60+data PublishOptions = PublishOptions
61+ { -- | How to obtain the version tag and version that the data being
62+ -- generated will refer to.
63+ publishGetVersion :: PrepareM (String, Version)
64+ }
65+
66+defaultPublishOptions :: PublishOptions
67+defaultPublishOptions = PublishOptions
68+ { publishGetVersion = getVersionFromGitTag
69+ }
70+
71+-- | Attempt to retrieve package metadata from the current directory.
72+-- Calls exitFailure if no package metadata could be retrieved.
73+preparePackage :: PublishOptions -> IO D.UploadedPackage
74+preparePackage opts =
75+ runPrepareM (preparePackage' opts)
76+ >>= either (\e -> printError e >> exitFailure)
77+ handleWarnings
78+ where
79+ handleWarnings (result, warns) = do
80+ printWarnings warns
81+ return result
82+
83+newtype PrepareM a =
84+ PrepareM { unPrepareM :: WriterT [PackageWarning] (ExceptT PackageError IO) a }
85+ deriving (Functor, Applicative, Monad,
86+ MonadWriter [PackageWarning],
87+ MonadError PackageError)
88+
89+-- This MonadIO instance ensures that IO errors don't crash the program.
90+instance MonadIO PrepareM where
91+ liftIO act =
92+ lift' (try act) >>= either (otherError . IOExceptionThrown) return
93+ where
94+ lift' :: IO a -> PrepareM a
95+ lift' = PrepareM . lift . lift
96+
97+runPrepareM :: PrepareM a -> IO (Either PackageError (a, [PackageWarning]))
98+runPrepareM = runExceptT . runWriterT . unPrepareM
99+
100+warn :: PackageWarning -> PrepareM ()
101+warn w = tell [w]
102+
103+userError :: UserError -> PrepareM a
104+userError = throwError . UserError
105+
106+internalError :: InternalError -> PrepareM a
107+internalError = throwError . InternalError
108+
109+otherError :: OtherError -> PrepareM a
110+otherError = throwError . OtherError
111+
112+catchLeft :: Applicative f => Either a b -> (a -> f b) -> f b
113+catchLeft a f = either f pure a
114+
115+preparePackage' :: PublishOptions -> PrepareM D.UploadedPackage
116+preparePackage' opts = do
117+ exists <- liftIO (doesFileExist "bower.json")
118+ unless exists (userError BowerJSONNotFound)
119+
120+ requireCleanWorkingTree
121+
122+ pkgMeta <- liftIO (Bower.decodeFile "bower.json")
123+ >>= flip catchLeft (userError . CouldntParseBowerJSON)
124+ (pkgVersionTag, pkgVersion) <- publishGetVersion opts
125+ pkgGithub <- getBowerInfo pkgMeta
126+ (pkgBookmarks, pkgModules) <- getModulesAndBookmarks
127+
128+ let declaredDeps = map fst (bowerDependencies pkgMeta ++
129+ bowerDevDependencies pkgMeta)
130+ pkgResolvedDependencies <- getResolvedDependencies declaredDeps
131+
132+ let pkgUploader = D.NotYetKnown
133+ let pkgCompilerVersion = P.version
134+
135+ return D.Package{..}
136+
137+getModulesAndBookmarks :: PrepareM ([D.Bookmark], [D.Module])
138+getModulesAndBookmarks = do
139+ (inputFiles, depsFiles) <- liftIO getInputAndDepsFiles
140+ liftIO (D.parseAndDesugar inputFiles depsFiles renderModules)
141+ >>= either (userError . ParseAndDesugarError) return
142+ where
143+ renderModules bookmarks modules =
144+ return (bookmarks, map D.convertModule modules)
145+
146+data TreeStatus = Clean | Dirty deriving (Show, Eq, Ord, Enum)
147+
148+getGitWorkingTreeStatus :: PrepareM TreeStatus
149+getGitWorkingTreeStatus = do
150+ out <- readProcess' "git" ["status", "--porcelain"] ""
151+ return $
152+ if null . filter (not . null) . lines $ out
153+ then Clean
154+ else Dirty
155+
156+requireCleanWorkingTree :: PrepareM ()
157+requireCleanWorkingTree = do
158+ status <- getGitWorkingTreeStatus
159+ unless (status == Clean) $
160+ userError DirtyWorkingTree
161+
162+getVersionFromGitTag :: PrepareM (String, Version)
163+getVersionFromGitTag = do
164+ out <- readProcess' "git" ["tag", "--list", "--points-at", "HEAD"] ""
165+ let vs = map trimWhitespace (lines out)
166+ case mapMaybe parseMay vs of
167+ [] -> userError TagMustBeCheckedOut
168+ [x] -> return x
169+ xs -> userError (AmbiguousVersions (map snd xs))
170+ where
171+ trimWhitespace =
172+ dropWhile isSpace >>> reverse >>> dropWhile isSpace >>> reverse
173+ parseMay str =
174+ (str,) <$> D.parseVersion' (dropPrefix "v" str)
175+ dropPrefix prefix str =
176+ fromMaybe str (stripPrefix prefix str)
177+
178+getBowerInfo :: PackageMeta -> PrepareM (D.GithubUser, D.GithubRepo)
179+getBowerInfo = either (userError . BadRepositoryField) return . tryExtract
180+ where
181+ tryExtract pkgMeta =
182+ case bowerRepository pkgMeta of
183+ Nothing -> Left RepositoryFieldMissing
184+ Just Repository{..} -> do
185+ unless (repositoryType == "git")
186+ (Left (BadRepositoryType repositoryType))
187+ maybe (Left NotOnGithub) Right (extractGithub repositoryUrl)
188+
189+extractGithub :: String -> Maybe (D.GithubUser, D.GithubRepo)
190+extractGithub =
191+ stripPrefix "git://github.com/"
192+ >>> fmap (splitOn "/")
193+ >=> takeTwo
194+ >>> fmap (D.GithubUser *** (D.GithubRepo . dropDotGit))
195+
196+ where
197+ takeTwo :: [a] -> Maybe (a, a)
198+ takeTwo [x, y] = Just (x, y)
199+ takeTwo _ = Nothing
200+
201+ dropDotGit :: String -> String
202+ dropDotGit str
203+ | ".git" `isSuffixOf` str = take (length str - 4) str
204+ | otherwise = str
205+
206+readProcess' :: String -> [String] -> String -> PrepareM String
207+readProcess' prog args stdin = do
208+ out <- liftIO (catch (Right <$> readProcess prog args stdin)
209+ (return . Left))
210+ either (otherError . ProcessFailed prog args) return out
211+
212+data DependencyStatus
213+ = Missing
214+ -- ^ Listed in bower.json, but not installed.
215+ | NoResolution
216+ -- ^ In the output of `bower list --json --offline`, there was no
217+ -- _resolution key. This can be caused by adding the dependency using
218+ -- `bower link`, or simply copying it into bower_components instead of
219+ -- installing it normally.
220+ | ResolvedOther String
221+ -- ^ Resolved, but to something other than a version. The String argument
222+ -- is the resolution type. The values it can take that I'm aware of are
223+ -- "commit" and "branch".
224+ | ResolvedVersion String
225+ -- ^ Resolved to a version. The String argument is the resolution tag (eg,
226+ -- "v0.1.0").
227+ deriving (Show, Eq)
228+
229+-- Go through all bower dependencies which contain purescript code, and
230+-- extract their versions.
231+--
232+-- In the case where a bower dependency is taken from a particular version,
233+-- that's easy; take that version. In any other case (eg, a branch, or a commit
234+-- sha) we print a warning that documentation links will not work, and avoid
235+-- linking to documentation for any types from that package.
236+--
237+-- The rationale for this is: people will prefer to use a released version
238+-- where possible. If they are not using a released version, then this is
239+-- probably for a reason. However, docs are only ever available for released
240+-- versions. Therefore there will probably be no version of the docs which is
241+-- appropriate to link to, and we should omit links.
242+getResolvedDependencies :: [PackageName] -> PrepareM [(PackageName, Version)]
243+getResolvedDependencies declaredDeps = do
244+ bower <- findBowerExecutable
245+ depsBS <- fromString <$> readProcess' bower ["list", "--json", "--offline"] ""
246+
247+ -- Check for undeclared dependencies
248+ toplevels <- catchJSON (parse asToplevelDependencies depsBS)
249+ warnUndeclared declaredDeps toplevels
250+
251+ deps <- catchJSON (parse asResolvedDependencies depsBS)
252+ handleDeps deps
253+
254+ where
255+ catchJSON = flip catchLeft (internalError . JSONError FromBowerList)
256+
257+findBowerExecutable :: PrepareM String
258+findBowerExecutable = do
259+ mname <- liftIO . runMaybeT . msum . map (MaybeT . findExecutable) $ names
260+ maybe (userError (BowerExecutableNotFound names)) return mname
261+ where
262+ names = case System.Info.os of
263+ "mingw32" -> ["bower", "bower.cmd"]
264+ _ -> ["bower"]
265+
266+-- | Extracts all dependencies and their versions from
267+-- `bower list --json --offline`
268+asResolvedDependencies :: Parse BowerError [(PackageName, DependencyStatus)]
269+asResolvedDependencies = nubBy ((==) `on` fst) <$> go
270+ where
271+ go =
272+ fmap (fromMaybe []) $
273+ keyMay "dependencies" $
274+ (++) <$> eachInObjectWithKey (parsePackageName . T.unpack)
275+ asDependencyStatus
276+ <*> (concatMap snd <$> eachInObject asResolvedDependencies)
277+
278+-- | Extracts only the top level dependency names from the output of
279+-- `bower list --json --offline`
280+asToplevelDependencies :: Parse BowerError [PackageName]
281+asToplevelDependencies =
282+ fmap (map fst) $
283+ key "dependencies" $
284+ eachInObjectWithKey (parsePackageName . T.unpack) (return ())
285+
286+asDependencyStatus :: Parse e DependencyStatus
287+asDependencyStatus = do
288+ isMissing <- keyOrDefault "missing" False asBool
289+ if isMissing
290+ then
291+ return Missing
292+ else
293+ key "pkgMeta" $
294+ keyOrDefault "_resolution" NoResolution $ do
295+ type_ <- key "type" asString
296+ case type_ of
297+ "version" -> ResolvedVersion <$> key "tag" asString
298+ other -> return (ResolvedOther other)
299+
300+warnUndeclared :: [PackageName] -> [PackageName] -> PrepareM ()
301+warnUndeclared declared actual =
302+ mapM_ (warn . UndeclaredDependency) (actual \\ declared)
303+
304+handleDeps ::
305+ [(PackageName, DependencyStatus)] -> PrepareM [(PackageName, Version)]
306+handleDeps deps = do
307+ let (missing, noVersion, installed) = partitionDeps deps
308+ case missing of
309+ (x:xs) ->
310+ userError (MissingDependencies (x :| xs))
311+ [] -> do
312+ mapM_ (warn . NoResolvedVersion) noVersion
313+ withVersions <- catMaybes <$> mapM tryExtractVersion' installed
314+ filterM (liftIO . isPureScript . bowerDir . fst) withVersions
315+
316+ where
317+ partitionDeps = foldr go ([], [], [])
318+ go (pkgName, d) (ms, os, is) =
319+ case d of
320+ Missing -> (pkgName : ms, os, is)
321+ NoResolution -> (ms, pkgName : os, is)
322+ ResolvedOther _ -> (ms, pkgName : os, is)
323+ ResolvedVersion v -> (ms, os, (pkgName, v) : is)
324+
325+ bowerDir pkgName = "bower_components/" ++ runPackageName pkgName
326+
327+ -- Try to extract a version, and warn if unsuccessful.
328+ tryExtractVersion' pair =
329+ maybe (warn (UnacceptableVersion pair) >> return Nothing)
330+ (return . Just)
331+ (tryExtractVersion pair)
332+
333+tryExtractVersion :: (PackageName, String) -> Maybe (PackageName, Version)
334+tryExtractVersion (pkgName, tag) =
335+ let tag' = fromMaybe tag (stripPrefix "v" tag)
336+ in (pkgName,) <$> D.parseVersion' tag'
337+
338+-- | Returns whether it looks like there is a purescript package checked out
339+-- in the given directory.
340+isPureScript :: FilePath -> IO Bool
341+isPureScript dir = do
342+ files <- Glob.globDir1 purescriptSourceFiles dir
343+ return (not (null files))
344+
345+getInputAndDepsFiles :: IO ([FilePath], [(PackageName, FilePath)])
346+getInputAndDepsFiles = do
347+ inputFiles <- globRelative purescriptSourceFiles
348+ depsFiles' <- globRelative purescriptDepsFiles
349+ return (inputFiles, mapMaybe withPackageName depsFiles')
350+
351+withPackageName :: FilePath -> Maybe (PackageName, FilePath)
352+withPackageName fp = (,fp) <$> getPackageName fp
353+
354+getPackageName :: FilePath -> Maybe PackageName
355+getPackageName fp = do
356+ let xs = splitOn [pathSeparator] fp
357+ ys <- stripPrefix ["bower_components"] xs
358+ y <- headMay ys
359+ case Bower.mkPackageName y of
360+ Right name -> Just name
361+ Left _ -> Nothing
psc-publish/BoxesHelpers.hs → src/Language/PureScript/Publish/BoxesHelpers.hsrenamed+2−2
@@ -1,7 +1,7 @@
1−module BoxesHelpers
1+module Language.PureScript.Publish.BoxesHelpers
22 ( Boxes.Box
33 , Boxes.nullBox
4− , module BoxesHelpers
4+ , module Language.PureScript.Publish.BoxesHelpers
55 ) where
66
77import System.IO (hPutStr, stderr)
psc-publish/ErrorsWarnings.hs → src/Language/PureScript/Publish/ErrorsWarnings.hsrenamed+100−33
@@ -1,11 +1,27 @@
11{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE RecordWildCards #-}
23
3−module ErrorsWarnings where
4+module Language.PureScript.Publish.ErrorsWarnings
5+ ( PackageError(..)
6+ , PackageWarning(..)
7+ , UserError(..)
8+ , InternalError(..)
9+ , OtherError(..)
10+ , RepositoryFieldError(..)
11+ , JSONSource(..)
12+ , printError
13+ , renderError
14+ , printWarnings
15+ , renderWarnings
16+ ) where
417
18+import Control.Applicative ((<$>))
519import Data.Aeson.BetterErrors
620import Data.Version
721import Data.Maybe
8−import Data.List (intersperse)
22+import Data.Monoid
23+import Data.Foldable (foldMap)
24+import Data.List (intersperse, intercalate)
925import Data.List.NonEmpty (NonEmpty(..))
1026import qualified Data.List.NonEmpty as NonEmpty
1127
@@ -18,7 +34,7 @@ import qualified Web.Bower.PackageMeta as Bower
1834import qualified Language.PureScript as P
1935import qualified Language.PureScript.Docs as D
2036
21−import BoxesHelpers
37+import Language.PureScript.Publish.BoxesHelpers
2238
2339-- | An error which meant that it was not possible to retrieve metadata for a
2440-- package.
@@ -29,13 +45,15 @@ data PackageError
2945 deriving (Show)
3046
3147data PackageWarning
32− = ResolutionNotVersion PackageName
48+ = NoResolvedVersion PackageName
3349 | UndeclaredDependency PackageName
50+ | UnacceptableVersion (PackageName, String)
3451 deriving (Show)
3552
3653-- | An error that should be fixed by the user.
3754data UserError
3855 = BowerJSONNotFound
56+ | BowerExecutableNotFound [String] -- list of executable names tried
3957 | CouldntParseBowerJSON (ParseError BowerError)
4058 | BowerJSONNameMissing
4159 | TagMustBeCheckedOut
@@ -43,6 +61,7 @@ data UserError
4361 | BadRepositoryField RepositoryFieldError
4462 | MissingDependencies (NonEmpty PackageName)
4563 | ParseAndDesugarError D.ParseDesugarError
64+ | DirtyWorkingTree
4665 deriving (Show)
4766
4867data RepositoryFieldError
@@ -103,6 +122,13 @@ displayUserError e = case e of
103122 [ "The bower.json file was not found. Please create one, or run "
104123 , "`pulp init`."
105124 ])
125+ BowerExecutableNotFound names ->
126+ para (concat
127+ [ "The Bower executable was not found (tried: ", format names, "). Please"
128+ , " ensure that bower is installed and on your PATH."
129+ ])
130+ where
131+ format = intercalate ", " . map show
106132 CouldntParseBowerJSON err ->
107133 vcat
108134 [ successivelyIndented
@@ -172,13 +198,18 @@ displayUserError e = case e of
172198 ParseAndDesugarError (D.SortModulesError err) ->
173199 vcat
174200 [ para "Error in sortModules:"
175− , indented (para (P.prettyPrintMultipleErrors False err))
201+ , indented (P.prettyPrintMultipleErrorsBox False err)
176202 ]
177203 ParseAndDesugarError (D.DesugarError err) ->
178204 vcat
179205 [ para "Error while desugaring:"
180− , indented (para (P.prettyPrintMultipleErrors False err))
206+ , indented (P.prettyPrintMultipleErrorsBox False err)
181207 ]
208+ DirtyWorkingTree ->
209+ para (concat
210+ [ "Your git working tree is dirty. Please commit, discard, or stash "
211+ , "your changes first."
212+ ])
182213
183214displayRepositoryError :: RepositoryFieldError -> Box
184215displayRepositoryError err = case err of
@@ -247,45 +278,52 @@ displayOtherError e = case e of
247278 successivelyIndented
248279 [ "An IO exception occurred:", show exc ]
249280
250−renderWarnings :: [PackageWarning] -> Box
251−renderWarnings =
252− collectWarnings
253− [ (getResolutionNotVersion, warnResolutionNotVersions)
254− , (getUndeclaredDependency, warnUndeclaredDependencies)
255− ]
256− where
257− collectWarnings patterns warns =
258− let boxes = mapMaybe (collectWarnings' warns) patterns
259− result = vcat
260− [ para "Warnings:"
261− , indented (vcat (intersperse spacer boxes))
262− ]
263− in if null boxes then nullBox else result
281+data CollectedWarnings = CollectedWarnings
282+ { noResolvedVersions :: [PackageName]
283+ , undeclaredDependencies :: [PackageName]
284+ , unacceptableVersions :: [(PackageName, String)]
285+ }
286+ deriving (Show, Eq, Ord)
264287
265− getResolutionNotVersion (ResolutionNotVersion n) = Just n
266− getResolutionNotVersion _ = Nothing
288+instance Monoid CollectedWarnings where
289+ mempty = CollectedWarnings mempty mempty mempty
290+ mappend (CollectedWarnings as bs cs) (CollectedWarnings as' bs' cs') =
291+ CollectedWarnings (as <> as') (bs <> bs') (cs <> cs')
267292
268− getUndeclaredDependency (UndeclaredDependency n) = Just n
269− getUndeclaredDependency _ = Nothing
293+collectWarnings :: [PackageWarning] -> CollectedWarnings
294+collectWarnings = foldMap singular
295+ where
296+ singular w = case w of
297+ NoResolvedVersion pn -> CollectedWarnings [pn] [] []
298+ UndeclaredDependency pn -> CollectedWarnings [] [pn] []
299+ UnacceptableVersion t -> CollectedWarnings [] [] [t]
270300
271−collectWarnings' :: [PackageWarning] -> ((PackageWarning -> Maybe a), (NonEmpty a -> Box)) -> Maybe Box
272−collectWarnings' warns (pattern, render) =
273− case mapMaybe pattern warns of
274− [] -> Nothing
275− (x:xs) -> Just (render (x :| xs))
301+renderWarnings :: [PackageWarning] -> Box
302+renderWarnings warns =
303+ let CollectedWarnings{..} = collectWarnings warns
304+ go toBox warns' = toBox <$> NonEmpty.nonEmpty warns'
305+ mboxes = [ go warnNoResolvedVersions noResolvedVersions
306+ , go warnUndeclaredDependencies undeclaredDependencies
307+ , go warnUnacceptableVersions unacceptableVersions
308+ ]
309+ in case catMaybes mboxes of
310+ [] -> nullBox
311+ boxes -> vcat [ para "Warnings:"
312+ , indented (vcat (intersperse spacer boxes))
313+ ]
276314
277−warnResolutionNotVersions :: NonEmpty PackageName -> Box
278−warnResolutionNotVersions pkgNames =
315+warnNoResolvedVersions :: NonEmpty PackageName -> Box
316+warnNoResolvedVersions pkgNames =
279317 let singular = NonEmpty.length pkgNames == 1
280318 pl a b = if singular then b else a
281319
282320 packages = pl "packages" "package"
283− were = pl "were" "was"
284321 anyOfThese = pl "any of these" "this"
285322 these = pl "these" "this"
286323 in vcat $
287324 [ para (concat
288− ["The following ", packages, " ", were, " not resolved to a version:"])
325+ ["The following ", packages, " did not appear to have a resolved "
326+ , "version:"])
289327 ] ++
290328 bulletedList runPackageName (NonEmpty.toList pkgNames)
291329 ++
@@ -314,5 +352,34 @@ warnUndeclaredDependencies pkgNames =
314352 ] ++
315353 bulletedList runPackageName (NonEmpty.toList pkgNames)
316354
355+warnUnacceptableVersions :: NonEmpty (PackageName, String) -> Box
356+warnUnacceptableVersions pkgs =
357+ let singular = NonEmpty.length pkgs == 1
358+ pl a b = if singular then b else a
359+
360+ packages' = pl "packages'" "package's"
361+ packages = pl "packages" "package"
362+ anyOfThese = pl "any of these" "this"
363+ these = pl "these" "this"
364+ versions = pl "versions" "version"
365+ in vcat $
366+ [ para (concat
367+ [ "The following installed Bower ", packages', " ", versions, " could "
368+ , "not be parsed:"
369+ ])
370+ ] ++
371+ bulletedList showTuple (NonEmpty.toList pkgs)
372+ ++
373+ [ spacer
374+ , para (concat
375+ ["Links to types in ", anyOfThese, " ", packages, " will not work. In "
376+ , "order to make links work, edit your bower.json to specify an "
377+ , "acceptable version or version range for ", these, " ", packages, ", "
378+ , "and rerun `bower install`."
379+ ])
380+ ]
381+ where
382+ showTuple (pkgName, tag) = runPackageName pkgName ++ "#" ++ tag
383+
317384printWarnings :: [PackageWarning] -> IO ()
318385printWarnings = printToStderr . renderWarnings
src/Language/PureScript/Publish/Utils.hsnew file+38
@@ -0,0 +1,38 @@
1+
2+module Language.PureScript.Publish.Utils where
3+
4+import Data.List
5+import Data.Either (partitionEithers)
6+import System.Directory
7+import System.Exit (exitFailure)
8+import System.IO (hPutStrLn, stderr)
9+import System.FilePath (pathSeparator)
10+import qualified System.FilePath.Glob as Glob
11+
12+-- | Glob relative to the current directory, and produce relative pathnames.
13+globRelative :: Glob.Pattern -> IO [FilePath]
14+globRelative pat = do
15+ currentDir <- getCurrentDirectory
16+ filesAbsolute <- Glob.globDir1 pat currentDir
17+ let prefix = currentDir ++ [pathSeparator]
18+ let (fails, paths) = partitionEithers . map (stripPrefix' prefix) $ filesAbsolute
19+ if null fails
20+ then return paths
21+ else do
22+ let p = hPutStrLn stderr
23+ p "Internal error in Language.PureScript.Publish.Utils.globRelative"
24+ p "Unmatched files:"
25+ mapM_ p fails
26+ exitFailure
27+
28+ where
29+ stripPrefix' prefix dir =
30+ maybe (Left dir) Right $ stripPrefix prefix dir
31+
32+-- | Glob pattern for PureScript source files.
33+purescriptSourceFiles :: Glob.Pattern
34+purescriptSourceFiles = Glob.compile "src/**/*.purs"
35+
36+-- | Glob pattern for PureScript dependency files.
37+purescriptDepsFiles :: Glob.Pattern
38+purescriptDepsFiles = Glob.compile "bower_components/*/src/**/*.purs"
src/Language/PureScript/Sugar/DoNotation.hs+3−3
@@ -10,7 +10,7 @@
1010--
1111-- |
1212-- This module implements the desugaring pass which replaces do-notation statements with
13−-- appropriate calls to (>>=) from the Prelude.Monad type class.
13+-- appropriate calls to bind from the Prelude.Monad type class.
1414--
1515-----------------------------------------------------------------------------
1616
@@ -32,7 +32,7 @@ import Control.Monad.Error.Class (MonadError(..))
3232import Control.Monad.Supply.Class
3333
3434-- |
35−-- Replace all @DoNotationBind@ and @DoNotationValue@ constructors with applications of the Prelude.(>>=) function,
35+-- Replace all @DoNotationBind@ and @DoNotationValue@ constructors with applications of the Prelude.bind function,
3636-- and all @DoNotationLet@ constructors with let expressions.
3737--
3838desugarDoModule :: forall m. (Applicative m, MonadSupply m, MonadError MultipleErrors m) => Module -> m Module
@@ -45,7 +45,7 @@ desugarDo d =
4545 in f d
4646 where
4747 bind :: Expr
48− bind = Var (Qualified Nothing (Op (C.>>=)))
48+ bind = Var (Qualified Nothing (Ident (C.bind)))
4949
5050 replace :: Expr -> m Expr
5151 replace (Do els) = go els
src/Language/PureScript/Sugar/Names.hs+74−7
@@ -14,13 +14,14 @@
1414
1515{-# LANGUAGE FlexibleContexts #-}
1616{-# LANGUAGE ScopedTypeVariables #-}
17+{-# LANGUAGE PatternGuards #-}
1718
1819module Language.PureScript.Sugar.Names (
1920 desugarImports
2021) where
2122
22−import Data.List (nub)
23−import Data.Maybe (fromMaybe, isJust, mapMaybe)
23+import Data.List (find, nub, (\\))
24+import Data.Maybe (catMaybes, fromMaybe, isJust, mapMaybe)
2425
2526import Control.Applicative (Applicative(..), (<$>), (<*>))
2627import Control.Monad
@@ -59,6 +60,10 @@ data Exports = Exports
5960 -- The values exported from each module
6061 --
6162 , exportedValues :: [Ident]
63+ -- |
64+ -- The modules exported from each module
65+ --
66+ , exportedModules :: [ModuleName]
6267 } deriving (Show)
6368
6469-- |
@@ -101,7 +106,7 @@ addEmptyModule :: (Applicative m, MonadError MultipleErrors m) => ExportEnvironm
101106addEmptyModule env name =
102107 if name `M.member` env
103108 then throwError . errorMessage $ RedefinedModule name
104− else return $ M.insert name (Exports [] [] []) env
109+ else return $ M.insert name (Exports [] [] [] []) env
105110
106111-- |
107112-- Adds a type belonging to a module to the export environment.
@@ -155,13 +160,65 @@ desugarImports :: forall m. (Applicative m, MonadError MultipleErrors m) => [Mod
155160desugarImports modules = do
156161 unfilteredExports <- findExports modules
157162 exports <- foldM filterModuleExports unfilteredExports modules
158− mapM (renameInModule' unfilteredExports exports) modules
163+ let modules' = moduleReexports <$> modules
164+ mapM (renameInModule' unfilteredExports exports) modules'
159165 where
166+ moduleReexports :: Module -> Module
167+ moduleReexports (Module coms mn decls exps) =
168+ let importedMods = catMaybes findImports'
169+ in (Module coms mn (decls ++ (concatMap reexports importedMods)) exps)
170+ where
171+ imports :: [Declaration]
172+ imports = filter isImportDecl decls
173+ findImports' :: [Maybe (Declaration, Module)]
174+ findImports' = go <$> modules
175+ where
176+ go :: Module -> Maybe (Declaration, Module)
177+ go m@(Module _ mn' _ (Just exps'))
178+ | any isModExport exps', Just d <- find ((== mn') . importedModName) imports = Just (d, m)
179+ where
180+ importedModName :: Declaration -> ModuleName
181+ importedModName (ImportDeclaration imn _ _) = imn
182+ importedModName (PositionedDeclaration _ _ d) = importedModName d
183+ importedModName _ = error "Not an import decl"
184+ go _ = Nothing
185+ reexports :: (Declaration, Module) -> [Declaration]
186+ reexports (ImportDeclaration _ (Hiding refs) _, (Module coms' mn' ds' (Just exps'))) =
187+ case nonHiddenRefs of
188+ [] -> []
189+ _ -> reexports (ImportDeclaration mn' Implicit Nothing, Module coms' mn' ds' (Just nonHiddenRefs))
190+ where
191+ nonHiddenRefs :: [DeclarationRef]
192+ nonHiddenRefs = filter isModExport exps' \\ filter isModExport refs
193+ reexports (ImportDeclaration _ ty qual, Module _ _ _ (Just exps')) =
194+ let ty' = case ty of
195+ Explicit _ -> Explicit []
196+ _ -> ty
197+ in (\m -> ImportDeclaration m ty' qual) <$> (catMaybes $ go <$> exps')
198+ where
199+ go :: DeclarationRef -> Maybe ModuleName
200+ go (ModuleRef mn') = Just mn'
201+ go _ = Nothing
202+ reexports (PositionedDeclaration _ _ d, m@(Module _ _ _ (Just _))) = reexports (d, m)
203+ reexports _ = []
204+
205+ isModExport :: DeclarationRef -> Bool
206+ isModExport (ModuleRef _) = True
207+ isModExport _ = False
160208
161209 -- Filters the exports for a module in the global exports environment so that only explicitly
162210 -- exported members remain. If the module does not explicitly export anything, everything is
163211 -- exported.
164212 filterModuleExports :: ExportEnvironment -> Module -> m ExportEnvironment
213+ filterModuleExports env (Module _ mn _ (Just exps))
214+ | any isSelfModuleExport exps, Just exps' <- M.lookup mn env =
215+ let moduleNames = filter (/= mn) $ (\(ModuleRef mn') -> mn') <$> filter isModExport exps
216+ in return $ M.insert mn (exps' {exportedModules = moduleNames}) env
217+ where
218+ isSelfModuleExport :: DeclarationRef -> Bool
219+ isSelfModuleExport (ModuleRef mn') | mn' == mn = True
220+ isSelfModuleExport (PositionedDeclarationRef _ _ ref) = isSelfModuleExport ref
221+ isSelfModuleExport _ = False
165222 filterModuleExports env (Module _ mn _ (Just exps)) = filterExports mn exps env
166223 filterModuleExports env _ = return env
167224
@@ -183,7 +240,8 @@ elaborateExports :: Exports -> Module -> Module
183240elaborateExports exps (Module coms mn decls _) = Module coms mn decls (Just $
184241 map (\(ctor, dctors) -> TypeRef ctor (Just dctors)) (exportedTypes exps) ++
185242 map TypeClassRef (exportedTypeClasses exps) ++
186− map ValueRef (exportedValues exps))
243+ map ValueRef (exportedValues exps) ++
244+ map ModuleRef (exportedModules exps))
187245
188246-- |
189247-- Add `import X ()` for any modules where there are only fully qualified references to members.
@@ -314,7 +372,7 @@ findExports = foldM addModule $ M.singleton (ModuleName [ProperName C.prim]) pri
314372 where
315373
316374 -- The exported types from the Prim module
317− primExports = Exports (mkTypeEntry `map` M.keys primTypes) [] []
375+ primExports = Exports (mkTypeEntry `map` M.keys primTypes) [] [] []
318376 where
319377 mkTypeEntry (Qualified _ name) = (name, [])
320378
@@ -358,7 +416,8 @@ filterExports mn exps env = do
358416 types' <- foldM (filterTypes $ exportedTypes exported) [] exps
359417 values <- foldM (filterValues $ exportedValues exported) [] exps
360418 classes <- foldM (filterClasses $ exportedTypeClasses exported) [] exps
361− return exported { exportedTypes = types', exportedTypeClasses = classes, exportedValues = values }
419+ modules <- foldM (filterModules $ exportedModules exported) [] exps
420+ return exported { exportedTypes = types', exportedTypeClasses = classes, exportedValues = values, exportedModules = modules }
362421
363422 -- Ensure the exported types and data constructors exist in the module and add them to the set of
364423 -- exports
@@ -395,6 +454,12 @@ filterExports mn exps env = do
395454 else throwError . errorMessage . UnknownValue $ Qualified (Just mn) name
396455 filterValues _ result _ = return result
397456
457+ -- Add the exported modules to the set of exports
458+ filterModules :: [ModuleName] -> [ModuleName] -> DeclarationRef -> m [ModuleName]
459+ filterModules exps' result (PositionedDeclarationRef pos _ r) = rethrowWithPosition pos $ filterModules exps' result r
460+ filterModules _ result (ModuleRef name) = return $ name : result
461+ filterModules _ result _ = return result
462+
398463-- |
399464-- Finds the imports within a module, mapping the imported module name to an optional set of
400465-- explicitly imported declarations.
@@ -501,6 +566,8 @@ resolveImport currentModule importModule exps imps impQual =
501566 return ref
502567 check ref@(TypeClassRef name) =
503568 checkImportExists UnknownTypeClass classes name >> return ref
569+ check ref@(ModuleRef name) =
570+ checkImportExists (UnknownModule . (\(Qualified _ m) -> m)) (exportedModules exps) name >> return ref
504571 check _ = error "Invalid argument to checkRefIsValid"
505572
506573 -- Find all exported data constructors for a given type
src/Language/PureScript/Sugar/TypeClasses.hs+1−1
@@ -300,7 +300,7 @@ typeInstanceDictionaryDeclaration name mn deps className tys decls1 =
300300
301301 memberToValue :: (Functor m, Applicative m, MonadSupply m, MonadError MultipleErrors m) => [(Ident, Type)] -> Declaration -> Desugar m Expr
302302 memberToValue tys' (ValueDeclaration ident _ [] (Right val)) = do
303− _ <- maybe (throwError . errorMessage $ MissingClassMember ident) return $ lookup ident tys'
303+ _ <- maybe (throwError . errorMessage $ ExtraneousClassMember ident) return $ lookup ident tys'
304304 return val
305305 memberToValue tys' (PositionedDeclaration pos com d) = rethrowWithPosition pos $ do
306306 val <- memberToValue tys' d
src/Language/PureScript/TypeChecker.hs+49−62
@@ -31,6 +31,7 @@ import Data.Foldable (for_)
3131
3232import qualified Data.Map as M
3333
34+import Control.Applicative ((<$>), (<*))
3435import Control.Monad.State
3536import Control.Monad.Error.Class (MonadError(..))
3637
@@ -88,10 +89,10 @@ addTypeClass moduleName pn args implies ds =
8889 toPair (PositionedDeclaration _ _ d) = toPair d
8990 toPair _ = error "Invalid declaration in TypeClassDeclaration"
9091
91−addTypeClassDictionaries :: [TypeClassDictionaryInScope] -> Check ()
92−addTypeClassDictionaries entries =
93− let mentries = M.fromList [ ((canonicalizeDictionary entry, mn), entry) | entry@TypeClassDictionaryInScope{ tcdName = Qualified mn _ } <- entries ]
94− in modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = (typeClassDictionaries . checkEnv $ st) `M.union` mentries } }
92+addTypeClassDictionaries :: Maybe ModuleName -> M.Map (Qualified ProperName) (M.Map (Qualified Ident) TypeClassDictionaryInScope) -> Check ()
93+addTypeClassDictionaries mn entries =
94+ modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = insertState st } }
95+ where insertState st = M.insertWith (M.unionWith M.union) mn entries (typeClassDictionaries . checkEnv $ st)
9596
9697checkDuplicateTypeArguments :: [String] -> Check ()
9798checkDuplicateTypeArguments args = for_ firstDup $ \dup ->
@@ -129,25 +130,23 @@ checkTypeSynonyms = void . replaceAllTypeSynonyms
129130-- * Process module imports
130131--
131132typeCheckAll :: Maybe ModuleName -> ModuleName -> [DeclarationRef] -> [Declaration] -> Check [Declaration]
132−typeCheckAll mainModuleName moduleName exps = go
133+typeCheckAll mainModuleName moduleName exps ds = mapM go ds <* mapM_ checkOrphanFixities ds
133134 where
134− go :: [Declaration] -> Check [Declaration]
135− go [] = return []
136− go (DataDeclaration dtype name args dctors : rest) = do
135+ go :: Declaration -> Check Declaration
136+ go (DataDeclaration dtype name args dctors) = do
137137 rethrow (onErrorMessages (ErrorInTypeConstructor name)) $ do
138138 when (dtype == Newtype) $ checkNewtype dctors
139139 checkDuplicateTypeArguments $ map fst args
140140 ctorKind <- kindsOf True moduleName name args (concatMap snd dctors)
141141 let args' = args `withKinds` ctorKind
142142 addDataType moduleName dtype name args' dctors ctorKind
143− ds <- go rest
144− return $ DataDeclaration dtype name args dctors : ds
143+ return $ DataDeclaration dtype name args dctors
145144 where
146145 checkNewtype :: [(ProperName, [Type])] -> Check ()
147146 checkNewtype [(_, [_])] = return ()
148147 checkNewtype [(_, _)] = throwError . errorMessage $ InvalidNewtype
149148 checkNewtype _ = throwError . errorMessage $ InvalidNewtype
150− go (d@(DataBindingGroupDeclaration tys) : rest) = do
149+ go (d@(DataBindingGroupDeclaration tys)) = do
151150 rethrow (onErrorMessages ErrorInDataBindingGroup) $ do
152151 let syns = mapMaybe toTypeSynonym tys
153152 let dataDecls = mapMaybe toDataDecl tys
@@ -160,8 +159,7 @@ typeCheckAll mainModuleName moduleName exps = go
160159 checkDuplicateTypeArguments $ map fst args
161160 let args' = args `withKinds` kind
162161 addTypeSynonym moduleName name args' ty kind
163− ds <- go rest
164− return $ d : ds
162+ return d
165163 where
166164 toTypeSynonym (TypeSynonymDeclaration nm args ty) = Just (nm, args, ty)
167165 toTypeSynonym (PositionedDeclaration _ _ d') = toTypeSynonym d'
@@ -169,26 +167,23 @@ typeCheckAll mainModuleName moduleName exps = go
169167 toDataDecl (DataDeclaration dtype nm args dctors) = Just (dtype, nm, args, dctors)
170168 toDataDecl (PositionedDeclaration _ _ d') = toDataDecl d'
171169 toDataDecl _ = Nothing
172− go (TypeSynonymDeclaration name args ty : rest) = do
170+ go (TypeSynonymDeclaration name args ty) = do
173171 rethrow (onErrorMessages (ErrorInTypeSynonym name)) $ do
174172 checkDuplicateTypeArguments $ map fst args
175173 kind <- kindsOf False moduleName name args [ty]
176174 let args' = args `withKinds` kind
177175 addTypeSynonym moduleName name args' ty kind
178− ds <- go rest
179− return $ TypeSynonymDeclaration name args ty : ds
180− go (TypeDeclaration _ _ : _) = error "Type declarations should have been removed"
181− go (ValueDeclaration name nameKind [] (Right val) : rest) = do
182− d <- rethrow (onErrorMessages (ErrorInValueDeclaration name)) $ do
176+ return $ TypeSynonymDeclaration name args ty
177+ go (TypeDeclaration{}) = error "Type declarations should have been removed"
178+ go (ValueDeclaration name nameKind [] (Right val)) =
179+ rethrow (onErrorMessages (ErrorInValueDeclaration name)) $ do
183180 valueIsNotDefined moduleName name
184181 [(_, (val', ty))] <- typesOf mainModuleName moduleName [(name, val)]
185182 addValue moduleName name ty nameKind
186183 return $ ValueDeclaration name nameKind [] $ Right val'
187− ds <- go rest
188− return $ d : ds
189− go (ValueDeclaration{} : _) = error "Binders were not desugared"
190− go (BindingGroupDeclaration vals : rest) = do
191− d <- rethrow (onErrorMessages (ErrorInBindingGroup (map (\(ident, _, _) -> ident) vals))) $ do
184+ go (ValueDeclaration{}) = error "Binders were not desugared"
185+ go (BindingGroupDeclaration vals) =
186+ rethrow (onErrorMessages (ErrorInBindingGroup (map (\(ident, _, _) -> ident) vals))) $ do
192187 forM_ (map (\(ident, _, _) -> ident) vals) $ \name ->
193188 valueIsNotDefined moduleName name
194189 tys <- typesOf mainModuleName moduleName $ map (\(ident, _, ty) -> (ident, ty)) vals
@@ -200,14 +195,11 @@ typeCheckAll mainModuleName moduleName exps = go
200195 addValue moduleName name ty nameKind
201196 return (name, nameKind, val)
202197 return $ BindingGroupDeclaration vals'
203− ds <- go rest
204− return $ d : ds
205− go (d@(ExternDataDeclaration name kind) : rest) = do
198+ go (d@(ExternDataDeclaration name kind)) = do
206199 env <- getEnv
207200 putEnv $ env { types = M.insert (Qualified (Just moduleName) name) (kind, ExternData) (types env) }
208− ds <- go rest
209− return $ d : ds
210− go (d@(ExternDeclaration name ty) : rest) = do
201+ return d
202+ go (d@(ExternDeclaration name ty)) = do
211203 rethrow (onErrorMessages (ErrorInForeignImport name)) $ do
212204 env <- getEnv
213205 kind <- kindOf moduleName ty
@@ -215,42 +207,37 @@ typeCheckAll mainModuleName moduleName exps = go
215207 case M.lookup (moduleName, name) (names env) of
216208 Just _ -> throwError . errorMessage $ RedefinedIdent name
217209 Nothing -> putEnv (env { names = M.insert (moduleName, name) (ty, External, Defined) (names env) })
218− ds <- go rest
219− return $ d : ds
220− go (d@(FixityDeclaration _ name) : rest) = do
221− ds <- go rest
210+ return d
211+ go (d@(FixityDeclaration{})) = return d
212+ go (d@(ImportDeclaration importedModule _ _)) = do
213+ instances <- lookupTypeClassDictionaries $ Just importedModule
214+ addTypeClassDictionaries (Just moduleName) instances
215+ return d
216+ go (d@(TypeClassDeclaration pn args implies tys)) = do
217+ addTypeClass moduleName pn args implies tys
218+ return d
219+ go (d@(TypeInstanceDeclaration dictName deps className tys _)) =
220+ goInstance d dictName deps className tys
221+ go (d@(ExternInstanceDeclaration dictName deps className tys)) =
222+ goInstance d dictName deps className tys
223+ go (PositionedDeclaration pos com d) =
224+ rethrowWithPosition pos $ PositionedDeclaration pos com <$> go d
225+
226+ checkOrphanFixities :: Declaration -> Check ()
227+ checkOrphanFixities (FixityDeclaration _ name) = do
222228 env <- getEnv
223229 guardWith (errorMessage (OrphanFixityDeclaration name)) $ M.member (moduleName, Op name) $ names env
224− return $ d : ds
225− go (d@(ImportDeclaration importedModule _ _) : rest) = do
226− tcds <- getTypeClassDictionaries
227− let instances = filter (\tcd -> let Qualified (Just mn) _ = tcdName tcd in importedModule == mn) tcds
228− addTypeClassDictionaries [ tcd { tcdName = Qualified (Just moduleName) ident, tcdType = TCDAlias (canonicalizeDictionary tcd) }
229− | tcd <- instances
230− , tcdExported tcd
231− , let (Qualified _ ident) = tcdName tcd
232− ]
233− ds <- go rest
234− return $ d : ds
235− go (d@(TypeClassDeclaration pn args implies tys) : rest) = do
236− addTypeClass moduleName pn args implies tys
237− ds <- go rest
238− return $ d : ds
239− go (d@(TypeInstanceDeclaration dictName deps className tys _) : rest) = do
240− goInstance d dictName deps className tys rest
241− go (d@(ExternInstanceDeclaration dictName deps className tys) : rest) = do
242− goInstance d dictName deps className tys rest
243− go (PositionedDeclaration pos com d : rest) =
244− rethrowWithPosition pos $ do
245− (d' : rest') <- go (d : rest)
246− return (PositionedDeclaration pos com d' : rest')
247− goInstance :: Declaration -> Ident -> [Constraint] -> Qualified ProperName -> [Type] -> [Declaration] -> Check [Declaration]
248− goInstance d dictName deps className tys rest = do
230+ checkOrphanFixities (PositionedDeclaration pos _ d) =
231+ rethrowWithPosition pos $ checkOrphanFixities d
232+ checkOrphanFixities _ = return ()
233+
234+ goInstance :: Declaration -> Ident -> [Constraint] -> Qualified ProperName -> [Type] -> Check Declaration
235+ goInstance d dictName deps className tys = do
249236 mapM_ (checkTypeClassInstance moduleName) tys
250237 forM_ deps $ mapM_ (checkTypeClassInstance moduleName) . snd
251− addTypeClassDictionaries [TypeClassDictionaryInScope (Qualified (Just moduleName) dictName) className tys (Just deps) TCDRegular isInstanceExported]
252− ds <- go rest
253− return $ d : ds
238+ let dict = TypeClassDictionaryInScope (Qualified (Just moduleName) dictName) className tys (Just deps) TCDRegular isInstanceExported
239+ addTypeClassDictionaries (Just moduleName) . M.singleton className $ M.singleton (canonicalizeDictionary dict) dict
240+ return d
254241
255242 where
256243
src/Language/PureScript/TypeChecker/Entailment.hs+9−14
@@ -47,20 +47,17 @@ newtype Work = Work Integer deriving (Show, Eq, Ord, Num)
4747-- Check that the current set of type class dictionaries entail the specified type class goal, and, if so,
4848-- return a type class dictionary reference.
4949--
50−entails :: Environment -> ModuleName -> [TypeClassDictionaryInScope] -> Constraint -> Bool -> Check Expr
51−entails env moduleName context = solve (sortedNubBy canonicalizeDictionary (filter filterModule context))
50+entails :: Environment -> ModuleName -> M.Map (Maybe ModuleName) (M.Map (Qualified ProperName) (M.Map (Qualified Ident) TypeClassDictionaryInScope)) -> Constraint -> Bool -> Check Expr
51+entails env moduleName context = solve
5252 where
53− sortedNubBy :: (Ord k) => (v -> k) -> [v] -> [v]
54− sortedNubBy f vs = M.elems (M.fromList (map (f &&& id) vs))
53+ forClassName :: Qualified ProperName -> [TypeClassDictionaryInScope]
54+ forClassName cn = findDicts cn Nothing ++ findDicts cn (Just moduleName)
5555
56− -- Filter out type dictionaries which are in scope in the current module
57− filterModule :: TypeClassDictionaryInScope -> Bool
58− filterModule (TypeClassDictionaryInScope { tcdName = Qualified (Just mn) _ }) | mn == moduleName = True
59− filterModule (TypeClassDictionaryInScope { tcdName = Qualified Nothing _ }) = True
60− filterModule _ = False
56+ findDicts :: Qualified ProperName -> Maybe ModuleName -> [TypeClassDictionaryInScope]
57+ findDicts cn = maybe [] M.elems . (>>= M.lookup cn) . flip M.lookup context
6158
62− solve :: [TypeClassDictionaryInScope] -> Constraint -> Bool -> Check Expr
63− solve context' (className, tys) trySuperclasses = do
59+ solve :: Constraint -> Bool -> Check Expr
60+ solve (className, tys) trySuperclasses = do
6461 let dicts = flip evalStateT (Work 0) $ go trySuperclasses className tys
6562 checkOverlaps dicts
6663 where
@@ -73,9 +70,7 @@ entails env moduleName context = solve (sortedNubBy canonicalizeDictionary (filt
7370 where
7471 directInstances :: StateT Work [] DictionaryValue
7572 directInstances = do
76− tcd <- lift context'
77− -- Make sure the type class name matches the one we are trying to satisfy
78− guard $ className' == tcdClassName tcd
73+ tcd <- lift $ forClassName className'
7974 -- Make sure the type unifies with the type in the type instance definition
8075 subst <- lift . maybeToList . (>>= verifySubstitution) . fmap concat $ zipWithM (typeHeadsAreEqual moduleName env) tys' (tcdInstanceTypes tcd)
8176 -- Solve any necessary subgoals
src/Language/PureScript/TypeChecker/Monad.hs+11−5
@@ -69,17 +69,23 @@ withScopedTypeVars mn ks = bindTypes (M.fromList (map (\(name, k) -> (Qualified
6969withTypeClassDictionaries :: (MonadState CheckState m) => [TypeClassDictionaryInScope] -> m a -> m a
7070withTypeClassDictionaries entries action = do
7171 orig <- get
72− let mentries = M.fromList [ ((canonicalizeDictionary entry, mn), entry) | entry@TypeClassDictionaryInScope{ tcdName = Qualified mn _ } <- entries ]
73− modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = (typeClassDictionaries . checkEnv $ st) `M.union` mentries } }
72+ let mentries = M.fromListWith (M.unionWith M.union) [ (mn, M.singleton className (M.singleton (canonicalizeDictionary entry) entry)) | entry@TypeClassDictionaryInScope{ tcdName = Qualified mn _, tcdClassName = className } <- entries ]
73+ modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = M.unionWith (M.unionWith M.union) (typeClassDictionaries . checkEnv $ st) mentries } }
7474 a <- action
7575 modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = typeClassDictionaries . checkEnv $ orig } }
7676 return a
7777
7878-- |
79−-- Get the currently available list of type class dictionaries
79+-- Get the currently available map of type class dictionaries
8080--
81−getTypeClassDictionaries :: (Functor m, MonadState CheckState m) => m [TypeClassDictionaryInScope]
82−getTypeClassDictionaries = M.elems . typeClassDictionaries . checkEnv <$> get
81+getTypeClassDictionaries :: (Functor m, MonadState CheckState m) => m (M.Map (Maybe ModuleName) (M.Map (Qualified ProperName) (M.Map (Qualified Ident) TypeClassDictionaryInScope)))
82+getTypeClassDictionaries = typeClassDictionaries . checkEnv <$> get
83+
84+-- |
85+-- Lookup type class dictionaries in a module.
86+--
87+lookupTypeClassDictionaries :: (Functor m, MonadState CheckState m) => Maybe ModuleName -> m (M.Map (Qualified ProperName) (M.Map (Qualified Ident) TypeClassDictionaryInScope))
88+lookupTypeClassDictionaries mn = fromMaybe M.empty . M.lookup mn . typeClassDictionaries . checkEnv <$> get
8389
8490-- |
8591-- Temporarily bind a collection of names to local variables
src/Language/PureScript/TypeChecker/Synonyms.hs+10−17
@@ -28,7 +28,6 @@ import Data.Maybe (fromMaybe)
2828import qualified Data.Map as M
2929
3030import Control.Applicative
31−import Control.Monad
3231import Control.Monad.Error.Class (MonadError(..))
3332import Control.Monad.State
3433
@@ -41,28 +40,22 @@ import Language.PureScript.Types
4140-- |
4241-- Build a type substitution for a type synonym
4342--
44−buildTypeSubstitution :: Qualified ProperName -> Int -> Type -> Either ErrorMessage (Maybe Type)
45−buildTypeSubstitution name n = go n []
43+buildTypeSubstitution :: M.Map (Qualified ProperName) Int -> Type -> Either ErrorMessage (Maybe Type)
44+buildTypeSubstitution m = go 0 []
4645 where
4746 go :: Int -> [Type] -> Type -> Either ErrorMessage (Maybe Type)
48− go 0 args (TypeConstructor ctor) | name == ctor = return (Just $ SaturatedTypeSynonym ctor args)
49− go m _ (TypeConstructor ctor) | m > 0 && name == ctor = throwError $ SimpleErrorWrapper $ PartiallyAppliedSynonym name
50− go m args (TypeApp f arg) = go (m - 1) (arg:args) f
47+ go c args (TypeConstructor ctor) | M.lookup ctor m == Just c = return (Just $ SaturatedTypeSynonym ctor args)
48+ go c _ (TypeConstructor ctor) | M.lookup ctor m > Just c = throwError $ SimpleErrorWrapper $ PartiallyAppliedSynonym ctor
49+ go c args (TypeApp f arg) = go (c + 1) (arg:args) f
5150 go _ _ _ = return Nothing
5251
53−-- |
54−-- Replace all instances of a specific type synonym with the @SaturatedTypeSynonym@ data constructor
55−--
56−saturateTypeSynonym :: Qualified ProperName -> Int -> Type -> Either ErrorMessage Type
57−saturateTypeSynonym name n = everywhereOnTypesTopDownM replace
58− where
59− replace t = fromMaybe t <$> buildTypeSubstitution name n t
60−
6152-- |
6253-- Replace all type synonyms with the @SaturatedTypeSynonym@ data constructor
6354--
64−saturateAllTypeSynonyms :: [(Qualified ProperName, Int)] -> Type -> Either ErrorMessage Type
65−saturateAllTypeSynonyms syns d = foldM (\result (name, n) -> saturateTypeSynonym name n result) d syns
55+saturateAllTypeSynonyms :: M.Map (Qualified ProperName) Int -> Type -> Either ErrorMessage Type
56+saturateAllTypeSynonyms syns = everywhereOnTypesTopDownM replace
57+ where
58+ replace t = fromMaybe t <$> buildTypeSubstitution syns t
6659
6760-- |
6861-- \"Desaturate\" @SaturatedTypeSynonym@s
@@ -80,7 +73,7 @@ desaturateAllTypeSynonyms = everywhereOnTypes replaceSaturatedTypeSynonym
8073replaceAllTypeSynonyms' :: Environment -> Type -> Either ErrorMessage Type
8174replaceAllTypeSynonyms' env d =
8275 let
83− syns = map (\(name, (args, _)) -> (name, length args)) . M.toList $ typeSynonyms env
76+ syns = length . fst <$> typeSynonyms env
8477 in
8578 saturateAllTypeSynonyms syns d
8679
src/Language/PureScript/TypeChecker/Types.hs+7−4
@@ -369,12 +369,15 @@ inferBinder val (ConstructorBinder ctor binders) = do
369369 fn' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ fn
370370 go binders fn'
371371 where
372− go [] ty' = do
373− _ <- subsumes Nothing val ty'
374− return M.empty
372+ go [] ty' = case (val, ty') of
373+ (TypeConstructor _, TypeApp _ _) -> throwIncorrectArity
374+ _ -> do
375+ _ <- subsumes Nothing val ty'
376+ return M.empty
375377 go (binder : binders') (TypeApp (TypeApp t obj) ret) | t == tyFunction =
376378 M.union <$> inferBinder obj binder <*> go binders' ret
377− go _ _ = throwError . errorMessage $ IncorrectConstructorArity ctor
379+ go _ _ = throwIncorrectArity
380+ throwIncorrectArity = throwError . errorMessage $ IncorrectConstructorArity ctor
378381 _ -> throwError . errorMessage $ UnknownDataConstructor ctor Nothing
379382inferBinder val (ObjectBinder props) = do
380383 row <- fresh
src/Language/PureScript/Types.hs+8−2
@@ -14,11 +14,15 @@
1414-----------------------------------------------------------------------------
1515
1616{-# LANGUAGE DeriveDataTypeable #-}
17+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
18+{-# LANGUAGE TemplateHaskell #-}
1719
1820module Language.PureScript.Types where
1921
2022import Data.Data
2123import Data.List (nub)
24+import qualified Data.Aeson as A
25+import qualified Data.Aeson.TH as A
2226
2327import Control.Monad.Unify
2428import Control.Arrow (second)
@@ -32,7 +36,7 @@ import Language.PureScript.Traversals
3236-- |
3337-- An identifier for the scope of a skolem variable
3438--
35−newtype SkolemScope = SkolemScope { runSkolemScope :: Int } deriving (Show, Eq, Ord, Data, Typeable)
39+newtype SkolemScope = SkolemScope { runSkolemScope :: Int } deriving (Show, Eq, Ord, Data, Typeable, A.ToJSON, A.FromJSON)
3640
3741-- |
3842-- The type of types
@@ -98,13 +102,15 @@ data Type
98102 -- |
99103 -- A placeholder used in pretty printing
100104 --
101− | PrettyPrintForAll [String] Type deriving (Show, Eq, Data, Typeable)
105+ | PrettyPrintForAll [String] Type deriving (Show, Eq, Ord, Data, Typeable)
102106
103107-- |
104108-- A typeclass constraint
105109--
106110type Constraint = (Qualified ProperName, [Type])
107111
112+$(A.deriveJSON A.defaultOptions ''Type)
113+
108114-- |
109115-- Convert a row to a list of pairs of labels and types
110116--
stack.yamlnew file+9
@@ -0,0 +1,9 @@
1+flags: {}
2+packages:
3+- '.'
4+extra-deps:
5+- aeson-better-errors-0.8.0
6+- bower-json-0.7.0.0
7+- boxes-0.1.4
8+- pattern-arrows-0.0.2
9+resolver: lts-2.22
tests/Main.hs+175−65
@@ -12,107 +12,217 @@
1212--
1313-----------------------------------------------------------------------------
1414
15−{-# LANGUAGE DataKinds, DoAndIfThenElse, TupleSections #-}
15+{-# LANGUAGE DataKinds #-}
16+{-# LANGUAGE DoAndIfThenElse #-}
17+{-# LANGUAGE TupleSections #-}
18+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
19+{-# LANGUAGE FlexibleInstances #-}
20+
21+-- Failing tests can specify the kind of error that should be thrown with a
22+-- @shouldFailWith declaration. For example:
23+--
24+-- "-- @shouldFailWith TypesDoNotUnify"
25+--
26+-- will cause the test to fail unless that module fails to compile with exactly
27+-- one TypesDoNotUnify error.
28+--
29+-- If a module is expected to produce multiple type errors, then use multiple
30+-- @shouldFailWith lines; for example:
31+--
32+-- -- @shouldFailWith TypesDoNotUnify
33+-- -- @shouldFailWith TypesDoNotUnify
34+-- -- @shouldFailWith TransitiveExportError
1635
1736module Main (main) where
1837
1938import qualified Language.PureScript as P
39+import qualified Language.PureScript.CodeGen.JS as J
40+import qualified Language.PureScript.CoreFn as CF
2041
21−import Data.List (isSuffixOf)
42+import Data.Char (isSpace)
43+import Data.Maybe (mapMaybe, fromMaybe)
44+import Data.List (isSuffixOf, sort, stripPrefix)
2245import Data.Traversable (traverse)
46+import Data.Time.Clock (UTCTime())
2347
2448import qualified Data.Map as M
2549
2650import Control.Monad
2751import Control.Monad.IO.Class (liftIO)
28−import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
29−import Control.Monad.Reader (runReaderT)
30−import Control.Monad.Writer (runWriterT)
31−import Control.Monad.Trans.Except (runExceptT)
3252import Control.Applicative
53+import Control.Arrow ((>>>))
54+
55+import Control.Monad.Reader
56+import Control.Monad.Writer
57+import Control.Monad.Trans.Maybe
58+import Control.Monad.Trans.Except
59+import Control.Monad.Error.Class
3360
3461import System.Exit
3562import System.Process
36−import System.FilePath ((</>))
37−import System.Directory (getCurrentDirectory, getTemporaryDirectory, getDirectoryContents, findExecutable)
63+import System.FilePath
64+import System.Directory
65+import qualified System.FilePath.Glob as Glob
3866
3967import Text.Parsec (ParseError)
4068
69+modulesDir :: FilePath
70+modulesDir = ".test_modules" </> "node_modules"
71+
72+makeActions :: M.Map P.ModuleName (FilePath, P.ForeignJS) -> P.MakeActions P.Make
73+makeActions foreigns = (P.buildMakeActions modulesDir (error "makeActions: input file map was read.") foreigns False)
74+ { P.getInputTimestamp = getInputTimestamp
75+ , P.getOutputTimestamp = getOutputTimestamp
76+ }
77+ where
78+ getInputTimestamp :: P.ModuleName -> P.Make (Either P.RebuildPolicy (Maybe UTCTime))
79+ getInputTimestamp mn
80+ | isSupportModule (P.runModuleName mn) = return (Left P.RebuildNever)
81+ | otherwise = return (Left P.RebuildAlways)
82+ where
83+ isSupportModule = flip elem supportModules
84+
85+ getOutputTimestamp :: P.ModuleName -> P.Make (Maybe UTCTime)
86+ getOutputTimestamp mn = do
87+ let filePath = modulesDir </> P.runModuleName mn
88+ exists <- liftIO $ doesDirectoryExist filePath
89+ return (if exists then Just (error "getOutputTimestamp: read timestamp") else Nothing)
90+
4191readInput :: [FilePath] -> IO [(FilePath, String)]
4292readInput inputFiles = forM inputFiles $ \inputFile -> do
4393 text <- readFile inputFile
4494 return (inputFile, text)
4595
46−loadPrelude :: [(FilePath, String)] -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> Either P.MultipleErrors (String, String, P.Environment)
47−loadPrelude fs foreigns = do
48− ms <- P.parseModulesFromFiles id fs
49− fmap fst . runWriterT $ runReaderT (P.compileJS (map snd ms) foreigns []) (P.defaultCompileOptions { P.optionsAdditional = P.CompileOptions "Tests" [] [] })
96+type TestM = WriterT [(FilePath, String)] IO
5097
51−compile :: P.Options P.Compile -> [FilePath] -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> IO (Either P.MultipleErrors (String, String, P.Environment))
52−compile opts inputFiles foreigns = runExceptT . fmap fst . runWriterT . flip runReaderT opts $ do
98+runTest :: P.Make a -> IO (Either P.MultipleErrors a)
99+runTest = fmap (fmap fst) . P.runMake P.defaultOptions
100+
101+compile :: [FilePath] -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> IO (Either P.MultipleErrors P.Environment)
102+compile inputFiles foreigns = runTest $ do
53103 fs <- liftIO $ readInput inputFiles
54104 ms <- P.parseModulesFromFiles id fs
55− P.compileJS (map snd ms) foreigns []
56−
57−assert :: FilePath -> P.Options P.Compile -> FilePath -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> (Either P.MultipleErrors (String, String, P.Environment) -> IO (Maybe String)) -> IO ()
58−assert preludeExterns opts inputFile foreigns f = do
59− e <- compile opts [preludeExterns, inputFile] foreigns
60− maybeErr <- f e
105+ P.make (makeActions foreigns) (map snd ms)
106+
107+assert :: [FilePath] ->
108+ M.Map P.ModuleName (FilePath, P.ForeignJS) ->
109+ (Either P.MultipleErrors P.Environment -> IO (Maybe String)) ->
110+ TestM ()
111+assert inputFiles foreigns f = do
112+ e <- liftIO $ compile inputFiles foreigns
113+ maybeErr <- liftIO $ f e
61114 case maybeErr of
62− Just err -> putStrLn err >> exitFailure
115+ Just err -> tell [(last inputFiles, err)]
63116 Nothing -> return ()
64117
65−assertCompiles :: String -> FilePath -> FilePath -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> IO ()
66−assertCompiles preludeJs preludeExterns inputFile foreigns = do
67− putStrLn $ "Assert " ++ inputFile ++ " compiles successfully"
68− let options = P.defaultCompileOptions
69− { P.optionsMain = Just "Main"
70− , P.optionsAdditional = P.CompileOptions "Tests" ["Main"] ["Main"]
71− }
72− assert preludeExterns options inputFile foreigns $ either (return . Just . P.prettyPrintMultipleErrors False) $ \(js, _, _) -> do
73− process <- findNodeProcess
74− result <- traverse (\node -> readProcessWithExitCode node [] (preludeJs ++ js)) process
75− case result of
76− Just (ExitSuccess, out, _) -> putStrLn out >> return Nothing
77− Just (ExitFailure _, _, err) -> return $ Just err
78− Nothing -> return $ Just "Couldn't find node.js executable"
79−
80−assertDoesNotCompile :: FilePath -> FilePath -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> IO ()
81−assertDoesNotCompile preludeExterns inputFile foreigns = do
82− putStrLn $ "Assert " ++ inputFile ++ " does not compile"
83− assert preludeExterns (P.defaultCompileOptions { P.optionsAdditional = P.CompileOptions "Tests" [] [] }) inputFile foreigns $ \e ->
118+assertCompiles :: [FilePath] -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> TestM ()
119+assertCompiles inputFiles foreigns = do
120+ liftIO . putStrLn $ "Assert " ++ last inputFiles ++ " compiles successfully"
121+ assert inputFiles foreigns $ \e ->
84122 case e of
85− Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> return Nothing
86− Right _ -> return $ Just "Should not have compiled"
123+ Left errs -> return . Just . P.prettyPrintMultipleErrors False $ errs
124+ Right _ -> do
125+ process <- findNodeProcess
126+ let entryPoint = modulesDir </> "index.js"
127+ writeFile entryPoint "require('Main').main()"
128+ result <- traverse (\node -> readProcessWithExitCode node [entryPoint] "") process
129+ case result of
130+ Just (ExitSuccess, out, _) -> putStrLn out >> return Nothing
131+ Just (ExitFailure _, _, err) -> return $ Just err
132+ Nothing -> return $ Just "Couldn't find node.js executable"
133+
134+assertDoesNotCompile :: [FilePath] -> M.Map P.ModuleName (FilePath, P.ForeignJS) -> TestM ()
135+assertDoesNotCompile inputFiles foreigns = do
136+ let testFile = last inputFiles
137+ liftIO . putStrLn $ "Assert " ++ testFile ++ " does not compile"
138+ shouldFailWith <- getShouldFailWith testFile
139+ assert inputFiles foreigns $ \e ->
140+ case e of
141+ Left errs -> do
142+ putStrLn (P.prettyPrintMultipleErrors False errs)
143+ return $ if null shouldFailWith
144+ then Just $ "shouldFailWith declaration is missing (errors were: "
145+ ++ show (map P.errorCode (P.runMultipleErrors errs))
146+ ++ ")"
147+ else checkShouldFailWith shouldFailWith errs
148+ Right _ ->
149+ return $ Just "Should not have compiled"
150+
151+ where
152+ getShouldFailWith =
153+ readFile
154+ >>> liftIO
155+ >>> fmap ( lines
156+ >>> mapMaybe (stripPrefix "-- @shouldFailWith ")
157+ >>> map trim
158+ )
159+
160+ checkShouldFailWith expected errs =
161+ let actual = map P.errorCode $ P.runMultipleErrors errs
162+ in if sort expected == sort actual
163+ then Nothing
164+ else Just $ "Expected these errors: " ++ show expected ++ ", but got these: " ++ show actual
165+
166+ trim =
167+ dropWhile isSpace >>> reverse >>> dropWhile isSpace >>> reverse
87168
88169findNodeProcess :: IO (Maybe String)
89170findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names
90− where
171+ where
91172 names = ["nodejs", "node"]
92173
93174main :: IO ()
94175main = do
176+ fetchSupportCode
95177 cwd <- getCurrentDirectory
96− let preludeDir = cwd </> "tests" </> "prelude"
97− jsDir = preludeDir </> "js"
98− prelude <- readInput [preludeDir </> "Prelude.purs"]
99− jsFiles <- map (jsDir </>) . filter (".js" `isSuffixOf`) <$> getDirectoryContents jsDir
100− foreignFiles <- forM jsFiles (\f -> (f,) <$> readFile f)
178+
179+ let supportDir = cwd </> "tests" </> "support" </> "flattened"
180+ let supportFiles ext = Glob.globDir1 (Glob.compile ("*." ++ ext)) supportDir
181+
182+ supportPurs <- supportFiles "purs"
183+ supportJS <- supportFiles "js"
184+
185+ foreignFiles <- forM supportJS (\f -> (f,) <$> readFile f)
101186 Right (foreigns, _) <- runExceptT $ runWriterT $ P.parseForeignModulesFromFiles foreignFiles
102− putStrLn "Compiling Prelude"
103− case loadPrelude prelude foreigns of
104− Left errs -> putStrLn (P.prettyPrintMultipleErrors False errs) >> exitFailure
105− Right (preludeJs, exts, _) -> do
106− tmp <- getTemporaryDirectory
107− let preludeExterns = tmp </> "prelude.externs"
108− writeFile preludeExterns exts
109− putStrLn $ "Wrote " ++ preludeExterns
110− let passing = cwd </> "examples" </> "passing"
111− passingTestCases <- getDirectoryContents passing
112− forM_ passingTestCases $ \inputFile -> when (".purs" `isSuffixOf` inputFile) $
113− assertCompiles preludeJs preludeExterns (passing </> inputFile) foreigns
114− let failing = cwd </> "examples" </> "failing"
115− failingTestCases <- getDirectoryContents failing
116− forM_ failingTestCases $ \inputFile -> when (".purs" `isSuffixOf` inputFile) $
117− assertDoesNotCompile preludeExterns (failing </> inputFile) foreigns
118− exitSuccess
187+
188+ let passing = cwd </> "examples" </> "passing"
189+ passingTestCases <- sort . filter (".purs" `isSuffixOf`) <$> getDirectoryContents passing
190+ let failing = cwd </> "examples" </> "failing"
191+ failingTestCases <- sort . filter (".purs" `isSuffixOf`) <$> getDirectoryContents failing
192+
193+ failures <- execWriterT $ do
194+ forM_ passingTestCases $ \inputFile ->
195+ assertCompiles (supportPurs ++ [passing </> inputFile]) foreigns
196+ forM_ failingTestCases $ \inputFile ->
197+ assertDoesNotCompile (supportPurs ++ [failing </> inputFile]) foreigns
198+
199+ if null failures
200+ then exitSuccess
201+ else do
202+ putStrLn "Failures:"
203+ forM_ failures $ \(fp, err) ->
204+ let fp' = fromMaybe fp $ stripPrefix (failing ++ [pathSeparator]) fp
205+ in putStrLn $ fp' ++ ": " ++ err
206+ exitFailure
207+
208+fetchSupportCode :: IO ()
209+fetchSupportCode = do
210+ setCurrentDirectory "tests/support"
211+ callProcess "npm" ["install"]
212+ -- Sometimes we run as a root (e.g. in simple docker containers)
213+ -- And we are non-interactive: https://github.com/bower/bower/issues/1162
214+ callProcess "node_modules/.bin/bower" ["--allow-root", "install", "--config.interactive=false"]
215+ callProcess "node" ["setup.js"]
216+ setCurrentDirectory "../.."
217+
218+supportModules :: [String]
219+supportModules =
220+ [ "Control.Monad.Eff.Class"
221+ , "Control.Monad.Eff.Console"
222+ , "Control.Monad.Eff"
223+ , "Control.Monad.Eff.Unsafe"
224+ , "Control.Monad.ST"
225+ , "Data.Function"
226+ , "Prelude"
227+ , "Test.Assert"
228+ ]
tests/prelude/Prelude.pursdeleted−628
@@ -1,628 +0,0 @@
1−-- | This snapshot is provided for the purposes of running the test suite.
2−-- | It is not necessarily kept up to date with the official PureScript Prelude,
3−-- | and should not be used in user code.
4−-- | The official Prelude can be found at https://github.com/purescript/purescript-prelude
5−
6−module Prelude
7− ( Unit(..), unit
8− , ($), (#)
9− , length
10− , flip
11− , const
12− , asTypeOf
13− , otherwise
14− , (:), cons, concat
15− , Semigroupoid, (<<<), (>>>)
16− , Category, id
17− , Functor, (<$>), (<#>), void
18− , Apply, (<*>)
19− , Applicative, pure, liftA1
20− , Bind, (>>=)
21− , Monad, return, liftM1, ap
22− , Semigroup, (<>), (++)
23− , Semiring, (+), zero, (*), one
24− , ModuloSemiring, (/), mod, jsMod, (%)
25− , Ring, (-), negate
26− , Num
27− , DivisionRing
28− , Eq, (==), (/=)
29− , Ordering(..), Ord, compare, (<), (>), (<=), (>=)
30− , Bounded, top, bottom
31− , Lattice, sup, inf, (||), (&&)
32− , BoundedLattice
33− , ComplementedLattice, not
34− , DistributiveLattice
35− , BooleanAlgebra
36− , Show, show
37− ) where
38−
39− newtype Unit = Unit {}
40−
41− unit :: Unit
42− unit = Unit {}
43−
44− foreign import length :: forall a. Array a -> Number
45−
46− infixr 0 $
47− infixl 0 #
48−
49− ($) :: forall a b. (a -> b) -> a -> b
50− ($) f x = f x
51−
52− (#) :: forall a b. a -> (a -> b) -> b
53− (#) x f = f x
54−
55− flip :: forall a b c. (a -> b -> c) -> b -> a -> c
56− flip f b a = f a b
57−
58− const :: forall a b. a -> b -> a
59− const a _ = a
60−
61− asTypeOf :: forall a. a -> a -> a
62− asTypeOf x _ = x
63−
64− otherwise :: Boolean
65− otherwise = true
66−
67− foreign import cons :: forall a. a -> Array a -> Array a
68−
69− infixr 6 :
70−
71− (:) :: forall a. a -> Array a -> Array a
72− (:) = cons
73−
74− foreign import concat :: forall a. Array a -> Array a -> Array a
75−
76− infixr 9 >>>
77− infixr 9 <<<
78−
79− class Semigroupoid a where
80− (<<<) :: forall b c d. a c d -> a b c -> a b d
81−
82− instance semigroupoidArr :: Semigroupoid (->) where
83− (<<<) f g x = f (g x)
84−
85− (>>>) :: forall a b c d. (Semigroupoid a) => a b c -> a c d -> a b d
86− (>>>) f g = g <<< f
87−
88− class (Semigroupoid a) <= Category a where
89− id :: forall t. a t t
90−
91− instance categoryArr :: Category (->) where
92− id x = x
93−
94− infixl 4 <$>
95− infixl 1 <#>
96−
97− class Functor f where
98− (<$>) :: forall a b. (a -> b) -> f a -> f b
99−
100− instance functorArr :: Functor ((->) r) where
101− (<$>) = (<<<)
102−
103− (<#>) :: forall f a b. (Functor f) => f a -> (a -> b) -> f b
104− (<#>) fa f = f <$> fa
105−
106− void :: forall f a. (Functor f) => f a -> f Unit
107− void fa = const unit <$> fa
108−
109− infixl 4 <*>
110−
111− class (Functor f) <= Apply f where
112− (<*>) :: forall a b. f (a -> b) -> f a -> f b
113−
114− instance applyArr :: Apply ((->) r) where
115− (<*>) f g x = f x (g x)
116−
117− class (Apply f) <= Applicative f where
118− pure :: forall a. a -> f a
119−
120− instance applicativeArr :: Applicative ((->) r) where
121− pure = const
122−
123− return :: forall m a. (Applicative m) => a -> m a
124− return = pure
125−
126− liftA1 :: forall f a b. (Applicative f) => (a -> b) -> f a -> f b
127− liftA1 f a = pure f <*> a
128−
129− infixl 1 >>=
130−
131− class (Apply m) <= Bind m where
132− (>>=) :: forall a b. m a -> (a -> m b) -> m b
133−
134− instance bindArr :: Bind ((->) r) where
135− (>>=) m f x = f (m x) x
136−
137− class (Applicative m, Bind m) <= Monad m
138−
139− instance monadArr :: Monad ((->) r)
140−
141− liftM1 :: forall m a b. (Monad m) => (a -> b) -> m a -> m b
142− liftM1 f a = do
143− a' <- a
144− return (f a')
145−
146− ap :: forall m a b. (Monad m) => m (a -> b) -> m a -> m b
147− ap f a = do
148− f' <- f
149− a' <- a
150− return (f' a')
151−
152− infixr 5 <>
153− infixr 5 ++
154−
155− class Semigroup a where
156− (<>) :: a -> a -> a
157−
158− (++) :: forall s. (Semigroup s) => s -> s -> s
159− (++) = (<>)
160−
161− instance semigroupString :: Semigroup String where
162− (<>) = concatString
163−
164− instance semigroupUnit :: Semigroup Unit where
165− (<>) _ _ = unit
166−
167− instance semigroupArr :: (Semigroup s') => Semigroup (s -> s') where
168− (<>) f g = \x -> f x <> g x
169−
170− instance semigroupOrdering :: Semigroup Ordering where
171− (<>) LT _ = LT
172− (<>) GT _ = GT
173− (<>) EQ y = y
174−
175− foreign import concatString :: String -> String -> String
176−
177− infixl 6 +
178− infixl 7 *
179−
180− class Semiring a where
181− (+) :: a -> a -> a
182− zero :: a
183− (*) :: a -> a -> a
184− one :: a
185−
186− instance semiringNumber :: Semiring Number where
187− (+) = numAdd
188− zero = 0.0
189− (*) = numMul
190− one = 1.0
191−
192− instance semiringUnit :: Semiring Unit where
193− (+) _ _ = unit
194− zero = unit
195− (*) _ _ = unit
196− one = unit
197−
198− infixl 6 -
199−
200− class (Semiring a) <= Ring a where
201− (-) :: a -> a -> a
202−
203− instance ringNumber :: Ring Number where
204− (-) = numSub
205−
206− instance ringUnit :: Ring Unit where
207− (-) _ _ = unit
208−
209− negate :: forall a. (Ring a) => a -> a
210− negate a = zero - a
211−
212− infixl 7 /
213−
214− class (Semiring a) <= ModuloSemiring a where
215− (/) :: a -> a -> a
216− mod :: a -> a -> a
217−
218− instance moduloSemiringNumber :: ModuloSemiring Number where
219− (/) = numDiv
220− mod _ _ = 0.0
221−
222− instance moduloSemiringUnit :: ModuloSemiring Unit where
223− (/) _ _ = unit
224− mod _ _ = unit
225−
226− foreign import jsMod :: Number -> Number -> Number
227−
228− infixl 7 %
229−
230− (%) = jsMod
231−
232− class (Ring a, ModuloSemiring a) <= DivisionRing a
233−
234− instance divisionRingNumber :: DivisionRing Number
235−
236− instance divisionRingUnit :: DivisionRing Unit
237−
238− class (DivisionRing a) <= Num a
239−
240− instance numNumber :: Num Number
241−
242− instance numUnit :: Num Unit
243−
244− foreign import numAdd :: Number -> Number -> Number
245−
246− foreign import numMul :: Number -> Number -> Number
247−
248− foreign import numDiv :: Number -> Number -> Number
249−
250− foreign import numSub :: Number -> Number -> Number
251−
252− infix 4 ==
253− infix 4 /=
254−
255− class Eq a where
256− (==) :: a -> a -> Boolean
257− (/=) :: a -> a -> Boolean
258−
259− instance eqBoolean :: Eq Boolean where
260− (==) = refEq
261− (/=) = refIneq
262−
263− instance eqNumber :: Eq Number where
264− (==) = refEq
265− (/=) = refIneq
266−
267− instance eqInt :: Eq Int where
268− (==) = refEq
269− (/=) = refIneq
270−
271− instance eqChar :: Eq Char where
272− (==) = refEq
273− (/=) = refIneq
274−
275− instance eqString :: Eq String where
276− (==) = refEq
277− (/=) = refIneq
278−
279− instance eqUnit :: Eq Unit where
280− (==) _ _ = true
281− (/=) _ _ = false
282−
283− instance eqArray :: (Eq a) => Eq (Array a) where
284− (==) = eqArrayImpl (==)
285− (/=) xs ys = not (xs == ys)
286−
287− instance eqOrdering :: Eq Ordering where
288− (==) LT LT = true
289− (==) GT GT = true
290− (==) EQ EQ = true
291− (==) _ _ = false
292− (/=) x y = not (x == y)
293−
294− foreign import refEq :: forall a. a -> a -> Boolean
295−
296− foreign import refIneq :: forall a. a -> a -> Boolean
297−
298− foreign import eqArrayImpl :: forall a. (a -> a -> Boolean) -> Array a -> Array a -> Boolean
299−
300− data Ordering = LT | GT | EQ
301−
302− class (Eq a) <= Ord a where
303− compare :: a -> a -> Ordering
304−
305− instance ordBoolean :: Ord Boolean where
306− compare false false = EQ
307− compare false true = LT
308− compare true true = EQ
309− compare true false = GT
310−
311− instance ordNumber :: Ord Number where
312− compare = unsafeCompare
313−
314− instance ordString :: Ord String where
315− compare = unsafeCompare
316−
317− instance ordUnit :: Ord Unit where
318− compare _ _ = EQ
319−
320− instance ordArray :: (Ord a) => Ord (Array a) where
321− compare xs ys = compare 0.0 $ ordArrayImpl (\x y -> case compare x y of
322− EQ -> 0.0
323− LT -> -1.0
324− GT -> 1.0) xs ys
325−
326− foreign import ordArrayImpl :: forall a. (a -> a -> Number) -> Array a -> Array a -> Number
327−
328− instance ordOrdering :: Ord Ordering where
329− compare LT LT = EQ
330− compare EQ EQ = EQ
331− compare GT GT = EQ
332− compare LT _ = LT
333− compare EQ LT = GT
334− compare EQ GT = LT
335− compare GT _ = GT
336−
337− infixl 4 <
338− infixl 4 >
339− infixl 4 <=
340− infixl 4 >=
341−
342− (<) :: forall a. (Ord a) => a -> a -> Boolean
343− (<) a1 a2 = case a1 `compare` a2 of
344− LT -> true
345− _ -> false
346−
347− (>) :: forall a. (Ord a) => a -> a -> Boolean
348− (>) a1 a2 = case a1 `compare` a2 of
349− GT -> true
350− _ -> false
351−
352− (<=) :: forall a. (Ord a) => a -> a -> Boolean
353− (<=) a1 a2 = case a1 `compare` a2 of
354− GT -> false
355− _ -> true
356−
357− (>=) :: forall a. (Ord a) => a -> a -> Boolean
358− (>=) a1 a2 = case a1 `compare` a2 of
359− LT -> false
360− _ -> true
361−
362− unsafeCompare :: forall a. a -> a -> Ordering
363− unsafeCompare = unsafeCompareImpl LT EQ GT
364−
365− foreign import unsafeCompareImpl :: forall a. Ordering -> Ordering -> Ordering -> a -> a -> Ordering
366−
367− class (Ord a) <= Bounded a where
368− top :: a
369− bottom :: a
370−
371− instance boundedBoolean :: Bounded Boolean where
372− top = true
373− bottom = false
374−
375− instance boundedUnit :: Bounded Unit where
376− top = unit
377− bottom = unit
378−
379− instance boundedOrdering :: Bounded Ordering where
380− top = GT
381− bottom = LT
382−
383− class (Ord a) <= Lattice a where
384− sup :: a -> a -> a
385− inf :: a -> a -> a
386−
387− instance latticeBoolean :: Lattice Boolean where
388− sup = boolOr
389− inf = boolAnd
390−
391− instance latticeUnit :: Lattice Unit where
392− sup _ _ = unit
393− inf _ _ = unit
394−
395− infixr 2 ||
396− infixr 3 &&
397−
398− (||) :: forall a. (Lattice a) => a -> a -> a
399− (||) = sup
400−
401− (&&) :: forall a. (Lattice a) => a -> a -> a
402− (&&) = inf
403−
404− class (Bounded a, Lattice a) <= BoundedLattice a
405−
406− instance boundedLatticeBoolean :: BoundedLattice Boolean
407−
408− instance boundedLatticeUnit :: BoundedLattice Unit
409−
410− class (BoundedLattice a) <= ComplementedLattice a where
411− not :: a -> a
412−
413− instance complementedLatticeBoolean :: ComplementedLattice Boolean where
414− not = boolNot
415−
416− instance complementedLatticeUnit :: ComplementedLattice Unit where
417− not _ = unit
418−
419− class (Lattice a) <= DistributiveLattice a
420−
421− instance distributiveLatticeBoolean :: DistributiveLattice Boolean
422−
423− instance distributiveLatticeUnit :: DistributiveLattice Unit
424−
425− class (ComplementedLattice a, DistributiveLattice a) <= BooleanAlgebra a
426−
427− instance booleanAlgebraBoolean :: BooleanAlgebra Boolean
428−
429− instance booleanAlgebraUnit :: BooleanAlgebra Unit
430−
431− foreign import boolOr :: Boolean -> Boolean -> Boolean
432−
433− foreign import boolAnd :: Boolean -> Boolean -> Boolean
434−
435− foreign import boolNot :: Boolean -> Boolean
436−
437− class Show a where
438− show :: a -> String
439−
440− instance showBoolean :: Show Boolean where
441− show true = "true"
442− show false = "false"
443−
444− instance showNumber :: Show Number where
445− show = showNumberImpl
446−
447− instance showString :: Show String where
448− show = showStringImpl
449−
450− instance showUnit :: Show Unit where
451− show _ = "unit"
452−
453− instance showArray :: (Show a) => Show (Array a) where
454− show = showArrayImpl show
455−
456− instance showOrdering :: Show Ordering where
457− show LT = "LT"
458− show GT = "GT"
459− show EQ = "EQ"
460−
461− foreign import showNumberImpl :: Number -> String
462−
463− foreign import showStringImpl :: String -> String
464−
465− foreign import showArrayImpl :: forall a. (a -> String) -> Array a -> String
466−
467−module Data.Function where
468−
469− import Prelude
470−
471− on :: forall a b c. (b -> b -> c) -> (a -> b) -> a -> a -> c
472− on f g x y = g x `f` g y
473−
474− foreign import data Fn0 :: * -> *
475−
476− foreign import data Fn1 :: * -> * -> *
477−
478− foreign import data Fn2 :: * -> * -> * -> *
479−
480− foreign import data Fn3 :: * -> * -> * -> * -> *
481−
482− foreign import data Fn4 :: * -> * -> * -> * -> * -> *
483−
484− foreign import data Fn5 :: * -> * -> * -> * -> * -> * -> *
485−
486− foreign import data Fn6 :: * -> * -> * -> * -> * -> * -> * -> *
487−
488− foreign import data Fn7 :: * -> * -> * -> * -> * -> * -> * -> * -> *
489−
490− foreign import data Fn8 :: * -> * -> * -> * -> * -> * -> * -> * -> * -> *
491−
492− foreign import data Fn9 :: * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> *
493−
494− foreign import data Fn10 :: * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> *
495−
496− foreign import mkFn0 :: forall a. (Unit -> a) -> Fn0 a
497−
498− foreign import mkFn1 :: forall a b. (a -> b) -> Fn1 a b
499−
500− foreign import mkFn2 :: forall a b c. (a -> b -> c) -> Fn2 a b c
501−
502− foreign import mkFn3 :: forall a b c d. (a -> b -> c -> d) -> Fn3 a b c d
503−
504− foreign import mkFn4 :: forall a b c d e. (a -> b -> c -> d -> e) -> Fn4 a b c d e
505−
506− foreign import mkFn5 :: forall a b c d e f. (a -> b -> c -> d -> e -> f) -> Fn5 a b c d e f
507−
508− foreign import mkFn6 :: forall a b c d e f g. (a -> b -> c -> d -> e -> f -> g) -> Fn6 a b c d e f g
509−
510− foreign import mkFn7 :: forall a b c d e f g h. (a -> b -> c -> d -> e -> f -> g -> h) -> Fn7 a b c d e f g h
511−
512− foreign import mkFn8 :: forall a b c d e f g h i. (a -> b -> c -> d -> e -> f -> g -> h -> i) -> Fn8 a b c d e f g h i
513−
514− foreign import mkFn9 :: forall a b c d e f g h i j. (a -> b -> c -> d -> e -> f -> g -> h -> i -> j) -> Fn9 a b c d e f g h i j
515−
516− foreign import mkFn10 :: forall a b c d e f g h i j k. (a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k) -> Fn10 a b c d e f g h i j k
517−
518− foreign import runFn0 :: forall a. Fn0 a -> a
519−
520− foreign import runFn1 :: forall a b. Fn1 a b -> a -> b
521−
522− foreign import runFn2 :: forall a b c. Fn2 a b c -> a -> b -> c
523−
524− foreign import runFn3 :: forall a b c d. Fn3 a b c d -> a -> b -> c -> d
525−
526− foreign import runFn4 :: forall a b c d e. Fn4 a b c d e -> a -> b -> c -> d -> e
527−
528− foreign import runFn5 :: forall a b c d e f. Fn5 a b c d e f -> a -> b -> c -> d -> e -> f
529−
530− foreign import runFn6 :: forall a b c d e f g. Fn6 a b c d e f g -> a -> b -> c -> d -> e -> f -> g
531−
532− foreign import runFn7 :: forall a b c d e f g h. Fn7 a b c d e f g h -> a -> b -> c -> d -> e -> f -> g -> h
533−
534− foreign import runFn8 :: forall a b c d e f g h i. Fn8 a b c d e f g h i -> a -> b -> c -> d -> e -> f -> g -> h -> i
535−
536− foreign import runFn9 :: forall a b c d e f g h i j. Fn9 a b c d e f g h i j -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j
537−
538− foreign import runFn10 :: forall a b c d e f g h i j k. Fn10 a b c d e f g h i j k -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k
539−
540−module Assert where
541−
542− import Prelude
543− import Control.Monad.Eff
544−
545− foreign import data Assert :: !
546−
547− foreign import error :: forall a. String -> a
548−
549− foreign import assertPartial :: forall e a. (Unit -> a) -> Eff (assert :: Assert | e) Unit
550−
551− assert :: forall e. Boolean -> Eff (assert :: Assert | e) Unit
552− assert true = return unit
553− assert false = error "Assertion failed!"
554−
555−module Prelude.Unsafe where
556−
557− foreign import unsafeIndex :: forall a. Array a -> Number -> a
558−
559−module Control.Monad.Eff
560− ( Eff()
561− , Pure()
562− , runPure
563− , untilE, whileE
564− ) where
565−
566− import Prelude
567−
568− foreign import data Eff :: # ! -> * -> *
569−
570− foreign import returnE :: forall e a. a -> Eff e a
571−
572− foreign import bindE :: forall e a b. Eff e a -> (a -> Eff e b) -> Eff e b
573−
574− type Pure a = forall e. Eff e a
575−
576− foreign import runPure :: forall a. Pure a -> a
577−
578− instance functorEff :: Functor (Eff e) where
579− (<$>) = liftA1
580−
581− instance applyEff :: Apply (Eff e) where
582− (<*>) = ap
583−
584− instance applicativeEff :: Applicative (Eff e) where
585− pure = returnE
586−
587− instance bindEff :: Bind (Eff e) where
588− (>>=) = bindE
589−
590− instance monadEff :: Monad (Eff e)
591−
592− foreign import untilE :: forall e. Eff e Boolean -> Eff e Unit
593−
594− foreign import whileE :: forall e a. Eff e Boolean -> Eff e a -> Eff e Unit
595−
596−module Debug.Trace where
597−
598− import Prelude
599− import Control.Monad.Eff
600−
601− foreign import data Trace :: !
602−
603− foreign import trace :: forall r. String -> Eff (trace :: Trace | r) Unit
604−
605− print :: forall a r. (Show a) => a -> Eff (trace :: Trace | r) Unit
606− print o = trace (show o)
607−
608−module Control.Monad.ST where
609−
610− import Prelude
611− import Control.Monad.Eff
612−
613− foreign import data ST :: * -> !
614−
615− foreign import data STRef :: * -> * -> *
616−
617− foreign import newSTRef :: forall a h r. a -> Eff (st :: ST h | r) (STRef h a)
618−
619− foreign import readSTRef :: forall a h r. STRef h a -> Eff (st :: ST h | r) a
620−
621− foreign import modifySTRef :: forall a h r. STRef h a -> (a -> a) -> Eff (st :: ST h | r) a
622−
623− foreign import writeSTRef :: forall a h r. STRef h a -> a -> Eff (st :: ST h | r) a
624−
625− foreign import runST :: forall a r. (forall h. Eff (st :: ST h | r) a) -> Eff r a
626−
627− pureST :: forall a. (forall h r. Eff (st :: ST h | r) a) -> a
628− pureST st = runPure (runST st)
tests/prelude/js/Assert.jsdeleted−19
@@ -1,19 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Assert
5−
6−exports.error = function(msg) {
7− throw msg;
8−};
9−
10−exports.assertPartial = function(f) {
11− return function() {
12− try {
13− return f();
14− } catch (e) {
15− if (e instanceof Error) return;
16− throw new Error('Pattern match failure is not Error');
17− }
18− };
19−};
tests/prelude/js/Control.Monad.Eff.jsdeleted−40
@@ -1,40 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Control.Monad.Eff
5−
6−exports.returnE = function (a) {
7− return function () {
8− return a;
9− };
10−};
11−
12−exports.bindE = function (a) {
13− return function (f) {
14− return function () {
15− return f(a())();
16− };
17− };
18−};
19−
20−exports.runPure = function (f) {
21− return f();
22−};
23−
24−exports.untilE = function (f) {
25− return function () {
26− while (!f());
27− return {};
28− };
29−};
30−
31−exports.whileE = function (f) {
32− return function (a) {
33− return function () {
34− while (f()) {
35− a();
36− }
37− return {};
38− };
39− };
40−};
tests/prelude/js/Control.Monad.ST.jsdeleted−38
@@ -1,38 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Control.Monad.ST
5−
6−exports.newSTRef = function (val) {
7− return function () {
8− return { value: val };
9− };
10−};
11−
12−exports.readSTRef = function (ref) {
13− return function () {
14− return ref.value;
15− };
16−};
17−
18−exports.modifySTRef = function (ref) {
19− return function (f) {
20− return function () {
21− /* jshint boss: true */
22− return ref.value = f(ref.value);
23− };
24− };
25−};
26−
27−exports.writeSTRef = function (ref) {
28− return function (a) {
29− return function () {
30− /* jshint boss: true */
31− return ref.value = a;
32− };
33− };
34−};
35−
36−exports.runST = function (f) {
37− return f;
38−};
tests/prelude/js/Data.Function.jsdeleted−233
@@ -1,233 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Data.Function
5−
6−exports.mkFn0 = function (fn) {
7− return function () {
8− return fn({});
9− };
10−};
11−
12−exports.mkFn1 = function (fn) {
13− return function (a) {
14− return fn(a);
15− };
16−};
17−
18−exports.mkFn2 = function (fn) {
19− /* jshint maxparams: 2 */
20− return function (a, b) {
21− return fn(a)(b);
22− };
23−};
24−
25−exports.mkFn3 = function (fn) {
26− /* jshint maxparams: 3 */
27− return function (a, b, c) {
28− return fn(a)(b)(c);
29− };
30−};
31−
32−exports.mkFn4 = function (fn) {
33− /* jshint maxparams: 4 */
34− return function (a, b, c, d) {
35− return fn(a)(b)(c)(d);
36− };
37−};
38−
39−exports.mkFn5 = function (fn) {
40− /* jshint maxparams: 5 */
41− return function (a, b, c, d, e) {
42− return fn(a)(b)(c)(d)(e);
43− };
44−};
45−
46−exports.mkFn6 = function (fn) {
47− /* jshint maxparams: 6 */
48− return function (a, b, c, d, e, f) {
49− return fn(a)(b)(c)(d)(e)(f);
50− };
51−};
52−
53−exports.mkFn7 = function (fn) {
54− /* jshint maxparams: 7 */
55− return function (a, b, c, d, e, f, g) {
56− return fn(a)(b)(c)(d)(e)(f)(g);
57− };
58−};
59−
60−exports.mkFn8 = function (fn) {
61− /* jshint maxparams: 8 */
62− return function (a, b, c, d, e, f, g, h) {
63− return fn(a)(b)(c)(d)(e)(f)(g)(h);
64− };
65−};
66−
67−exports.mkFn9 = function (fn) {
68− /* jshint maxparams: 9 */
69− return function (a, b, c, d, e, f, g, h, i) {
70− return fn(a)(b)(c)(d)(e)(f)(g)(h)(i);
71− };
72−};
73−
74−exports.mkFn10 = function (fn) {
75− /* jshint maxparams: 10 */
76− return function (a, b, c, d, e, f, g, h, i, j) {
77− return fn(a)(b)(c)(d)(e)(f)(g)(h)(i)(j);
78− };
79−};
80−
81−exports.runFn0 = function (fn) {
82− return fn();
83−};
84−
85−exports.runFn1 = function (fn) {
86− return function (a) {
87− return fn(a);
88− };
89−};
90−
91−exports.runFn2 = function (fn) {
92− return function (a) {
93− return function (b) {
94− return fn(a, b);
95− };
96− };
97−};
98−
99−exports.runFn3 = function (fn) {
100− return function (a) {
101− return function (b) {
102− return function (c) {
103− return fn(a, b, c);
104− };
105− };
106− };
107−};
108−
109−exports.runFn4 = function (fn) {
110− return function (a) {
111− return function (b) {
112− return function (c) {
113− return function (d) {
114− return fn(a, b, c, d);
115− };
116− };
117− };
118− };
119−};
120−
121−exports.runFn5 = function (fn) {
122− return function (a) {
123− return function (b) {
124− return function (c) {
125− return function (d) {
126− return function (e) {
127− return fn(a, b, c, d, e);
128− };
129− };
130− };
131− };
132− };
133−};
134−
135−exports.runFn6 = function (fn) {
136− return function (a) {
137− return function (b) {
138− return function (c) {
139− return function (d) {
140− return function (e) {
141− return function (f) {
142− return fn(a, b, c, d, e, f);
143− };
144− };
145− };
146− };
147− };
148− };
149−};
150−
151−exports.runFn7 = function (fn) {
152− return function (a) {
153− return function (b) {
154− return function (c) {
155− return function (d) {
156− return function (e) {
157− return function (f) {
158− return function (g) {
159− return fn(a, b, c, d, e, f, g);
160− };
161− };
162− };
163− };
164− };
165− };
166− };
167−};
168−
169−exports.runFn8 = function (fn) {
170− return function (a) {
171− return function (b) {
172− return function (c) {
173− return function (d) {
174− return function (e) {
175− return function (f) {
176− return function (g) {
177− return function (h) {
178− return fn(a, b, c, d, e, f, g, h);
179− };
180− };
181− };
182− };
183− };
184− };
185− };
186− };
187−};
188−
189−exports.runFn9 = function (fn) {
190− return function (a) {
191− return function (b) {
192− return function (c) {
193− return function (d) {
194− return function (e) {
195− return function (f) {
196− return function (g) {
197− return function (h) {
198− return function (i) {
199− return fn(a, b, c, d, e, f, g, h, i);
200− };
201− };
202− };
203− };
204− };
205− };
206− };
207− };
208− };
209−};
210−
211−exports.runFn10 = function (fn) {
212− return function (a) {
213− return function (b) {
214− return function (c) {
215− return function (d) {
216− return function (e) {
217− return function (f) {
218− return function (g) {
219− return function (h) {
220− return function (i) {
221− return function (j) {
222− return fn(a, b, c, d, e, f, g, h, i, j);
223− };
224− };
225− };
226− };
227− };
228− };
229− };
230− };
231− };
232− };
233−};
tests/prelude/js/Debug.Trace.jsdeleted−11
@@ -1,11 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Debug.Trace
5−
6−exports.trace = function(s) {
7− return function() {
8− console.log(s);
9− return {};
10− };
11−};
tests/prelude/js/Prelude.Unsafe.jsdeleted−10
@@ -1,10 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Prelude.Unsafe
5−
6−exports.unsafeIndex = function(xs) {
7− return function(n) {
8− return xs[n];
9− };
10−};
tests/prelude/js/Prelude.jsdeleted−150
@@ -1,150 +0,0 @@
1−/* global exports */
2−"use strict";
3−
4−// module Prelude
5−
6−exports.cons = function(e) {
7− return function(l) {
8− return [e].concat(l);
9− };
10−};
11−
12−exports.concat = function(l1) {
13− return function(l2) {
14− return l1.concat(l2);
15− };
16−};
17−
18−exports.length = function(a) {
19− return a.length;
20−};
21−
22−exports.concatString = function(s1) {
23− return function(s2) {
24− return s1 + s2;
25− };
26−};
27−
28−exports.numAdd = function (n1) {
29− return function (n2) {
30− return n1 + n2;
31− };
32−};
33−
34−exports.numMul = function (n1) {
35− return function (n2) {
36− return n1 * n2;
37− };
38−};
39−
40−exports.numDiv = function (n1) {
41− return function (n2) {
42− return n1 / n2;
43− };
44−};
45−
46−exports.numSub = function (n1) {
47− return function (n2) {
48− return n1 - n2;
49− };
50−};
51−
52−exports.jsMod = function(x) {
53− return function (y) {
54− return x % y;
55− };
56−};
57−
58−exports.refEq = function(r1) {
59− return function(r2) {
60− return r1 === r2;
61− };
62−};
63−
64−exports.refIneq = function(r1) {
65− return function(r2) {
66− return r1 !== r2;
67− };
68−};
69−
70−exports.eqArrayImpl = function(f) {
71− return function(xs) {
72− return function(ys) {
73− if (xs.length !== ys.length) return false;
74− for (var i = 0; i < xs.length; i++) {
75− if (!f(xs[i])(ys[i])) return false;
76− }
77− return true;
78− };
79− };
80−};
81−
82−exports.ordArrayImpl = function(f) {
83− return function (xs) {
84− return function (ys) {
85− var i = 0;
86− while (i < xs.length && i < ys.length) {
87− var x = xs[i];
88− var y = ys[i];
89− var o = f(x)(y);
90− if (o !== 0) {
91− return o;
92− }
93− }
94− if (xs.length == ys.length) {
95− return 0;
96− } else if (xs.length > ys.length) {
97− return 1;
98− } else {
99− return -1;
100− }
101− };
102− };
103−};
104−
105−exports.unsafeCompareImpl = function(lt) {
106− return function(eq) {
107− return function(gt) {
108− return function(x) {
109− return function(y) {
110− return x < y ? lt : x > y ? gt : eq;
111− };
112− };
113− };
114− };
115−};
116−
117−exports.boolOr = function (b1) {
118− return function (b2) {
119− return b1 || b2;
120− };
121−};
122−
123−exports.boolAnd = function (b1) {
124− return function (b2) {
125− return b1 && b2;
126− };
127−};
128−
129−exports.boolNot = function (b) {
130− return !b;
131−};
132−
133−exports.showNumberImpl = function (n) {
134− /* jshint bitwise: false */
135− return n === (n | 0) ? n + ".0" : n.toString();
136−};
137−
138−exports.showStringImpl = function (s) {
139− return JSON.stringify(s);
140−};
141−
142−exports.showArrayImpl = function (f) {
143− return function (xs) {
144− var ss = [];
145− for (var i = 0, l = xs.length; i < l; i++) {
146− ss[i] = f(xs[i]);
147− }
148− return "[" + ss.join(",") + "]";
149− };
150−};
tests/support/.gitignorenew file+2
@@ -0,0 +1,2 @@
1+node_modules/
2+bower_components/
tests/support/bower.jsonnew file+11
@@ -0,0 +1,11 @@
1+{
2+ "name": "purescript-test-suite-support",
3+ "dependencies": {
4+ "purescript-eff": "0.1.0",
5+ "purescript-prelude": "0.1.1",
6+ "purescript-assert": "0.1.1",
7+ "purescript-st": "0.1.0",
8+ "purescript-console": "0.1.0",
9+ "purescript-functions": "0.1.0"
10+ }
11+}
tests/support/package.jsonnew file+7
@@ -0,0 +1,7 @@
1+{
2+ "private": true,
3+ "dependencies": {
4+ "bower": "^1.4.1",
5+ "glob": "^5.0.14"
6+ }
7+}
tests/support/setup.jsnew file+22
@@ -0,0 +1,22 @@
1+var glob = require("glob");
2+var fs = require("fs");
3+
4+try {
5+ fs.mkdirSync("./flattened");
6+} catch(e) {
7+ // ignore the error if it already exists
8+ if (e.code !== "EEXIST") {
9+ throw(e);
10+ }
11+}
12+
13+glob("bower_components/*/src/**/*.{js,purs}", function(err, files) {
14+ if (err) throw err;
15+ files.forEach(function(file) {
16+ // We join with "-" because Cabal is weird about file extensions.
17+ var dest = "./flattened/" + file.split("/").slice(3).join("-");
18+ console.log("Copying " + file + " to " + dest);
19+ var content = fs.readFileSync(file, "utf-8");
20+ fs.writeFileSync(dest, content, "utf-8");
21+ });
22+})
travis-after-script.shdeleted−21
@@ -1,21 +0,0 @@
1−set -e
2−
3−pushd core-tests/
4−
5−./test-everything.sh
6−
7−popd
8−
9−if [ -z $( git describe --tags --exact-match 2>/dev/null ) ]
10−then
11− cabal install hpc-coveralls
12− case "$SUITE" in
13− "tests")
14− hpc-coveralls --exclude-dir=dist/build/autogen --exclude-dir=tests tests;;
15− "psci-tests")
16− hpc-coveralls --exclude-dir=dist/build/autogen --exclude-dir=src --exclude-dir=psci/tests psci-tests;;
17− *)
18− echo "unrecognised test suite $SUITE"
19− exit 1;;
20− esac
21−fi
travis-script.shdeleted−17
@@ -1,17 +0,0 @@
1−set -e
2−
3−if [ -z $( git describe --tags --exact-match 2>/dev/null ) ]
4−then
5− cabal configure --enable-tests --enable-coverage -v2
6−else
7− cabal configure --enable-tests -v2
8−fi
9−
10−cabal build
11−cabal test
12−
13−# Check that a source distribution can be successfully generated, and that
14−# the generated source distribution can be installed
15−cabal sdist
16−SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&
17− (cd dist && cabal install --force-reinstalls "$SRC_TGZ")
travis/after.shnew file+25
@@ -0,0 +1,25 @@
1+set -e
2+
3+pushd core-tests/
4+./test-everything.sh
5+popd
6+
7+if ! git describe --tags --exact-match >/dev/null 2>/dev/null && [ -n "$COVERAGE_SUITE" ]
8+then
9+ case "$COVERAGE_SUITE" in
10+ "tests")
11+ ./.cabal-sandbox/bin/hpc-coveralls \
12+ --exclude-dir=dist/build/autogen \
13+ --exclude-dir=tests \
14+ tests;;
15+ "psci-tests")
16+ ./.cabal-sandbox/bin/hpc-coveralls \
17+ --exclude-dir=dist/build/autogen \
18+ --exclude-dir=src \
19+ --exclude-dir=psci/tests \
20+ psci-tests;;
21+ *)
22+ echo "unrecognised test suite $COVERAGE_SUITE"
23+ exit 1;;
24+ esac
25+fi
travis/configure.shnew file+17
@@ -0,0 +1,17 @@
1+set -e
2+
3+configure_flags="--enable-tests -v2"
4+
5+if ! git describe --tags --exact-match >/dev/null 2>/dev/null
6+then
7+ # Not a release build
8+ configure_flags="--disable-optimization $configure_flags"
9+fi
10+
11+if [ -n "$COVERAGE_SUITE" ]
12+then
13+ configure_flags="--enable-coverage $configure_flags"
14+fi
15+
16+echo "> cabal configure $configure_flags"
17+cabal configure $configure_flags
travis/test-install.shnew file+12
@@ -0,0 +1,12 @@
1+set -e
2+
3+# Check that a source distribution can be successfully generated, and that
4+# the generated source distribution can be installed
5+cabal sdist
6+if SRC_TGZ="$PWD/dist/$(cabal info . | awk '{print $2;exit}').tar.gz"
7+then
8+ mkdir -p ../install-test
9+ cd ../install-test
10+ cabal sandbox init
11+ cabal install -j2 --ghc-options='+RTS -A32m -RTS' "$SRC_TGZ"
12+fi