git.iko.soy/rowtype-yoga/purescript-native
on 33d72eb help sign in
197 files changed+13660−2723
since splitsnapshots
unifiedsplit
.gitignore−13 .travis.yml+3 CONTRIBUTING.md+16 ChangeLog.md−3 LICENSE+16−26 README-go.md−48 README.md+10−38 RELEASE-0.2.md+85 RELEASE-0.3.md+85 RELEASE-0.4.md+60 RELEASE-0.5.md+40 Setup.hs+37−1 app/Main.hs−250 default.nix−23 docgen/Main.hs+155 docs/.gitignore+1 docs/Makefile+177 docs/source/conf.py+258 docs/source/ffi.rst+31 docs/source/index.rst+30 docs/source/intro.rst+134 docs/source/kinds.rst+21 docs/source/modules.rst+29 docs/source/patterns.rst+139 docs/source/prelude.rst+856 docs/source/syntax.rst+222 docs/source/typeclasses.rst+26 docs/source/types.rst+159 examples/.gitignore+1 examples/failing/Arrays.purs+5 examples/failing/Do.purs+8 examples/failing/Import.purs+3 examples/failing/ImportExplicit.purs+14 examples/failing/ImportExplicit2.purs+7 examples/failing/KindError.purs+3 examples/failing/MPTCs.purs+7 examples/failing/ModuleDeps.purs+7 examples/failing/MutRec.purs+5 examples/failing/MutRec2.purs+3 examples/failing/NullaryAbs.purs+3 examples/failing/Object.purs+5 examples/failing/OverlappingVars.purs+12 examples/failing/Rank2Types.purs+7 examples/failing/ReadShow.purs+7 examples/failing/Reserved.purs+4 examples/failing/SkolemEscape.purs+5 examples/failing/SkolemEscape2.purs+9 examples/failing/TypeClassInstances.purs+8 examples/failing/TypeClasses.purs+7 examples/failing/TypeClasses2.purs+15 examples/failing/TypeError.purs+5 examples/failing/TypeSynonyms.purs+5 examples/failing/TypeSynonyms2.purs+9 examples/failing/TypeSynonyms3.purs+13 examples/passing/Applicative.purs+16 examples/passing/ArrayType.purs+17 examples/passing/Arrays.purs+34 examples/passing/Auto.purs+15 examples/passing/BindersInFunctions.purs+12 examples/passing/Church.purs+18 examples/passing/Collatz.purs+18 examples/passing/Conditional.purs+9 examples/passing/Cons.purs+12 examples/passing/Console.purs+13 examples/passing/DataAndType.purs+9 examples/passing/DataImport.purs+13 examples/passing/Do.purs+49 examples/passing/Dollar.purs+16 examples/passing/DottedModules.purs+20 examples/passing/Eff.purs+27 examples/passing/EmptyDataDecls.purs+20 examples/passing/EmptyTypeClass.purs+18 examples/passing/ExternData.purs+19 examples/passing/ExternRaw.purs+15 examples/passing/FFI.purs+16 examples/passing/FunctionScope.purs+17 examples/passing/Functions.purs+17 examples/passing/Functions2.purs+17 examples/passing/Guards.purs+16 examples/passing/Import.purs+16 examples/passing/ImportExplicit.purs+14 examples/passing/InferRecFunWithConstrainedArgument.purs+8 examples/passing/JSReserved.purs+21 examples/passing/Let.purs+18 examples/passing/List.purs+10 examples/passing/MPTCs.purs+24 examples/passing/Match.purs+9 examples/passing/Math.purs+10 examples/passing/Maybe.purs+12 examples/passing/Module.purs+28 examples/passing/ModuleDeps.purs+17 examples/passing/Monad.purs+32 examples/passing/MonadState.purs+35 examples/passing/MultipleConstructorArgs.purs+28 examples/passing/MutRec.purs+21 examples/passing/NamedPatterns.purs+9 examples/passing/Nested.purs+9 examples/passing/NestedTypeSynonyms.purs+13 examples/passing/ObjectSynonym.purs+15 examples/passing/ObjectUpdate.purs+20 examples/passing/Objects.purs+20 examples/passing/OneConstructor.purs+9 examples/passing/Operators.purs+82 examples/passing/OptimizerBug.purs+11 examples/passing/Patterns.purs+30 examples/passing/Person.purs+15 examples/passing/Rank2Data.purs+31 examples/passing/Rank2Types.purs+25 examples/passing/Recursion.purs+12 examples/passing/RedefinedFixity.purs+18 examples/passing/RuntimeScopeIssue.purs+25 examples/passing/STArray.purs+23 examples/passing/TailCall.purs+20 examples/passing/Tick.purs+7 examples/passing/TopLevelCase.purs+20 examples/passing/TypeClasses.purs+69 examples/passing/TypeClassesInOrder.purs+11 examples/passing/TypeClassesWithOverlappingTypeVariables.purs+10 examples/passing/TypeDecl.purs+14 examples/passing/TypeSynonyms.purs+40 examples/passing/iota.purs+11 examples/passing/s.purs+7 package.yaml−86 prelude/README.md+758 prelude/prelude.purs+1199 prelude/tests/.gitignore+1 prelude/tests/Eff.purs+60 prelude/tests/build.sh+2 prelude/updateDocs.sh+2 psc/Main.hs+128 psci/Commands.hs+68 psci/Main.hs+323 psci/Parser.hs+92 psgo.cabal−145 purescript.cabal+115 src/CodeGen/IL.hs−321 src/CodeGen/IL/Common.hs−196 src/CodeGen/IL/Optimizer.hs−81 src/CodeGen/IL/Optimizer/Common.hs−18 src/CodeGen/IL/Optimizer/Inliner.hs−435 src/CodeGen/IL/Optimizer/MagicDo.hs−146 src/CodeGen/IL/Optimizer/TCO.hs−141 src/CodeGen/IL/Printer.hs−527 src/Data/Generics/Extras.hs+63 src/Language/PureScript.hs+78 src/Language/PureScript/CodeGen.hs+26 src/Language/PureScript/CodeGen/Common.hs+134 src/Language/PureScript/CodeGen/Externs.hs+51 src/Language/PureScript/CodeGen/JS.hs+329 src/Language/PureScript/CodeGen/JS/AST.hs+233 src/Language/PureScript/CodeGen/Monad.hs+43 src/Language/PureScript/CodeGen/Optimize.hs+472 src/Language/PureScript/DeadCodeElimination.hs+77 src/Language/PureScript/Declarations.hs+208 src/Language/PureScript/Kinds.hs+46 src/Language/PureScript/ModuleDependencies.hs+62 src/Language/PureScript/Names.hs+98 src/Language/PureScript/Options.hs+58 src/Language/PureScript/Parser.hs+35 src/Language/PureScript/Parser/Common.hs+370 src/Language/PureScript/Parser/Declarations.hs+150 src/Language/PureScript/Parser/Kinds.hs+45 src/Language/PureScript/Parser/State.hs+30 src/Language/PureScript/Parser/Types.hs+125 src/Language/PureScript/Parser/Values.hs+245 src/Language/PureScript/Pretty.hs+32 src/Language/PureScript/Pretty/Common.hs+22 src/Language/PureScript/Pretty/JS.hs+253 src/Language/PureScript/Pretty/Kinds.hs+60 src/Language/PureScript/Pretty/Types.hs+98 src/Language/PureScript/Pretty/Values.hs+149 src/Language/PureScript/Scope.hs+61 src/Language/PureScript/Sugar.hs+57 src/Language/PureScript/Sugar/BindingGroups.hs+121 src/Language/PureScript/Sugar/CaseDeclarations.hs+83 src/Language/PureScript/Sugar/DoNotation.hs+62 src/Language/PureScript/Sugar/Let.hs+32 src/Language/PureScript/Sugar/Names.hs+239 src/Language/PureScript/Sugar/Operators.hs+118 src/Language/PureScript/Sugar/TypeClasses.hs+184 src/Language/PureScript/Sugar/TypeDeclarations.hs+43 src/Language/PureScript/TypeChecker.hs+222 src/Language/PureScript/TypeChecker/Kinds.hs+166 src/Language/PureScript/TypeChecker/Monad.hs+281 src/Language/PureScript/TypeChecker/Synonyms.hs+60 src/Language/PureScript/TypeChecker/Types.hs+953 src/Language/PureScript/Types.hs+223 src/Language/PureScript/Values.hs+217 src/Tests.hs−141 stack.nix−23 stack.yaml−24 support/ffi-loader.go−30 support/go.mod.ffi-loader−2 support/go.mod.output−2 support/go.mod.working−1 test/Spec.hs−2 tests/Main.hs+99
.gitignore−13
@@ -8,16 +8,3 @@ cabal.sandbox.config
88*.chs.h
99*.lksh*
1010.virthualenv
11−.psci_modules/
12−.test_modules/
13−bower_components/
14−node_modules
15−tmp/
16−.stack-work/
17−stack.yaml.lock
18−output
19−examples/docs/docs/
20−core-tests/full-core-docs.md
21−.psc-ide-port
22−.vscode/
23−result
.travis.ymlnew file+3
@@ -0,0 +1,3 @@
1+language: haskell
2+notifications:
3+ email: true
CONTRIBUTING.mdnew file+16
@@ -0,0 +1,16 @@
1+Pull requests are encouraged.
2+
3+Please follow the following guidelines:
4+
5+- Add at least a test to `examples/passing/` and possibly to `examples/failing`.
6+- Build the binaries and libs with `cabal build`
7+- Install the binaries and libs with `cabal install`.
8+- Run `cabal test` to build the test suite.
9+- Run `./execTests.sh` to execute the test suite.
10+- Please run `hlint`.
11+
12+If you would like to contribute, please consider the issues in the current milestone first.
13+
14+Send me (`paf31`) a message if you have any implementation questions, I'm more than happy to talk about the design, and I'm more than willing to redesign parts if necessary.
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.
ChangeLog.mddeleted−3
@@ -1,3 +0,0 @@
1−# Changelog for pscpp
2−
3−## Unreleased changes
LICENSE+16−26
@@ -1,30 +1,20 @@
1−Copyright Andy Arvanitis (c) 2018
1+The MIT License (MIT)
22
3−All rights reserved.
3+Copyright (c) 2013 Phil Freeman
44
5−Redistribution and use in source and binary forms, with or without
6−modification, are permitted provided that the following conditions are met:
5+Permission is hereby granted, free of charge, to any person obtaining a copy of
6+this software and associated documentation files (the "Software"), to deal in
7+the Software without restriction, including without limitation the rights to
8+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+the Software, and to permit persons to whom the Software is furnished to do so,
10+subject to the following conditions:
711
8− * Redistributions of source code must retain the above copyright
9− notice, this list of conditions and the following disclaimer.
12+The above copyright notice and this permission notice shall be included in all
13+copies or substantial portions of the Software.
1014
11− * Redistributions in binary form must reproduce the above
12− copyright notice, this list of conditions and the following
13− disclaimer in the documentation and/or other materials provided
14− with the distribution.
15−
16− * Neither the name of Author name here nor the names of other
17− contributors may be used to endorse or promote products derived
18− from this software without specific prior written permission.
19−
20−THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21−"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22−LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23−A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24−OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25−SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26−LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27−DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28−THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29−(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30−OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
README-go.mddeleted−48
@@ -1,48 +0,0 @@
1−
2−### psgo
3−
4−#### Performance
5−
6−* No runtime system beyond some support types and functions
7−* Uses PureScript's normal tail call optimization techniques for generated Go code
8−
9−#### Differences from PureScript:
10−
11−* Foreign imports/exports are Go instead of JavaScript – see [standard library foreign implementations](https://github.com/andyarvanitis/purescript-native-go-ffi)
12−* No Go-specific REPL
13−
14−#### Other notes:
15−
16−* The provided `Any` type is just an alias for `interface{}`
17−* PureScript types are represented in Go with:
18−
19− | PureScript | Go |
20− |------------|----|
21− |`Array` | `[]Any`|
22− |`String` | `string`|
23− |`Number` | `float64`|
24− |`Int` | `int`|
25− |`Char` | `string` (single UTF-8 entity)|
26− |`Boolean` | `bool`|
27− |Records | `map[string]Any`|
28−
29−#### Future ideas:
30−
31−* Nice facilities (modules) for concurrency/parallelism, using goroutines
32−
33−
34−#### Getting Started
35−This assumes you are running macOS (OS X) or a Unix-like system (Linux, *BSD, etc.).
36−
37−1. Choose a working directory wherever you like. Then create a `src` subdirectory under it, which will be where you will place your own PureScript source files.
38−
39−1. Initialize your project with `spago init`, and install any dependencies with `spago install` (please see their instructions if you haven't used it before).
40−
41−1. Add the `backend = "psgo"` option to your `spago.dhall` file. That way `spago` will use the psgo backend when compiling.
42−
43−1. You should now be ready to build a PureScript program:
44− * As stated above, place your source file(s) in the working directory's `src` subdirectory and execute `spago build`.
45−
46− * This will generate the Go source tree for your program and then build an executable binary. The resulting executable will be in your working directory and will be named `Main`. The generated source files will be under `output/`.
47−
48−---
README.md+10−38
@@ -1,41 +1,13 @@
1−[![PureScript](https://raw.githubusercontent.com/purescript/purescript/master/logo.png)](http://purescript.org)
1+[![Build Status](https://secure.travis-ci.org/purescript/purescript.png?branch=master)](http://travis-ci.org/purescript/purescript)
2+[![Hackage](https://budueba.com/hackage/purescript)](http://hackage.haskell.org/package/purescript)
23
3−This is a platform-native compiler backend for [PureScript](https://github.com/purescript/purescript). It attempts to generate "sane", debuggable, and portable [C++11](https://isocpp.org/wiki/faq/cpp11) (or later) or [Go](https://golang.org/) code as an intermediate language, which is then compiled to a native executable binary. This also enables easy interoperability with existing C/C++ or Go frameworks and libraries on a number of platforms.
4+PureScript is a small strongly, statically typed programming language with expressive types, written in and inspired by Haskell, and compiling to Javascript.
45
5−There are two utilities in the purescript-native "suite": `pscpp` and `psgo`. The source code in this branch is for `psgo`, the purescript-to-Go transpiler. For the source code of the `pscpp` purescript-to-C++ transpiler, please see the [cpp branch](https://github.com/andyarvanitis/purescript-native/tree/cpp).
6+## Resources
67
7−#### Platforms
8−* Although purescript-native should work on any platform supporting PureScript and modern C++ or Go, the generated code and resulting binary executables have been tested on:
9− * macOS Mojave 10.14.5 – full test suite
10− * For C++, Xcode 10.2.1's `clang` was used
11− * For Go, `go` version 1.12.7 was used
12− * Windows 10 x64 – full test suite
13− * C++: Visual Studio 2017 and `clang`
14− * Go: `go` version 1.12.7
15− * Linux Debian 9.5 amd64 – full test suite (C++)
16− * Default versions of `clang` and `gcc`
17− * Linux Debian 10 amd64 – full test suite (Go)
18− * Default version of `go`
19− * Raspberry Pi 3 B+ Raspbian official build (ARM), default versions of `clang` and `gcc`
20−
21−
22−#### Requirements for building `pscpp` and `psgo`
23−
24−* [Haskell Stack](https://docs.haskellstack.org/en/stable/README/) (if you're running macOS 10.14.5+, you can use pre-built binaries from [here](https://github.com/andyarvanitis/purescript-native/releases/))
25−
26−#### Requirements for using PureScript + purescript-native
27−
28−* A recent version (0.13+) of [purescript](https://github.com/purescript/purescript/releases).
29−
30−* For `pscpp`, a C++11-capable toolchain, e.g. recent versions of clang, gcc, Microsoft Visual Studio
31− * GNU Make + `psc-package` is the default supported build tool, but you should be able to use your favorite package manager, C++ build system, tools, debuggers, etc.
32−* For `psgo`, the [Go toolchain](https://golang.org) for your system
33− * You can use your favorite PureScript package manager and build tools – but for simplicity, [`spago`](https://github.com/spacchetti/spago) is recommended.
34−
35−
36−#### For more information and a Getting Started guide, please see
37−* [`pscpp`](https://github.com/andyarvanitis/purescript-native/blob/cpp/README-cpp.md)
38−* [`psgo`](https://github.com/andyarvanitis/purescript-native/blob/golang/README-go.md)
39−
40−
41−---
8+- [Documentation](http://purescript.readthedocs.org/)
9+- [#purescript IRC @ FreeNode](irc://irc.freenode.net/#purescript)
10+- [Twitter](http://twitter.com/purescript)
11+- [Try PureScript!](http://tryps.functorial.com/)
12+- [Release Notes](https://github.com/purescript/purescript/blob/master/RELEASE.md)
13+- [Contributing to PureScript](https://github.com/purescript/purescript/blob/master/CONTRIBUTING.md)
RELEASE-0.2.mdnew file+85
@@ -0,0 +1,85 @@
1+## 0.2.0 Changes
2+
3+Many thanks to the [contributors](https://github.com/purescript/purescript/graphs/contributors) who helped with this release.
4+
5+- Full language guide can be found [here](http://functorial.com/purescript).
6+- Try out the latest features [here](http://tryps.functorial.com).
7+
8+### New Features
9+
10+- RankNTypes
11+
12+ This experimental feature allows polymorphic types (introduced with `forall`) to appear on the left of a function arrow, or as the type of a record field, etc. For example:
13+
14+ rank2 :: (forall a. a -> a) -> Number
15+ rank2 = \f -> if f true then f 1 else f 2
16+
17+- Modules
18+- Polymorphic Object Update
19+
20+ Records now support member update in which the type of the field changes during the update. For example:
21+
22+ data Wrap a = Wrap a
23+
24+ update = \o -> o { prop = Wrap o.prop }
25+
26+### Enhancements
27+
28+- Naked expressions as statements
29+
30+ Naked expressions of type `{}` can now be used as statements.
31+
32+- Split code generation into `AST -> JS` and `JS -> String`
33+
34+ JavaScript generation is now split into the generation of a JavaScript AST, and the pretty-printing of that AST. This enables some optimizations, and a better JavaScript pretty-printer.
35+
36+- Syntactic sugar for introducing curried functions
37+
38+ Single-argument functions and multiple-argument functions can now be introduced in the same way:
39+
40+ test = \a (b, c) d -> a + b + c + d
41+
42+- JavaScript optimizations
43+
44+ Some basic dead-variable elimination, inlining and eta-conversion are now performed on the generated JavaScript.
45+
46+- Generate formatted Javascript
47+
48+ The generated JavaScript is now formatted to be more readable. In particular, newlines get generated, and the correct indentation is used.
49+
50+- More valid infix operators
51+
52+ The colon and period characters are now valid in infix operator names.
53+
54+### Syntax Changes
55+
56+- Avoid 'do' keyword for blocks
57+
58+ `do` will be used later for Haskell-like monad comprehensions, so its previous use in introducing blocks of statements is now invalid. The `do` keyword is still reserved.
59+
60+- Member foreign import syntax
61+
62+ A small syntactic addition to the FFI, to support a common use case.
63+
64+- Make FFI syntax match Haskell
65+
66+ Use `foreign import` instead of `extern`.
67+
68+- Make record declaration syntax match Haskell
69+- Simplify array binders
70+
71+ There are now two types of array binders: cons binders `x : xs -> ...` and array binders `[x, y, z] -> ...` instead of the previously confusing `[x:xs]`.
72+
73+- Array indexing syntax is ambiguous
74+
75+ Array elements are now accessed using the `!!` operator: `arr !! 0` etc.
76+
77+### Bug Fixes
78+
79+- Allow guards access to current scope
80+
81+### Libraries
82+
83+- Prelude
84+
85+ There is now a basic prelude in the `libraries/prelude` folder.
RELEASE-0.3.mdnew file+85
@@ -0,0 +1,85 @@
1+## 0.3.0 Changes
2+
3+Many thanks to the [contributors](https://github.com/purescript/purescript/graphs/contributors) who helped with this release.
4+
5+- Full language guide can be found [here](http://functorial.com/purescript).
6+- Try out the latest features [here](http://tryps.functorial.com).
7+
8+## New Features / Enhancements
9+
10+- Mutually recursive functions and types are now allowed within a module.
11+- Syntactic sugar for patterns in top-level declarations has been added. For example:
12+
13+ sum [] = 0
14+ sum (x:xs) = x + sum xs
15+
16+- Basic support for type classes has been added. Polymorphic types of the form `forall a. (C a) => ...` will not be inferred but can be checked. Type inference still works if all type class instances can be determined. There is not yet support for functionality like GHC's `FlexibleInstances`, `FlexibleContexts` or `MultiParamTypesClasses`. For example:
17+
18+ class Truthy a where
19+ isTrue :: a -> Boolean
20+
21+ instance Truthy Boolean where
22+ isTrue b = b
23+
24+ instance Truthy String where
25+ isTrue "" = false
26+ isTrue _ = true
27+
28+ ifThenElse :: forall a b. (Truthy a) => a -> b -> b -> b
29+ ifThenElse a tr fa = if isTrue a then tr else fa
30+
31+- There is now support for `do` notation, using the `Monad` type class from the `Prelude` module. For example:
32+
33+ data Maybe = Nothing | Just a
34+
35+ instance Prelude.Monad Maybe where
36+ ret = Just
37+ (>>=) Nothing _ = Nothing
38+ (>>=) (Just a) f = f a
39+
40+ test = do
41+ x <- Just 1
42+ y <- Just 2
43+ ret $ x + y
44+
45+- There is now a better story for side-effects. The `Eff` module in the `Prelude` defines a monad `Eff e` where e is a row of effect types. The kind system now defines a new kind `!` of effects. Row polymorphism allows different native effects to be interleaved. For example:
46+
47+ test = do
48+ trace "Testing"
49+ throwError "Error!"
50+
51+ has inferred type `forall eff. Eff (trace :: Trace | error :: Error String | eff)`.
52+ See the `/examples/passing/Eff.purs` file for a more in-depth set of examples.
53+ Supported native effects currently include `ST`, `Trace`, `Error` and `DOM` (via the `libraries/jquery` module).
54+- There is a new flag `--run-main` which will check the type of the `Main.main` function and emit the call to `main();` after all other generated Javascript.
55+- The `Prelude` module is now automatically included, unless the `--no-prelude` flag is specified.
56+- The class of accepted operator names has been expanded. Specifically, `$` is now a valid operator, and is defined in the `Prelude` module.
57+- Tail calls can be eliminated using the `--tco` flag.
58+- There is basic support for checking the types of values at runtime, using the `--runtime-type-checks` flag. Right now, this only works for primitive types, and so is a work-in-progress.
59+- GHCJS/Fay-style foreign imports are now supported. An example is
60+
61+ foreign import "function(n) { \
62+ \ return function(p) {\
63+ \ return Math.pow(n, p);\
64+ \ }\
65+ \ }" pow :: Number -> Number -> Number
66+- Data constructors now get imported along with their type definitions.
67+- The `-s` flag will now cause the compiler to use `stdin` for input.
68+- There is a new executable `psci` which provides simple REPL-like functionality - it parses expressions, passes the generated Javascript to Node for execution, and prints the result. This is a work-in-progress.
69+- The JQuery example (`libraries/jquery/test`) has been improved to use the new `Eff` monad and `do` notation.
70+
71+## Regressions
72+
73+- `foreach` is no longer supported. The `Prelude` module defines `map` which should provide the same functionality.
74+- Support for naked expressions as statements has been removed.
75+
76+## Bug Fixes
77+
78+- Operator precedence rules now work across modules.
79+- A bug in which expressions involving non-qualified names did not typecheck was fixed.
80+- Trailing spaces have been removed in the generated Javascript, thanks to @utkarshkukreti.
81+- Type synonyms now work properly across modules.
82+- Module imports are not transitive, which was previously leading to some unexpected error messages.
83+- A bug which caused the optimizer to break generated Javascript for mutually recursive values was fixed.
84+- Some `Prelude` functions which called methods in the standard Javascript library have been fixed.
85+
RELEASE-0.4.mdnew file+60
@@ -0,0 +1,60 @@
1+## 0.4.0 Changes
2+
3+This release focussed mainly on bug fixes and minor enhancements, in order to provide a stable release of the compiler.
4+
5+This release saw major contributions from [a number of new contributors](https://github.com/purescript/purescript/graphs/contributors). Thank you very much to everyone who submitted pull requests, issues and suggestions, and also to the users of the #purescript FreeNode channel for their valuable feedback. As always, new contributors are always welcome!
6+
7+- The full language guide can be found [here](http://purescript.readthedocs.org).
8+- Try out the latest features [here](http://tryps.functorial.com).
9+
10+## Breaking Changes
11+
12+- Multiple argument functions are no longer available.
13+- When used in the browser, PureScript modules are now accessed through `window.PS.<ModuleName>`. The `PS` object name can be changed via the `--browser-namespace` compiler argument.
14+- The `--run-main` argument has been replaced with `--main` which can now accept a module name in which to find the `main` function.
15+
16+### New Features
17+
18+- Dead code elimination. The new compiler argument `--module=` can be used to specify one or more modules that should be kept in the generated code along with their dependencies. If no modules are specified, all code is exported.
19+
20+### Enhancements
21+
22+- The `->` and `[]` types are now usable in type class instances.
23+- The file path is included in syntax error messages.
24+- Most reserved Javascript names (`return`, `const`, etc) are now usable.
25+- Generated code for operators is more user friendly (for example, `Prelude[">>="]`). Where this transformation cannot be applied, human-readable variable names (e.g. `$greater$greater$eq`) are generated.
26+- The typechecker's function application judgement was greatly simplified, and as a result, more valid things now typecheck.
27+- Data constructors with multiple arguments can now be defined.
28+- It is no longer necessary to sort modules in order of dependencies manually.
29+- Case statements matching data constructors no longer generate unnecessary constructor checks at runtime if there is only a single data constructor.
30+- New optimizer rules were added to inline JavaScript's built-in operators.
31+
32+### Bug Fixes
33+
34+- Floats parse correctly.
35+- Using data constructors in pattern matches now works properly across modules.
36+- PureScript modules no longer overwrite global objects with the same name.
37+- Show problems with shadowing of names were fixed.
38+- Problems with recursive non-function values were fixed.
39+- Type synonyms can now expand to types containing more type synonyms.
40+- A bug in capture-avoiding type variable substitution which was affecting the `Functor (Either e)` instance was fixed.
41+- Type synonym instances are now disallowed.
42+- Precedence rules for some basic operators were corrected.
43+- A bug which allowed skolem variables to escape their scope was add (thanks to Brian McKenna).
44+- Modules containing mutually recursive type synonyms and data declarations now compile correctly.
45+- A number of bugs in the optimizer were addressed.
46+
47+### Libraries
48+
49+- The `Prelude` has been greatly expanded. Definitions for built-in JavaScript operators have been moved into the Prelude.
50+- Gary Burgess has released the [grunt-purescript library](https://github.com/purescript/grunt-purescript) to build PureScript code using Grunt.
51+- The [purescript-parsing](https://github.com/purescript/purescript-parsing) library provides Parsec-like parsing combinators.
52+- The [purescript-promises](https://github.com/purescript/purescript-promises) library provides `Monad` and `Applicative` instances for promises.
53+- The [purescript-quickcheck](https://github.com/purescript/purescript-quickcheck) library provides a very basic implementation of a QuickCheck-style testing harness.
54+- The [purescript-json](https://github.com/purescript/purescript-json) library aims to provide a safe way to consume JSON data.
55+
56+### Documentation
57+
58+- Documentation for the `Prelude` modules is now automatically generated and can be found [here](http://purescript.readthedocs.org/en/latest/prelude.html).
59+- There is now Hackage documentation.
60+- Code comments have been improved.
RELEASE-0.5.mdnew file+40
@@ -0,0 +1,40 @@
1+## 0.5.0 Changes
2+
3+## Breaking Changes
4+
5+- Support for blocks has been removed. (paf31)
6+
7+### New Features
8+
9+- `let ... in` syntax for bindings (paf31)
10+- Multi parameter typeclasses (paf31)
11+
12+### Enhancements
13+
14+- Pretty printing for row types was improved (garyb)
15+- Module names can now contain `.` (garyb)
16+- Prelude modules now follow a naming scheme similar to haskell (e.g. `Data.Maybe`, `Control.Monad`) (garyb)
17+- New optimizer rules have been added for code in the ST monad, to reproduce the functionality of the blocks feature, which has been removed (paf31)
18+- Pattern binders are now usable in lambda expression arguments (paf31)
19+- PSCI now has a `:t` command for checking the type of a value (paf31)
20+- Array pretty printing via `show` has been improved (joneshf)
21+- PSCI completions are sorted (joneshf)
22+- PSCI now has help commands (joneshf)
23+- PSCI history is in XDG config (joneshf)
24+- PSCI allows loading of modules from ~ paths (joneshf)
25+- PSCI can accept a list of modules to load on start from the command line (paf31)
26+
27+### Bug Fixes
28+
29+- The subsumes relation has been fixed for object types (paf31)
30+- `sort` no longer mutates arrays (joneshf)
31+- PSCI now evaluates expressions (joneshf)
32+- Overlapping variables in typeclass instances are rejected (paf31)
33+
34+### Libraries
35+
36+- The [purescript-date](https://github.com/purescript/purescript-date) library provides basic date/time functions
37+
38+### Documentation
39+
40+-
Setup.hs+37−1
@@ -1,2 +1,38 @@
1+{-# LANGUAGE CPP #-}
2+
3+#ifndef POSIX_LIKE
4+#define POSIX_LIKE !(defined(_WIN32_HOST_OS) || defined(_WIN64_HOST_OS)) && \
5+ (defined(unix_HOST_OS) || defined(__unix___HOST_OS) || \
6+ defined(__unix_HOST_OS) || defined(linux_HOST_OS) || \
7+ defined(__linux___HOST_OS) || defined(__linux_HOST_OS) || \
8+ (defined(__APPLE___HOST_OS) && defined(__MACH___HOST_OS)))
9+#endif
10+
11+module Main where
12+
13+import Control.Monad
14+
15+import Distribution.PackageDescription
116import Distribution.Simple
2−main = defaultMain
17+import Distribution.Simple.LocalBuildInfo
18+import Distribution.Simple.Setup
19+
20+import System.Directory
21+import System.Environment.XDG.BaseDir
22+#if POSIX_LIKE
23+import System.Posix.Files
24+#endif
25+
26+main :: IO ()
27+main = defaultMainWithHooks $ simpleUserHooks {postInst = setupXDG}
28+
29+setupXDG :: Args -> InstallFlags -> PackageDescription -> LocalBuildInfo -> IO ()
30+setupXDG _ _ _ _ = do
31+ configDir <- getUserConfigDir "purescript"
32+ configExists <- doesDirectoryExist configDir
33+ unless configExists $ do
34+ createDirectoryIfMissing True configDir
35+#if POSIX_LIKE
36+ setFileMode configDir ownerModes
37+#endif
38+#undef POSIX_LIKE
app/Main.hsdeleted−250
@@ -1,250 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE RankNTypes #-}
3−{-# LANGUAGE TemplateHaskell #-}
4−
5−module Main where
6−
7−import Control.Monad (when)
8−import qualified Control.Monad.Parallel as Par
9−import Data.Aeson
10−import Data.Aeson.Types
11−import Data.Char
12−import Data.FileEmbed (embedFile)
13−import Data.List (delete, intercalate, isPrefixOf, nub, partition, (\\))
14−import Data.Maybe
15−import Data.Monoid ((<>))
16−import Data.Version
17−import Control.Monad.Supply
18−import Control.Monad.Supply.Class
19−import Text.Printf
20−
21−import System.Environment
22−import System.Directory (createDirectoryIfMissing, doesDirectoryExist, doesFileExist, getCurrentDirectory, getModificationTime)
23−import System.FilePath ((</>), joinPath, splitDirectories, takeDirectory)
24−import System.FilePath.Find
25−import System.Process
26−
27−import Data.Text (Text)
28−import qualified Data.Text as T
29−import qualified Data.Text.Encoding as T
30−import qualified Data.Text.Lazy as L
31−import qualified Data.Text.Lazy.Encoding as L
32−import qualified Data.ByteString as B
33−
34−import Development.GitRev
35−
36−import Language.PureScript.AST.Literals
37−import Language.PureScript.CoreFn
38−import Language.PureScript.CoreFn.FromJSON
39−
40−import CodeGen.IL
41−import CodeGen.IL.Common
42−import CodeGen.IL.Printer
43−
44−import Tests
45−
46−data Command = Build | Run (Maybe String)
47−
48−parseJson :: Text -> Value
49−parseJson text
50− | Just fileJson <- decode . L.encodeUtf8 $ L.fromStrict text = fileJson
51− | otherwise = error "Bad json"
52−
53−jsonToModule :: Value -> Module Ann
54−jsonToModule value =
55− case parse moduleFromJSON value of
56− Success (_, r) -> r
57− _ -> error "Failed parsing corefn. Psgo currently supports purescript <= 0.13.8"
58−
59−splitArgs :: [String] -> ([String], Maybe String, [String])
60−splitArgs args =
61− let (opts, files) = partition (isPrefixOf "--") args
62− opts' = (map . map) toLower opts
63− (moduleName, files') =
64− if null files
65− then (Nothing, files)
66− else
67− if "--run" `elem` opts' && length (files) >= 1
68− then do
69− let file0 = head files
70− files' = tail files
71− case file0 of
72− "Main.main" -> (Just "Main", files')
73− "Test.Main.main" -> (Just "Test.Main", files')
74− _ -> (Nothing, files)
75− else (Nothing, files)
76− in (opts, moduleName, files')
77−
78−main :: IO ()
79−main = do
80− args <- getArgs
81− -- let (opts, files) = partition (isPrefixOf "--") args
82− let (opts, moduleName, files) = splitArgs args
83− opts' = (map . map) toLower opts
84− if "--tests" `elem` opts'
85− then runTests
86− else do
87− if "--help" `elem` opts' || "--version" `elem` opts'
88− then do
89− when ("--help" `elem` opts') $ do
90− putStrLn help
91− when ("--version" `elem` opts') $ do
92− let branch = $(gitBranch)
93− details | branch == "golang" = "master, commit " ++ $(gitHash)
94− | otherwise = branch
95− putStrLn $ details ++ if $(gitDirty) then " (DIRTY)" else ""
96− else do
97− if null files
98− then do
99− currentDir <- getCurrentDirectory
100− processFiles opts' [currentDir]
101− else
102− processFiles opts' files
103− if "--run" `elem` opts
104− then runBuildTool $ Run moduleName
105− else when ("--no-build" `notElem` opts) $
106− runBuildTool Build
107− return ()
108− where
109− processFiles :: [String] -> [FilePath] -> IO ()
110− processFiles opts [file] = do
111− isDir <- doesDirectoryExist file
112− if isDir then do
113− files <- find always (fileName ==? corefn) file
114− if null files
115− then errorNoCorefnFiles
116− else generateFiles opts files
117− else generateFiles opts [file]
118− processFiles opts files = do
119− generateFiles opts files
120− basePath :: [FilePath] -> FilePath
121− basePath files =
122− let filepath = takeDirectory (head files) in
123− joinPath $ (init $ splitDirectories filepath)
124− generateFiles :: [String] -> [FilePath] -> IO ()
125− generateFiles opts files = do
126− let baseOutpath = basePath files
127− writeSupportFiles baseOutpath
128− Par.mapM (generateCode opts baseOutpath) files
129− return ()
130− runBuildTool :: Command -> IO ()
131− runBuildTool cmd = do
132− project <- projectEnv
133− case cmd of
134− Build -> do
135− callProcess "go" ["build", T.unpack project </> modPrefix' </> "Main"]
136− Run moduleName -> do
137− callProcess "go" ["run", T.unpack project </> modPrefix' </> fromMaybe "Main" moduleName]
138− return ()
139−
140−generateCode :: [String] -> FilePath -> FilePath -> IO ()
141−generateCode opts baseOutpath jsonFile = do
142− jsonModTime <- getModificationTime jsonFile
143− let filepath = takeDirectory jsonFile
144− dirparts = splitDirectories $ filepath
145− mname = last dirparts
146− basedir = joinPath $ init dirparts
147− mname' = T.pack mname
148− possibleFileName = basedir </> (T.unpack mname') </> implFileName mname'
149− exists <- doesFileExist possibleFileName
150− if exists
151− then do
152− modTime <- getModificationTime possibleFileName
153− when (modTime < jsonModTime) $
154− transpile opts baseOutpath jsonFile
155− else transpile opts baseOutpath jsonFile
156−
157−transpile :: [String] -> FilePath -> FilePath -> IO ()
158−transpile opts baseOutpath jsonFile = do
159− jsonText <- T.decodeUtf8 <$> B.readFile jsonFile
160− project <- projectEnv
161− let module' = jsonToModule $ parseJson jsonText
162− ((_, foreigns, asts, implHeader, implFooter), _) <- runSupplyT 5 (moduleToIL module' project)
163− let mn = moduleNameToIL' $ moduleName module'
164− implementation = prettyPrintIL asts
165− outpath = joinPath [baseOutpath, T.unpack mn]
166− implPath = outpath </> implFileName mn
167− createDirectoryIfMissing True outpath
168− putStrLn implPath
169− B.writeFile implPath $ T.encodeUtf8 (implHeader <> implementation <> implFooter)
170−
171−writeSupportFiles :: FilePath -> IO ()
172−writeSupportFiles baseOutpath = do
173− currentDir <- getCurrentDirectory
174− let outputdir = T.pack $ baseOutpath \\ currentDir
175− ffiOutpath = currentDir </> subdir
176− createDirectoryIfMissing True baseOutpath
177− createDirectoryIfMissing True ffiOutpath
178− writeModuleFile outputdir currentDir $(embedFile "support/go.mod.working")
179− writeModuleFile outputdir baseOutpath $(embedFile "support/go.mod.output")
180− writeModuleFile outputdir ffiOutpath $(embedFile "support/go.mod.ffi-loader")
181− writeLoaderFile ffiOutpath $(embedFile "support/ffi-loader.go")
182− where
183− writeModuleFile :: Text -> FilePath -> B.ByteString -> IO ()
184− writeModuleFile outputdir path modText = do
185− let goModSource = path </> "go.mod"
186− goModSourceExists <- doesFileExist goModSource
187− when (not goModSourceExists) $ do
188− project <- projectEnv
189− let project' = T.unpack project
190− outputdir' = tail $ T.unpack outputdir
191− modText' = T.replace "$PROJECT" project $ T.decodeUtf8 modText
192− replaceLoader = project' </> ffiLoader' <> "=." </> subdir
193− replaceOutput = project' </> modPrefix' <> "=." </> outputdir'
194− B.writeFile goModSource $ T.encodeUtf8 modText'
195− callProcess "go" ["mod", "edit", "-replace", replaceLoader]
196− callProcess "go" ["mod", "edit", "-replace", replaceOutput]
197− callProcess "go" ["clean", "-modcache"]
198− writeLoaderFile :: FilePath -> B.ByteString -> IO ()
199− writeLoaderFile ffiOutpath loaderText = do
200− let loaderSource = ffiOutpath </> "ffi_loader.go"
201− loaderSourceExists <- doesFileExist loaderSource
202− when (not loaderSourceExists) $ do
203− B.writeFile loaderSource loaderText
204−
205−implFileName :: Text -> FilePath
206−implFileName mn = ((\c -> if c == '.' then '_' else c) <$> T.unpack mn) <> ".go"
207−
208−projectEnv :: IO Text
209−projectEnv = do
210− T.pack . fromMaybe defaultProject <$> lookupEnv goproject
211−
212−help :: String
213−help = "Usage: psgo OPTIONS COREFN-FILES\n\
214− \ PureScript to native (via go) compiler\n\n\
215− \Available options:\n\
216− \ --help Show this help text\n\n\
217− \ --version Show the version number\n\n\
218− \ --run Run the generated go code directly, without building an\n\
219− \ executable\n\
220− \ --no-build Generate go source files, but do not build an executable\n\
221− \ --tests Run test cases (under construction)\n\n\
222− \See also:\n\
223− \ purs compile --help\n"
224−
225−corefn :: String
226−corefn = "corefn.json"
227−
228−goSrc :: String
229−goSrc = ".go"
230−
231−goproject :: String
232−goproject = "GOPROJECT"
233−
234−defaultProject :: String
235−defaultProject = "project.localhost"
236−
237−modPrefix' :: String
238−modPrefix' = T.unpack modPrefix
239−
240−ffiLoader' :: String
241−ffiLoader' = T.unpack ffiLoader
242−
243−subdir :: String
244−subdir = T.unpack modLabel
245−
246−errorNoCorefnFiles :: IO ()
247−errorNoCorefnFiles = do
248− ioError . userError $ "no compiled purescript '" <> corefn <> "' files found –\n" <>
249− " make sure to use the '--codegen corefn' option with your purs\n" <>
250− " project build tool"
default.nixdeleted−23
@@ -1,23 +0,0 @@
1−let
2− haskellNix = import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz) {};
3− nixpkgsSrc = haskellNix.sources.nixpkgs-1903; # has hsc2hs-0.68.4
4−
5− hsc2hsOverlay = self: super: {
6− buildPackages = super.buildPackages // {
7− hsc2hs = super.haskellPackages.hsc2hs;
8− };
9− };
10−
11− nixpkgsArgs = haskellNix.nixpkgsArgs // {
12− overlays = haskellNix.nixpkgsArgs.overlays ++ [ hsc2hsOverlay ];
13− };
14−in
15−{ pkgs ? import nixpkgsSrc nixpkgsArgs
16−}:
17−
18−pkgs.haskell-nix.stackProject {
19− src = pkgs.haskell-nix.haskellLib.cleanGit {
20− name = "purescript-native";
21− src = ./.;
22− };
23−}
docgen/Main.hsnew file+155
@@ -0,0 +1,155 @@
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+module Main where
16+
17+import qualified Language.PureScript as P
18+import System.Console.CmdTheLine
19+import Control.Applicative
20+import Control.Monad
21+import Control.Monad.Writer
22+import System.Exit (exitSuccess, exitFailure)
23+import qualified System.IO.UTF8 as U
24+import qualified Paths_purescript as Paths
25+import Data.Version (showVersion)
26+import Data.List
27+import Data.Function (on)
28+
29+docgen :: FilePath -> IO ()
30+docgen input = do
31+ text <- U.readFile input
32+ case P.runIndentParser input P.parseModules text of
33+ Left err -> do
34+ U.print err
35+ exitFailure
36+ Right ms -> do
37+ U.putStrLn . runDocs $ renderModules ms
38+ exitSuccess
39+
40+type Docs = Writer [String] ()
41+
42+runDocs :: Docs -> String
43+runDocs = unlines . execWriter
44+
45+spacer :: Docs
46+spacer = tell [""]
47+
48+headerLevel :: Int -> String -> Docs
49+headerLevel level hdr = tell [replicate level '#' ++ ' ' : hdr]
50+
51+atIndent :: Int -> String -> Docs
52+atIndent indent text =
53+ let ls = lines text in
54+ forM_ ls $ \l -> tell [replicate indent ' ' ++ l]
55+
56+renderModules :: [P.Module] -> Docs
57+renderModules ms = do
58+ headerLevel 1 "Module Documentation"
59+ mapM_ renderModule ms
60+
61+renderModule :: P.Module -> Docs
62+renderModule (P.Module moduleName ds) = do
63+ headerLevel 2 $ "Module " ++ P.runModuleName moduleName
64+ spacer
65+ headerLevel 3 "Types"
66+ spacer
67+ renderTopLevel (filter isTypeDeclaration ds)
68+ spacer
69+ headerLevel 3 "Type Classes"
70+ spacer
71+ renderTopLevel (filter isTypeClassDeclaration ds)
72+ spacer
73+ headerLevel 3 "Type Class Instances"
74+ spacer
75+ renderTopLevel (filter isTypeInstanceDeclaration ds)
76+ spacer
77+ headerLevel 3 "Values"
78+ spacer
79+ renderTopLevel (filter isValueDeclaration ds)
80+ spacer
81+
82+renderTopLevel :: [P.Declaration] -> Docs
83+renderTopLevel decls = forM_ (sortBy (compare `on` getName) decls) $ \decl -> do
84+ renderDeclaration 4 decl
85+ spacer
86+
87+renderDeclaration :: Int -> P.Declaration -> Docs
88+renderDeclaration n (P.TypeDeclaration ident ty) =
89+ atIndent n $ show ident ++ " :: " ++ P.prettyPrintType ty
90+renderDeclaration n (P.ExternDeclaration _ ident _ ty) =
91+ atIndent n $ show ident ++ " :: " ++ P.prettyPrintType ty
92+renderDeclaration n (P.DataDeclaration name args ctors) = do
93+ let typeName = P.runProperName name ++ " " ++ unwords args
94+ atIndent n $ "data " ++ typeName ++ " where"
95+ forM_ ctors $ \(ctor, tys) ->
96+ atIndent (n + 2) $ P.runProperName ctor ++ " :: " ++ concatMap (\ty -> P.prettyPrintType ty ++ " -> ") tys ++ typeName
97+renderDeclaration n (P.ExternDataDeclaration name kind) =
98+ atIndent n $ "data " ++ P.runProperName name ++ " :: " ++ P.prettyPrintKind kind
99+renderDeclaration n (P.TypeSynonymDeclaration name args ty) = do
100+ let typeName = P.runProperName name ++ " " ++ unwords args
101+ atIndent n $ "type " ++ typeName ++ " = " ++ P.prettyPrintType ty
102+renderDeclaration n (P.TypeClassDeclaration name args ds) = do
103+ atIndent n $ "class " ++ P.runProperName name ++ " " ++ unwords args ++ " where"
104+ mapM_ (renderDeclaration (n + 2)) ds
105+renderDeclaration n (P.TypeInstanceDeclaration constraints name tys _) = do
106+ let constraintsText = case constraints of
107+ [] -> ""
108+ cs -> "(" ++ intercalate "," (map (\(pn, tys') -> show pn ++ " (" ++ unwords (map (("(" ++) . (++ ")") . P.prettyPrintType) tys') ++ ")") cs) ++ ") => "
109+ atIndent n $ constraintsText ++ "instance " ++ show name ++ " " ++ unwords (map (("(" ++) . (++ ")") . P.prettyPrintType) tys)
110+renderDeclaration _ _ = return ()
111+
112+getName :: P.Declaration -> String
113+getName (P.TypeDeclaration ident _) = show ident
114+getName (P.ExternDeclaration _ ident _ _) = show ident
115+getName (P.DataDeclaration name _ _) = P.runProperName name
116+getName (P.ExternDataDeclaration name _) = P.runProperName name
117+getName (P.TypeSynonymDeclaration name _ _) = P.runProperName name
118+getName (P.TypeClassDeclaration name _ _) = P.runProperName name
119+getName (P.TypeInstanceDeclaration _ name _ _) = show name
120+getName _ = error "Invalid argument to getName"
121+
122+isValueDeclaration :: P.Declaration -> Bool
123+isValueDeclaration P.TypeDeclaration{} = True
124+isValueDeclaration P.ExternDeclaration{} = True
125+isValueDeclaration _ = False
126+
127+isTypeDeclaration :: P.Declaration -> Bool
128+isTypeDeclaration P.DataDeclaration{} = True
129+isTypeDeclaration P.ExternDataDeclaration{} = True
130+isTypeDeclaration P.TypeSynonymDeclaration{} = True
131+isTypeDeclaration _ = False
132+
133+isTypeClassDeclaration :: P.Declaration -> Bool
134+isTypeClassDeclaration P.TypeClassDeclaration{} = True
135+isTypeClassDeclaration _ = False
136+
137+isTypeInstanceDeclaration :: P.Declaration -> Bool
138+isTypeInstanceDeclaration P.TypeInstanceDeclaration{} = True
139+isTypeInstanceDeclaration _ = False
140+
141+inputFile :: Term FilePath
142+inputFile = value $ pos 0 "input.ps" $ posInfo { posDoc = "The input .ps file" }
143+
144+term :: Term (IO ())
145+term = docgen <$> inputFile
146+
147+termInfo :: TermInfo
148+termInfo = defTI
149+ { termName = "docgen"
150+ , version = showVersion Paths.version
151+ , termDoc = "Generate Markdown documentation from PureScript extern files"
152+ }
153+
154+main :: IO ()
155+main = run (term, termInfo)
docs/.gitignorenew file+1
@@ -0,0 +1 @@
1+build
docs/Makefilenew file+177
@@ -0,0 +1,177 @@
1+# Makefile for Sphinx documentation
2+#
3+
4+# You can set these variables from the command line.
5+SPHINXOPTS =
6+SPHINXBUILD = sphinx-build
7+PAPER =
8+BUILDDIR = build
9+
10+# User-friendly check for sphinx-build
11+ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12+$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13+endif
14+
15+# Internal variables.
16+PAPEROPT_a4 = -D latex_paper_size=a4
17+PAPEROPT_letter = -D latex_paper_size=letter
18+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
19+# the i18n builder cannot share the environment and doctrees with the others
20+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
21+
22+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
23+
24+help:
25+ @echo "Please use \`make <target>' where <target> is one of"
26+ @echo " html to make standalone HTML files"
27+ @echo " dirhtml to make HTML files named index.html in directories"
28+ @echo " singlehtml to make a single large HTML file"
29+ @echo " pickle to make pickle files"
30+ @echo " json to make JSON files"
31+ @echo " htmlhelp to make HTML files and a HTML help project"
32+ @echo " qthelp to make HTML files and a qthelp project"
33+ @echo " devhelp to make HTML files and a Devhelp project"
34+ @echo " epub to make an epub"
35+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
36+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
37+ @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
38+ @echo " text to make text files"
39+ @echo " man to make manual pages"
40+ @echo " texinfo to make Texinfo files"
41+ @echo " info to make Texinfo files and run them through makeinfo"
42+ @echo " gettext to make PO message catalogs"
43+ @echo " changes to make an overview of all changed/added/deprecated items"
44+ @echo " xml to make Docutils-native XML files"
45+ @echo " pseudoxml to make pseudoxml-XML files for display purposes"
46+ @echo " linkcheck to check all external links for integrity"
47+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
48+
49+clean:
50+ rm -rf $(BUILDDIR)/*
51+
52+html:
53+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
54+ @echo
55+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
56+
57+dirhtml:
58+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
59+ @echo
60+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
61+
62+singlehtml:
63+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
64+ @echo
65+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
66+
67+pickle:
68+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
69+ @echo
70+ @echo "Build finished; now you can process the pickle files."
71+
72+json:
73+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
74+ @echo
75+ @echo "Build finished; now you can process the JSON files."
76+
77+htmlhelp:
78+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
79+ @echo
80+ @echo "Build finished; now you can run HTML Help Workshop with the" \
81+ ".hhp project file in $(BUILDDIR)/htmlhelp."
82+
83+qthelp:
84+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
85+ @echo
86+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
87+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
88+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PureScript.qhcp"
89+ @echo "To view the help file:"
90+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PureScript.qhc"
91+
92+devhelp:
93+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
94+ @echo
95+ @echo "Build finished."
96+ @echo "To view the help file:"
97+ @echo "# mkdir -p $$HOME/.local/share/devhelp/PureScript"
98+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PureScript"
99+ @echo "# devhelp"
100+
101+epub:
102+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
103+ @echo
104+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
105+
106+latex:
107+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
108+ @echo
109+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
110+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
111+ "(use \`make latexpdf' here to do that automatically)."
112+
113+latexpdf:
114+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
115+ @echo "Running LaTeX files through pdflatex..."
116+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
117+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
118+
119+latexpdfja:
120+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
121+ @echo "Running LaTeX files through platex and dvipdfmx..."
122+ $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
123+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
124+
125+text:
126+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
127+ @echo
128+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
129+
130+man:
131+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
132+ @echo
133+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
134+
135+texinfo:
136+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
137+ @echo
138+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
139+ @echo "Run \`make' in that directory to run these through makeinfo" \
140+ "(use \`make info' here to do that automatically)."
141+
142+info:
143+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
144+ @echo "Running Texinfo files through makeinfo..."
145+ make -C $(BUILDDIR)/texinfo info
146+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
147+
148+gettext:
149+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
150+ @echo
151+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
152+
153+changes:
154+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
155+ @echo
156+ @echo "The overview file is in $(BUILDDIR)/changes."
157+
158+linkcheck:
159+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
160+ @echo
161+ @echo "Link check complete; look for any errors in the above output " \
162+ "or in $(BUILDDIR)/linkcheck/output.txt."
163+
164+doctest:
165+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
166+ @echo "Testing of doctests in the sources finished, look at the " \
167+ "results in $(BUILDDIR)/doctest/output.txt."
168+
169+xml:
170+ $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
171+ @echo
172+ @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
173+
174+pseudoxml:
175+ $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
176+ @echo
177+ @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
docs/source/conf.pynew file+258
@@ -0,0 +1,258 @@
1+# -*- coding: utf-8 -*-
2+#
3+# PureScript documentation build configuration file, created by
4+# sphinx-quickstart on Wed Jan 22 22:04:23 2014.
5+#
6+# This file is execfile()d with the current directory set to its
7+# containing dir.
8+#
9+# Note that not all possible configuration values are present in this
10+# autogenerated file.
11+#
12+# All configuration values have a default; values that are commented out
13+# serve to show the default.
14+
15+import sys
16+import os
17+
18+# If extensions (or modules to document with autodoc) are in another directory,
19+# add these directories to sys.path here. If the directory is relative to the
20+# documentation root, use os.path.abspath to make it absolute, like shown here.
21+#sys.path.insert(0, os.path.abspath('.'))
22+
23+# -- General configuration ------------------------------------------------
24+
25+# If your documentation needs a minimal Sphinx version, state it here.
26+#needs_sphinx = '1.0'
27+
28+# Add any Sphinx extension module names here, as strings. They can be
29+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
30+# ones.
31+extensions = []
32+
33+# Add any paths that contain templates here, relative to this directory.
34+templates_path = ['_templates']
35+
36+# The suffix of source filenames.
37+source_suffix = '.rst'
38+
39+# The encoding of source files.
40+#source_encoding = 'utf-8-sig'
41+
42+# The master toctree document.
43+master_doc = 'index'
44+
45+# General information about the project.
46+project = u'PureScript'
47+copyright = u'2014, Phil Freeman'
48+
49+# The version info for the project you're documenting, acts as replacement for
50+# |version| and |release|, also used in various other places throughout the
51+# built documents.
52+#
53+# The short X.Y version.
54+version = '0.4.0'
55+# The full version, including alpha/beta/rc tags.
56+release = '0.4.0'
57+
58+# The language for content autogenerated by Sphinx. Refer to documentation
59+# for a list of supported languages.
60+#language = None
61+
62+# There are two options for replacing |today|: either, you set today to some
63+# non-false value, then it is used:
64+#today = ''
65+# Else, today_fmt is used as the format for a strftime call.
66+#today_fmt = '%B %d, %Y'
67+
68+# List of patterns, relative to source directory, that match files and
69+# directories to ignore when looking for source files.
70+exclude_patterns = []
71+
72+# The reST default role (used for this markup: `text`) to use for all
73+# documents.
74+#default_role = None
75+
76+# If true, '()' will be appended to :func: etc. cross-reference text.
77+#add_function_parentheses = True
78+
79+# If true, the current module name will be prepended to all description
80+# unit titles (such as .. function::).
81+#add_module_names = True
82+
83+# If true, sectionauthor and moduleauthor directives will be shown in the
84+# output. They are ignored by default.
85+#show_authors = False
86+
87+# The name of the Pygments (syntax highlighting) style to use.
88+pygments_style = 'sphinx'
89+
90+# A list of ignored prefixes for module index sorting.
91+#modindex_common_prefix = []
92+
93+# If true, keep warnings as "system message" paragraphs in the built documents.
94+#keep_warnings = False
95+
96+
97+# -- Options for HTML output ----------------------------------------------
98+
99+# The theme to use for HTML and HTML Help pages. See the documentation for
100+# a list of builtin themes.
101+html_theme = 'default'
102+
103+# Theme options are theme-specific and customize the look and feel of a theme
104+# further. For a list of options available for each theme, see the
105+# documentation.
106+#html_theme_options = {}
107+
108+# Add any paths that contain custom themes here, relative to this directory.
109+#html_theme_path = []
110+
111+# The name for this set of Sphinx documents. If None, it defaults to
112+# "<project> v<release> documentation".
113+#html_title = None
114+
115+# A shorter title for the navigation bar. Default is the same as html_title.
116+#html_short_title = None
117+
118+# The name of an image file (relative to this directory) to place at the top
119+# of the sidebar.
120+#html_logo = None
121+
122+# The name of an image file (within the static path) to use as favicon of the
123+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
124+# pixels large.
125+#html_favicon = None
126+
127+# Add any paths that contain custom static files (such as style sheets) here,
128+# relative to this directory. They are copied after the builtin static files,
129+# so a file named "default.css" will overwrite the builtin "default.css".
130+html_static_path = ['_static']
131+
132+# Add any extra paths that contain custom files (such as robots.txt or
133+# .htaccess) here, relative to this directory. These files are copied
134+# directly to the root of the documentation.
135+#html_extra_path = []
136+
137+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
138+# using the given strftime format.
139+#html_last_updated_fmt = '%b %d, %Y'
140+
141+# If true, SmartyPants will be used to convert quotes and dashes to
142+# typographically correct entities.
143+#html_use_smartypants = True
144+
145+# Custom sidebar templates, maps document names to template names.
146+#html_sidebars = {}
147+
148+# Additional templates that should be rendered to pages, maps page names to
149+# template names.
150+#html_additional_pages = {}
151+
152+# If false, no module index is generated.
153+#html_domain_indices = True
154+
155+# If false, no index is generated.
156+#html_use_index = True
157+
158+# If true, the index is split into individual pages for each letter.
159+#html_split_index = False
160+
161+# If true, links to the reST sources are added to the pages.
162+#html_show_sourcelink = True
163+
164+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
165+#html_show_sphinx = True
166+
167+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
168+#html_show_copyright = True
169+
170+# If true, an OpenSearch description file will be output, and all pages will
171+# contain a <link> tag referring to it. The value of this option must be the
172+# base URL from which the finished HTML is served.
173+#html_use_opensearch = ''
174+
175+# This is the file name suffix for HTML files (e.g. ".xhtml").
176+#html_file_suffix = None
177+
178+# Output file base name for HTML help builder.
179+htmlhelp_basename = 'PureScriptdoc'
180+
181+
182+# -- Options for LaTeX output ---------------------------------------------
183+
184+latex_elements = {
185+# The paper size ('letterpaper' or 'a4paper').
186+#'papersize': 'letterpaper',
187+
188+# The font size ('10pt', '11pt' or '12pt').
189+#'pointsize': '10pt',
190+
191+# Additional stuff for the LaTeX preamble.
192+#'preamble': '',
193+}
194+
195+# Grouping the document tree into LaTeX files. List of tuples
196+# (source start file, target name, title,
197+# author, documentclass [howto, manual, or own class]).
198+latex_documents = [
199+ ('index', 'PureScript.tex', u'PureScript Documentation',
200+ u'Phil Freeman', 'manual'),
201+]
202+
203+# The name of an image file (relative to this directory) to place at the top of
204+# the title page.
205+#latex_logo = None
206+
207+# For "manual" documents, if this is true, then toplevel headings are parts,
208+# not chapters.
209+#latex_use_parts = False
210+
211+# If true, show page references after internal links.
212+#latex_show_pagerefs = False
213+
214+# If true, show URL addresses after external links.
215+#latex_show_urls = False
216+
217+# Documents to append as an appendix to all manuals.
218+#latex_appendices = []
219+
220+# If false, no module index is generated.
221+#latex_domain_indices = True
222+
223+
224+# -- Options for manual page output ---------------------------------------
225+
226+# One entry per manual page. List of tuples
227+# (source start file, name, description, authors, manual section).
228+man_pages = [
229+ ('index', 'purescript', u'PureScript Documentation',
230+ [u'Phil Freeman'], 1)
231+]
232+
233+# If true, show URL addresses after external links.
234+#man_show_urls = False
235+
236+
237+# -- Options for Texinfo output -------------------------------------------
238+
239+# Grouping the document tree into Texinfo files. List of tuples
240+# (source start file, target name, title, author,
241+# dir menu entry, description, category)
242+texinfo_documents = [
243+ ('index', 'PureScript', u'PureScript Documentation',
244+ u'Phil Freeman', 'PureScript', 'One line description of project.',
245+ 'Miscellaneous'),
246+]
247+
248+# Documents to append as an appendix to all manuals.
249+#texinfo_appendices = []
250+
251+# If false, no module index is generated.
252+#texinfo_domain_indices = True
253+
254+# How to display URL addresses: 'footnote', 'no', or 'inline'.
255+#texinfo_show_urls = 'footnote'
256+
257+# If true, do not generate a @detailmenu in the "Top" node's menu.
258+#texinfo_no_detailmenu = False
docs/source/ffi.rstnew file+31
@@ -0,0 +1,31 @@
1+Foreign Function Interface
2+==========================
3+
4+Importing Values
5+----------------
6+
7+The `foreign import` keyword declares a value which is defined in Javascript, and its type::
8+
9+ foreign import pow :: Number -> Number -> Number
10+
11+Inline Javascript
12+-----------------
13+
14+A foreign import declaration may optionally contain its definition in Javascript as a string literal. If this is provided, the string will be inserted directly into the generated Javascript before the current module definition::
15+
16+ foreign import pow "function pow(n) {\
17+ \ return function(p) {\
18+ \ return Math.pow(n, p);\
19+ \ };\
20+ \}" :: Number -> Number -> Number
21+
22+Importing Types
23+---------------
24+
25+To declare a new type with no constructors, use `foreign import data` and provide the kind::
26+
27+ foreign import data DOM :: *
28+
29+ foreign import document :: {
30+ createElement :: String -> DOM
31+ }
docs/source/index.rstnew file+30
@@ -0,0 +1,30 @@
1+.. PureScript documentation master file, created by
2+ sphinx-quickstart on Wed Jan 22 22:04:23 2014.
3+ You can adapt this file completely to your liking, but it should at least
4+ contain the root `toctree` directive.
5+
6+Welcome to PureScript's documentation!
7+======================================
8+
9+Contents:
10+
11+.. toctree::
12+ :maxdepth: 2
13+
14+ intro
15+ types
16+ kinds
17+ syntax
18+ typeclasses
19+ patterns
20+ modules
21+ ffi
22+ prelude
23+
24+Indices and tables
25+==================
26+
27+* :ref:`genindex`
28+* :ref:`modindex`
29+* :ref:`search`
30+
docs/source/intro.rstnew file+134
@@ -0,0 +1,134 @@
1+Introduction
2+============
3+
4+PureScript is a small strongly, statically typed compile-to-JS language with a number of interesting features, such as:
5+
6+- Type Inference
7+- Higher Kinded Polymorphism
8+- Support for basic Javascript types
9+- Extensible records
10+- Extensible effects
11+- Optimizer rules for generation of efficient Javascript
12+- Pattern matching
13+- Simple FFI
14+- Modules
15+- Rank N Types
16+- Do Notation
17+- Optional tail-call elimination
18+- Type Classes
19+
20+Installation
21+------------
22+
23+If you have the Haskell Plaform installed, then you can install the latest released version from Hackage::
24+
25+ cabal update
26+ cabal install purescript
27+
28+If you would like to build the latest version of the code, clone this repository and build::
29+
30+ git clone git://github.com:paf31/purescript.git
31+ cabal configure --enable-tests
32+ cabal build
33+ cabal test
34+ cabal install
35+
36+Usage
37+-----
38+
39+The `psc` executable takes a list of PureScript source files as arguments and by default writes out its errors or output to the console.
40+
41+The following options are supported:
42+
43+--stdin Read input from standard input instead of from files
44+--output Write the generated Javascript to the specified file
45+--externs Write a list of foreign imports declarations to the specified file in addition to generating Javascript output
46+--runtime-type-checks Generate simple runtime type checks for function arguments with simple types.
47+--tco Perform tail-call elimination on the generated Javascript.
48+--no-prelude Do not include the Prelude in the generated Javascript.
49+--magic-do Overload the `do` keyword to inline calls to `bind` for the `Eff` monad, to generate more efficient code.
50+--main Generate a call to `main` in the specified module after all other generated Javascript. Defaults to `Main` if the option is used but no value is provided.
51+--module If specified, any code which is not referenced transitively from this module will be removed. This argument can be used multiple times.
52+--browser-namespace Specify the namespace that PureScript modules will be exported to when running in the browser.
53+
54+Motivation
55+----------
56+
57+I was looking for a simple functional language which would compile to JavaScript and have the following characteristics:
58+
59+- Generate simple readable Javascript
60+- Provide the ability to compile to tight loops if necessary
61+- Reasonable type system
62+- Ideally, written in a programming language I would enjoy working in
63+- Provides a simple interface to existing Javascript code
64+
65+I didn't find exactly what I was looking for, so I wrote PureScript. It doesn't have everything right now, but it should serve as a simple core on which to develop new ideas.
66+
67+PureScript was originally designed to implement purely functional core logic. However, recent additions to the compiler and libraries now also make it a good option for general-purpose programming.
68+
69+PureScript can also be seen as a trade-off between a theoretically ideal language and one which generates reasonably high performance code.
70+
71+Hello, PureScript!
72+------------------
73+
74+As an introductory example, here is the usual "Hello World" written in PureScript::
75+
76+ module Main where
77+
78+ import Trace
79+
80+ main = trace "Hello, World!"
81+
82+which compiles to the following Javascript, ignoring the Prelude::
83+
84+ var Main;
85+ (function (Main) {
86+ var main = trace("Hello, World!");
87+ Main.main = main;
88+ })(Main = Main || {});
89+
90+The following command will compile and execute the PureScript code above::
91+
92+ psc input.purs --run-main | nodejs
93+
94+Another Example
95+---------------
96+
97+The following code defines a `Person` data type and a function to generate a string representation for a `Person`::
98+
99+ data Person = Person { name :: String, age :: Number }
100+
101+ foreign import numberToString :: Number -> String
102+
103+ showPerson :: Person -> String
104+ showPerson (Person o) = o.name ++ ", aged " ++ numberToString(o.age)
105+
106+Line by line, this reads as follows:
107+
108+- `Person` is a data type with one constructor, also called `Person`
109+- The `Person` constructor takes an object with two properties, `name` which is a `String`, and `age` which is a `Number`
110+- The `numberToString` function is written in Javascript, and converts a `Number` to its `String` representation
111+- The `showPerson` function takes a `Person` and returns a `String`
112+- `showPerson` works by case analysis on its argument, first matching the constructor `Person` and then using string concatenation and object accessors to return its result.
113+
114+The generated Javascript looks like this::
115+
116+ var Person = function (value) {
117+ return { ctor: 'Person', values: [value] };
118+ };
119+
120+ function showPerson(_1) {
121+ return _1.values[0].name + ", aged " + numberToString(_1.values[0].age);
122+ };
123+
124+Related Projects
125+----------------
126+
127+PureScript might be compared to other AltJS projects such as Roy, Haste, Fay, Elm and GHCJS. Certainly, there is a lot of overlap in terms of syntax, but the goals of PureScript listed above separate it in one or more ways from each of these languages.
128+
129+Roy is probably the most similar language on the list, and was a large influence on the development of PureScript. There are however, key differences in the foreign function interface, the type system and the choice of development language (Haskell vs. Javascript)
130+
131+Projects such as Haste, Fay and GHCJS aim to use some combination of the GHC compiler itself and/or its intermediate representation, Core, to perform some of the tasks involved in compilation such as parsing and type checking. This usually gives the advantage that tools and libraries can be shared with Haskell, but often at the cost of the size of the generated Javascript. This is the main practical difference between PureScript and these projects.
132+
133+Elm also shares a lot in terms of functionality with PureScript. Elm is designed for functional reactive programming, and focusses on tools and language features suitable for that domain, while PureScript focusses on the development of purely functional core application logic. Another difference between PureScript and Elm is PureScript's lack of a runtime system.
134+
docs/source/kinds.rstnew file+21
@@ -0,0 +1,21 @@
1+Kind System
2+===========
3+
4+The kind system defines the following kinds:
5+
6+- ``*``, the kind of types.
7+- ``!``, the kind of effects.
8+- Arrow kinds ``k1 -> k2``
9+- Row kinds ``# k``
10+
11+Row Kinds
12+---------
13+
14+The kind ``# k`` of rows is used to classify labelled, unordered collections of types of kind ``k``.
15+
16+For example ``# *`` is the kind of rows of types, as used to define records, and ``# !`` is the kind of rows of effects, used to define the monad ``Eff`` of extensible effects.
17+
18+Quantification
19+--------------
20+
21+A type variable can refer to not only a type or a row, but a type constructor, or row constructor etc., and type variables with those kinds can be bound inside a ``forall`` quantifier.
docs/source/modules.rstnew file+29
@@ -0,0 +1,29 @@
1+Modules
2+=======
3+
4+All code in PureScript is contained in a module. Modules are introduced using the ``module`` keyword::
5+
6+ module A where
7+
8+ id x = x
9+
10+When referencing values or data types in another module, names may be qualified by using a dot::
11+
12+ module B where
13+
14+ foo = A.id
15+
16+Importing Modules
17+-----------------
18+
19+A module can be imported using the ``import`` keyword. This will create aliases for all of the values and types in the imported module::
20+
21+ module B where
22+
23+ import A
24+
25+Alternatively, a list of names to import can be provided in parentheses::
26+
27+ module B where
28+
29+ import A (id)
docs/source/patterns.rstnew file+139
@@ -0,0 +1,139 @@
1+Pattern Matching
2+================
3+
4+Pattern matching deconstructs a value to bring zero or more expressions into scope. Pattern matches are introduced with the `case` keyword.
5+
6+Pattern matches have the following general form::
7+
8+ case value of
9+ pattern -> result
10+ ...
11+ pattern -> result
12+
13+Pattern matching can also be used in the declaration of functions, as we have already seen::
14+
15+ fn pattern_1 ... pattern_n = result
16+
17+Patterns can also be used when introducing functions. For example::
18+
19+ example x y z = x * y + z
20+
21+The following pattern types are supported:
22+
23+- Wildcard pattern
24+- Literal patterns
25+- Variable pattern
26+- Array patterns
27+- Cons patterns
28+- Constructor patterns
29+- Record patterns
30+- Named patterns
31+- Guards
32+
33+Patterns need not be exhaustive. A pattern match failed exception will be thrown at runtime if no pattern matches the input.
34+
35+Wildcard Patterns
36+-----------------
37+
38+The wilcard `_` matches any input and brings nothing into scope::
39+
40+ f _ = 0
41+
42+Literal Patterns
43+----------------
44+
45+Literal patterns are provided to match on primitives::
46+
47+ f true = 0
48+ f false = 1
49+
50+ g "Foo" = 0
51+ g _ = 1
52+
53+ h 0 = 0
54+ h _ = 1
55+
56+Variable Patterns
57+-----------------
58+
59+A variable pattern matches any input and binds that input to its name::
60+
61+ double x = x * 2
62+
63+Array Patterns
64+--------------
65+
66+Array patterns match an input which is an array, and bring its elements into scope. For example::
67+
68+ f [x] = x
69+ f [x, y] = x * y
70+ f _ = 0
71+
72+Here, the first pattern only matches arrays of length one, and brings the first element of the array into scope.
73+
74+The second pattern matches arrays with two elements, and brings the first and second elements into scope.
75+
76+Cons Patterns
77+-------------
78+
79+The head and tail of a non-empty array can be matched by using a cons pattern::
80+
81+ sum [] = 0
82+ sum (x : xs) = x + sum xs
83+
84+`:` associates to the right::
85+
86+ addPairs (x : y : xs) = x * y + addPairs xs
87+ addPairs _ = 0
88+
89+
90+Constructor patterns
91+--------------------
92+
93+Constructor patterns match a data constructor and its arguments::
94+
95+ data Foo = Foo String | Bar Number Boolean
96+
97+ foo (Foo s) = true
98+ foo (Bar _ b) = b
99+
100+Record Patterns
101+---------------
102+
103+Record patterns match an input which is a record, and bring its properties into scope::
104+
105+ f { foo = "Foo" } = o.bar
106+ f _ = 0
107+
108+Nested Patterns
109+---------------
110+
111+The patterns above can be combined to create larger patterns. For example::
112+
113+ f { arr = x : _, take = "car" } = x
114+ f { arr = _ : x : _, take = "cadr" } = x
115+ f _ = 0
116+
117+Named Patterns
118+--------------
119+
120+Named patterns bring additional names into scope when using nested patterns. Any pattern can be named by using the ``@`` symbol::
121+
122+ f a@(_ : _ : _) = true
123+ f _ = false
124+
125+Here, in the first pattern, any array with two or more elements will be matched and bound to the variable ``a``.
126+
127+Guards
128+------
129+
130+Guards are used to impose additional constraints inside a pattern using boolean-valued expressions, and are introduced with a pipe after the pattern::
131+
132+ evens [] = 0
133+ evens (x : xs) | x % 2 == 0 = 1 + evens xs
134+ evens (_ : xs) = evens xs
135+
136+When using patterns to define a function at the top level, guards appear after all patterns::
137+
138+ greater x y | x > y = true
139+ greater _ _ = false
docs/source/prelude.rstnew file+856
@@ -0,0 +1,856 @@
1+Module Documentation
2+====================
3+
4+Module Prelude
5+--------------
6+
7+Types
8+~~~~~
9+
10+::
11+
12+ data Ref a where
13+ Ref :: a -> Ref a
14+
15+Type Classes
16+~~~~~~~~~~~~
17+
18+::
19+
20+ class Alternative f where
21+ empty :: forall a. f a
22+ (<|>) :: forall a. f a -> f a -> f a
23+
24+ class Applicative f where
25+ pure :: forall a. a -> f a
26+ (<*>) :: forall b. forall a. f (a -> b) -> f a -> f b
27+
28+ class Bits b where
29+ (&) :: b -> b -> b
30+ (|) :: b -> b -> b
31+ (^) :: b -> b -> b
32+ shl :: b -> Prim.Number -> b
33+ shr :: b -> Prim.Number -> b
34+ zshr :: b -> Prim.Number -> b
35+ complement :: b -> b
36+
37+ class BoolLike b where
38+ (&&) :: b -> b -> b
39+ (||) :: b -> b -> b
40+ not :: b -> b
41+
42+ class Category a where
43+ id :: forall t. a t t
44+ (<<<) :: forall d. forall c. forall b. a c d -> a b c -> a b d
45+ (>>>) :: forall d. forall c. forall b. a b c -> a c d -> a b d
46+
47+ class Eq a where
48+ (==) :: a -> a -> Prim.Boolean
49+ (/=) :: a -> a -> Prim.Boolean
50+
51+ class Functor f where
52+ (<$>) :: forall b. forall a. (a -> b) -> f a -> f b
53+
54+ class Monad m where
55+ return :: forall a. a -> m a
56+ (>>=) :: forall b. forall a. m a -> (a -> m b) -> m b
57+
58+ class Num a where
59+ (+) :: a -> a -> a
60+ (-) :: a -> a -> a
61+ (*) :: a -> a -> a
62+ (/) :: a -> a -> a
63+ (%) :: a -> a -> a
64+ negate :: a -> a
65+
66+ class Ord a where
67+ (<) :: a -> a -> Prim.Boolean
68+ (>) :: a -> a -> Prim.Boolean
69+ (<=) :: a -> a -> Prim.Boolean
70+ (>=) :: a -> a -> Prim.Boolean
71+
72+ class Read a where
73+ read :: Prim.String -> a
74+
75+ class Show a where
76+ show :: a -> Prim.String
77+
78+Type Class Instances
79+~~~~~~~~~~~~~~~~~~~~
80+
81+::
82+
83+ (Monad (m)) => instance Applicative m
84+
85+ instance Bits Prim.Number
86+
87+ instance BoolLike Prim.Boolean
88+
89+ instance Category Prim.Function
90+
91+ instance Eq Ref a
92+
93+ instance Eq Prim.String
94+
95+ instance Eq Prim.Number
96+
97+ instance Eq Prim.Boolean
98+
99+ (Eq (a)) => instance Eq [a]
100+
101+ (Applicative (f)) => instance Functor f
102+
103+ instance Num Prim.Number
104+
105+ instance Ord Prim.Number
106+
107+ instance Prelude.Show Prim.Number
108+
109+ instance Read Prim.String
110+
111+ instance Read Prim.Boolean
112+
113+ instance Read Prim.Number
114+
115+ instance Show Prim.String
116+
117+ instance Show Prim.Boolean
118+
119+Values
120+~~~~~~
121+
122+::
123+
124+ (!!) :: forall a. [a] -> Prim.Number -> a
125+
126+ (#) :: forall b. forall a. a -> (a -> b) -> b
127+
128+ ($) :: forall b. forall a. (a -> b) -> a -> b
129+
130+ (++) :: Prim.String -> Prim.String -> Prim.String
131+
132+ boolAnd :: Prim.Boolean -> Prim.Boolean -> Prim.Boolean
133+
134+ boolNot :: Prim.Boolean -> Prim.Boolean
135+
136+ boolOr :: Prim.Boolean -> Prim.Boolean -> Prim.Boolean
137+
138+ const :: forall b. forall a. a -> b -> a
139+
140+ flip :: forall c. forall b. forall a. (a -> b -> c) -> b -> a -> c
141+
142+ liftRef :: forall b. forall a. (a -> a -> b) -> Ref a -> Ref a -> b
143+
144+ numAdd :: Prim.Number -> Prim.Number -> Prim.Number
145+
146+ numAnd :: Prim.Number -> Prim.Number -> Prim.Number
147+
148+ numComplement :: Prim.Number -> Prim.Number
149+
150+ numDiv :: Prim.Number -> Prim.Number -> Prim.Number
151+
152+ numGreater :: Prim.Number -> Prim.Number -> Prim.Boolean
153+
154+ numGreaterEq :: Prim.Number -> Prim.Number -> Prim.Boolean
155+
156+ numLess :: Prim.Number -> Prim.Number -> Prim.Boolean
157+
158+ numLessEq :: Prim.Number -> Prim.Number -> Prim.Boolean
159+
160+ numMod :: Prim.Number -> Prim.Number -> Prim.Number
161+
162+ numMul :: Prim.Number -> Prim.Number -> Prim.Number
163+
164+ numNegate :: Prim.Number -> Prim.Number
165+
166+ numOr :: Prim.Number -> Prim.Number -> Prim.Number
167+
168+ numShl :: Prim.Number -> Prim.Number -> Prim.Number
169+
170+ numShr :: Prim.Number -> Prim.Number -> Prim.Number
171+
172+ numSub :: Prim.Number -> Prim.Number -> Prim.Number
173+
174+ numXor :: Prim.Number -> Prim.Number -> Prim.Number
175+
176+ numZshr :: Prim.Number -> Prim.Number -> Prim.Number
177+
178+ readNumber :: Prim.String -> Prim.Number
179+
180+ refEq :: forall a. Ref a -> Ref a -> Prim.Boolean
181+
182+ refIneq :: forall a. Ref a -> Ref a -> Prim.Boolean
183+
184+ showNumber :: Prim.Number -> Prim.String
185+
186+ unsafeRefEq :: forall a. a -> a -> Prim.Boolean
187+
188+ unsafeRefIneq :: forall a. a -> a -> Prim.Boolean
189+
190+Module Data.Monoid
191+------------------
192+
193+Types
194+~~~~~
195+
196+Type Classes
197+~~~~~~~~~~~~
198+
199+::
200+
201+ class Monoid m where
202+ mempty :: m
203+ (<>) :: m -> m -> m
204+
205+Type Class Instances
206+~~~~~~~~~~~~~~~~~~~~
207+
208+::
209+
210+ instance Monoid Prim.String
211+
212+ instance Monoid [a]
213+
214+Values
215+~~~~~~
216+
217+::
218+
219+ mconcat :: forall m. (Monoid (m)) => [m] -> m
220+
221+Module Control.Monad
222+--------------------
223+
224+Types
225+~~~~~
226+
227+Type Classes
228+~~~~~~~~~~~~
229+
230+Type Class Instances
231+~~~~~~~~~~~~~~~~~~~~
232+
233+Values
234+~~~~~~
235+
236+::
237+
238+ (<=<) :: forall c. forall b. forall a. forall m. (Monad (m)) => (b -> m c) -> (a -> m b) -> a -> m c
239+
240+ (>=>) :: forall c. forall b. forall a. forall m. (Monad (m)) => (a -> m b) -> (b -> m c) -> a -> m c
241+
242+ foldM :: forall b. forall a. forall m. (Monad (m)) => (a -> b -> m a) -> a -> [b] -> m a
243+
244+ join :: forall a. forall m. (Monad (m)) => m (m a) -> m a
245+
246+ mapM :: forall b. forall a. forall m. (Monad (m)) => (a -> m b) -> [a] -> m [b]
247+
248+ replicateM :: forall a. forall m. (Monad (m)) => Prim.Number -> m a -> m [a]
249+
250+ sequence :: forall a. forall m. (Monad (m)) => [m a] -> m [a]
251+
252+ when :: forall m. (Monad (m)) => Prim.Boolean -> m { } -> m { }
253+
254+Module Data.Maybe
255+-----------------
256+
257+Types
258+~~~~~
259+
260+::
261+
262+ data Maybe a where
263+ Nothing :: Maybe a
264+ Just :: a -> Maybe a
265+
266+Type Classes
267+~~~~~~~~~~~~
268+
269+Type Class Instances
270+~~~~~~~~~~~~~~~~~~~~
271+
272+::
273+
274+ instance Prelude.Applicative Maybe
275+
276+ instance Prelude.Functor Maybe
277+
278+ instance Prelude.Monad Maybe
279+
280+ (Show (a)) => instance Prelude.Show Maybe a
281+
282+Values
283+~~~~~~
284+
285+::
286+
287+ fromMaybe :: forall a. a -> Maybe a -> a
288+
289+ maybe :: forall b. forall a. b -> (a -> b) -> Maybe a -> b
290+
291+Module Data.Either
292+------------------
293+
294+Types
295+~~~~~
296+
297+::
298+
299+ data Either a b where
300+ Left :: a -> Either a b
301+ Right :: b -> Either a b
302+
303+Type Classes
304+~~~~~~~~~~~~
305+
306+Type Class Instances
307+~~~~~~~~~~~~~~~~~~~~
308+
309+::
310+
311+ instance Prelude.Applicative Either e
312+
313+ instance Prelude.Functor Either a
314+
315+ instance Prelude.Monad Either e
316+
317+ (Show (a),Show (b)) => instance Prelude.Show Either a b
318+
319+Values
320+~~~~~~
321+
322+::
323+
324+ either :: forall c. forall b. forall a. (a -> c) -> (b -> c) -> Either a b -> c
325+
326+Module Data.Array
327+-----------------
328+
329+Types
330+~~~~~
331+
332+Type Classes
333+~~~~~~~~~~~~
334+
335+Type Class Instances
336+~~~~~~~~~~~~~~~~~~~~
337+
338+::
339+
340+ instance Prelude.Alternative Prim.Array
341+
342+ instance Prelude.Functor Prim.Array
343+
344+ instance Prelude.Monad Prim.Array
345+
346+ (Prelude.Show (a)) => instance Prelude.Show [a]
347+
348+Values
349+~~~~~~
350+
351+::
352+
353+ (:) :: forall a. a -> [a] -> [a]
354+
355+ all :: forall a. (a -> Prim.Boolean) -> [a] -> Prim.Boolean
356+
357+ any :: forall a. (a -> Prim.Boolean) -> [a] -> Prim.Boolean
358+
359+ concat :: forall a. [a] -> [a] -> [a]
360+
361+ concatMap :: forall b. forall a. [a] -> (a -> [b]) -> [b]
362+
363+ filter :: forall a. (a -> Prim.Boolean) -> [a] -> [a]
364+
365+ find :: forall a. (a -> Prim.Boolean) -> [a] -> Maybe a
366+
367+ foldl :: forall b. forall a. (a -> b -> b) -> b -> [a] -> b
368+
369+ foldr :: forall b. forall a. (a -> b -> a) -> a -> [b] -> a
370+
371+ head :: forall a. [a] -> Maybe a
372+
373+ indexOf :: forall a. [a] -> a -> Prim.Number
374+
375+ isEmpty :: forall a. [a] -> Prim.Boolean
376+
377+ joinS :: [Prim.String] -> Prim.String
378+
379+ joinWith :: [Prim.String] -> Prim.String -> Prim.String
380+
381+ lastIndexOf :: forall a. [a] -> a -> Prim.Number
382+
383+ length :: forall a. [a] -> Prim.Number
384+
385+ map :: forall b. forall a. (a -> b) -> [a] -> [b]
386+
387+ push :: forall a. [a] -> a -> [a]
388+
389+ range :: Prim.Number -> Prim.Number -> [Prim.Number]
390+
391+ reverse :: forall a. [a] -> [a]
392+
393+ shift :: forall a. [a] -> [a]
394+
395+ singleton :: forall a. a -> [a]
396+
397+ slice :: forall a. Prim.Number -> Prim.Number -> [a] -> [a]
398+
399+ sort :: forall a. [a] -> [a]
400+
401+ splice :: forall a. Prim.Number -> Prim.Number -> [a] -> [a] -> [a]
402+
403+ tail :: forall a. [a] -> Maybe [a]
404+
405+ zipWith :: forall c. forall b. forall a. (a -> b -> c) -> [a] -> [b] -> [c]
406+
407+Module Data.Array.Unsafe
408+------------------------
409+
410+Types
411+~~~~~
412+
413+Type Classes
414+~~~~~~~~~~~~
415+
416+Type Class Instances
417+~~~~~~~~~~~~~~~~~~~~
418+
419+Values
420+~~~~~~
421+
422+::
423+
424+ head :: forall a. [a] -> a
425+
426+ tail :: forall a. [a] -> [a]
427+
428+Module Data.Tuple
429+-----------------
430+
431+Types
432+~~~~~
433+
434+::
435+
436+ data Tuple a b where
437+ Tuple :: a -> b -> Tuple a b
438+
439+Type Classes
440+~~~~~~~~~~~~
441+
442+Type Class Instances
443+~~~~~~~~~~~~~~~~~~~~
444+
445+::
446+
447+ (Prelude.Show (a),Prelude.Show (b)) => instance Prelude.Show Tuple a b
448+
449+Values
450+~~~~~~
451+
452+::
453+
454+ curry :: forall c. forall b. forall a. (Tuple a b -> c) -> a -> b -> c
455+
456+ uncurry :: forall c. forall b. forall a. (a -> b -> c) -> Tuple a b -> c
457+
458+ unzip :: forall b. forall a. [Tuple a b] -> Tuple [a] [b]
459+
460+ zip :: forall b. forall a. [a] -> [b] -> [Tuple a b]
461+
462+Module Data.String
463+------------------
464+
465+Types
466+~~~~~
467+
468+Type Classes
469+~~~~~~~~~~~~
470+
471+Type Class Instances
472+~~~~~~~~~~~~~~~~~~~~
473+
474+Values
475+~~~~~~
476+
477+::
478+
479+ charAt :: Prim.Number -> Prim.String -> Prim.String
480+
481+ indexOfS :: Prim.String -> Prim.String -> Prim.Number
482+
483+ lastIndexOfS :: Prim.String -> Prim.String -> Prim.Number
484+
485+ lengthS :: Prim.String -> Prim.Number
486+
487+ localeCompare :: Prim.String -> Prim.String -> Prim.Number
488+
489+ replace :: Prim.String -> Prim.String -> Prim.String -> Prim.String
490+
491+ sliceS :: Prim.Number -> Prim.Number -> Prim.String -> Prim.String
492+
493+ split :: Prim.String -> Prim.String -> [Prim.String]
494+
495+ substr :: Prim.Number -> Prim.Number -> Prim.String -> Prim.String
496+
497+ substring :: Prim.Number -> Prim.Number -> Prim.String -> Prim.String
498+
499+ toLower :: Prim.String -> Prim.String
500+
501+ toUpper :: Prim.String -> Prim.String
502+
503+ trim :: Prim.String -> Prim.String
504+
505+Module Data.String.Regex
506+------------------------
507+
508+Types
509+~~~~~
510+
511+::
512+
513+ data Regex :: *
514+
515+Type Classes
516+~~~~~~~~~~~~
517+
518+Type Class Instances
519+~~~~~~~~~~~~~~~~~~~~
520+
521+Values
522+~~~~~~
523+
524+::
525+
526+ match :: Regex -> Prim.String -> [Prim.String]
527+
528+ regex :: Prim.String -> Prim.String -> Regex
529+
530+ replaceR :: Regex -> Prim.String -> Prim.String -> Prim.String
531+
532+ search :: Regex -> Prim.String -> Prim.Number
533+
534+ test :: Regex -> Prim.String -> Prim.Boolean
535+
536+Module Global
537+-------------
538+
539+Types
540+~~~~~
541+
542+Type Classes
543+~~~~~~~~~~~~
544+
545+Type Class Instances
546+~~~~~~~~~~~~~~~~~~~~
547+
548+Values
549+~~~~~~
550+
551+::
552+
553+ decodeURI :: Prim.String -> Prim.String
554+
555+ decodeURIComponent :: Prim.String -> Prim.String
556+
557+ encodeURI :: Prim.String -> Prim.String
558+
559+ encodeURIComponent :: Prim.String -> Prim.String
560+
561+ infinity :: Prim.Number
562+
563+ isFinite :: Prim.Number -> Prim.Boolean
564+
565+ isNaN :: Prim.Number -> Prim.Boolean
566+
567+ nan :: Prim.Number
568+
569+ parseFloat :: Prim.String -> Prim.Number
570+
571+ parseInt :: Prim.String -> Prim.Number
572+
573+ toExponential :: Prim.Number -> Prim.String
574+
575+ toFixed :: Prim.Number -> Prim.Number -> Prim.String
576+
577+ toPrecision :: Prim.Number -> Prim.Number -> Prim.String
578+
579+Module Math
580+-----------
581+
582+Types
583+~~~~~
584+
585+Type Classes
586+~~~~~~~~~~~~
587+
588+Type Class Instances
589+~~~~~~~~~~~~~~~~~~~~
590+
591+Values
592+~~~~~~
593+
594+::
595+
596+ abs :: Prim.Number -> Prim.Number
597+
598+ aceil :: Prim.Number -> Prim.Number
599+
600+ acos :: Prim.Number -> Prim.Number
601+
602+ asin :: Prim.Number -> Prim.Number
603+
604+ atan :: Prim.Number -> Prim.Number
605+
606+ atan2 :: Prim.Number -> Prim.Number -> Prim.Number
607+
608+ cos :: Prim.Number -> Prim.Number
609+
610+ e :: Prim.Number
611+
612+ exp :: Prim.Number -> Prim.Number
613+
614+ floor :: Prim.Number -> Prim.Number
615+
616+ ln10 :: Prim.Number
617+
618+ ln2 :: Prim.Number
619+
620+ log :: Prim.Number -> Prim.Number
621+
622+ log10e :: Prim.Number
623+
624+ log2e :: Prim.Number
625+
626+ max :: Prim.Number -> Prim.Number
627+
628+ min :: Prim.Number -> Prim.Number
629+
630+ pi :: Prim.Number
631+
632+ pow :: Prim.Number -> Prim.Number
633+
634+ round :: Prim.Number -> Prim.Number
635+
636+ sin :: Prim.Number -> Prim.Number
637+
638+ sqrt :: Prim.Number -> Prim.Number
639+
640+ sqrt1_2 :: Prim.Number
641+
642+ sqrt2 :: Prim.Number
643+
644+ tan :: Prim.Number -> Prim.Number
645+
646+Module Control.Monad.Eff
647+------------------------
648+
649+Types
650+~~~~~
651+
652+::
653+
654+ data Eff :: # ! -> * -> *
655+
656+ type Pure a = forall e. Eff e a
657+
658+Type Classes
659+~~~~~~~~~~~~
660+
661+Type Class Instances
662+~~~~~~~~~~~~~~~~~~~~
663+
664+::
665+
666+ instance Prelude.Monad Eff e
667+
668+Values
669+~~~~~~
670+
671+::
672+
673+ bindEff :: forall b. forall a. forall e. Eff e a -> (a -> Eff e b) -> Eff e b
674+
675+ forE :: forall e. Prim.Number -> Prim.Number -> (Prim.Number -> Eff e { }) -> Eff e { }
676+
677+ foreachE :: forall a. forall e. [a] -> (a -> Eff e { }) -> Eff e { }
678+
679+ retEff :: forall a. forall e. a -> Eff e a
680+
681+ runPure :: forall a. Pure a -> a
682+
683+ untilE :: forall e. Eff e Prim.Boolean -> Eff e { }
684+
685+ whileE :: forall a. forall e. Eff e Prim.Boolean -> Eff e a -> Eff e { }
686+
687+Module Random
688+-------------
689+
690+Types
691+~~~~~
692+
693+::
694+
695+ data Random :: !
696+
697+Type Classes
698+~~~~~~~~~~~~
699+
700+Type Class Instances
701+~~~~~~~~~~~~~~~~~~~~
702+
703+Values
704+~~~~~~
705+
706+::
707+
708+ random :: forall e. Eff (random :: Random | e) Prim.Number
709+
710+Module Control.Monad.Error
711+--------------------------
712+
713+Types
714+~~~~~
715+
716+::
717+
718+ data Error :: * -> !
719+
720+Type Classes
721+~~~~~~~~~~~~
722+
723+Type Class Instances
724+~~~~~~~~~~~~~~~~~~~~
725+
726+Values
727+~~~~~~
728+
729+::
730+
731+ catchError :: forall a. forall r. forall e. (e -> Eff r a) -> Eff (err :: Error e | r) a -> Eff r a
732+
733+ throwError :: forall r. forall e. forall a. e -> Eff (err :: Error e | r) a
734+
735+Module Data.IORef
736+-----------------
737+
738+Types
739+~~~~~
740+
741+::
742+
743+ data IORef :: * -> *
744+
745+ data Ref :: !
746+
747+Type Classes
748+~~~~~~~~~~~~
749+
750+Type Class Instances
751+~~~~~~~~~~~~~~~~~~~~
752+
753+Values
754+~~~~~~
755+
756+::
757+
758+ modifyIORef :: forall r. forall s. IORef s -> (s -> s) -> Eff (ref :: Ref | r) { }
759+
760+ newIORef :: forall r. forall s. s -> Eff (ref :: Ref | r) (IORef s)
761+
762+ readIORef :: forall r. forall s. IORef s -> Eff (ref :: Ref | r) s
763+
764+ unsafeRunIORef :: forall a. forall eff. Eff (ref :: Ref | eff) a -> Eff eff a
765+
766+ writeIORef :: forall r. forall s. IORef s -> s -> Eff (ref :: Ref | r) { }
767+
768+Module Debug.Trace
769+------------------
770+
771+Types
772+~~~~~
773+
774+::
775+
776+ data Trace :: !
777+
778+Type Classes
779+~~~~~~~~~~~~
780+
781+Type Class Instances
782+~~~~~~~~~~~~~~~~~~~~
783+
784+Values
785+~~~~~~
786+
787+::
788+
789+ print :: forall r. forall a. (Prelude.Show (a)) => a -> Eff (trace :: Trace | r) { }
790+
791+ trace :: forall r. Prim.String -> Eff (trace :: Trace | r) { }
792+
793+Module Control.Monad.ST
794+-----------------------
795+
796+Types
797+~~~~~
798+
799+::
800+
801+ data ST :: * -> !
802+
803+ data STArray :: * -> * -> *
804+
805+ data STRef :: * -> * -> *
806+
807+Type Classes
808+~~~~~~~~~~~~
809+
810+Type Class Instances
811+~~~~~~~~~~~~~~~~~~~~
812+
813+Values
814+~~~~~~
815+
816+::
817+
818+ modifySTRef :: forall r. forall h. forall a. STRef h a -> (a -> a) -> Eff (st :: ST h | r) a
819+
820+ newSTArray :: forall r. forall h. forall a. Prim.Number -> a -> Eff (st :: ST h | r) (STArray h a)
821+
822+ newSTRef :: forall r. forall h. forall a. a -> Eff (st :: ST h | r) (STRef h a)
823+
824+ peekSTArray :: forall r. forall h. forall a. STArray h a -> Eff (st :: ST h | r) a
825+
826+ pokeSTArray :: forall r. forall h. forall a. STArray h a -> Prim.Number -> a -> Eff (st :: ST h | r) a
827+
828+ readSTRef :: forall r. forall h. forall a. STRef h a -> Eff (st :: ST h | r) a
829+
830+ runST :: forall r. forall a. forall h. Eff (st :: ST h | r) a -> Eff r a
831+
832+ runSTArray :: forall r. forall a. forall h. Eff (st :: ST h | r) (STArray h a) -> Eff r [a]
833+
834+ writeSTRef :: forall r. forall h. forall a. STRef h a -> a -> Eff (st :: ST h | r) a
835+
836+Module Data.Enum
837+----------------
838+
839+Types
840+~~~~~
841+
842+Type Classes
843+~~~~~~~~~~~~
844+
845+::
846+
847+ class Enum a where
848+ toEnum :: Prim.Number -> Maybe a
849+ fromEnum :: a -> Prim.Number
850+
851+Type Class Instances
852+~~~~~~~~~~~~~~~~~~~~
853+
854+Values
855+~~~~~~
856+
docs/source/syntax.rstnew file+222
@@ -0,0 +1,222 @@
1+Syntax
2+======
3+
4+Whitespace Rules
5+----------------
6+
7+Syntax is whitespace sensitive. The general rule of thumb is that declarations which span multiple lines should be indented past the column on which they were first defined on their subsequent lines.
8+
9+That is, the following is valid::
10+
11+ foo = bar(x) +
12+ baz(x)
13+
14+But this is not::
15+
16+ foo = bar(x) +
17+ baz(x)
18+
19+Operators
20+---------
21+
22+PureScript supports the following unary operators (in precedence order):
23+
24+== =======================
25+ Meaning
26+== =======================
27+\- Numeric negation
28+! Boolean negation
29+~ Binary negation
30+\+ Unary plus (numeric)
31+== =======================
32+
33+and the following binary operators (in precedence order):
34+
35+==== =====================
36+ Meaning
37+==== =====================
38+\+ Numeric addition
39+\- Numeric subtraction
40+\* Numeric multiplication
41+/ Numeric division
42+% Numeric modulus
43+== Equality check
44+!= Inequality check
45+< Less than
46+<= Less than or equal
47+> Greater than
48+>= Greater than or equal
49+&& Boolean AND
50+|| Boolean OR
51+& Binary AND
52+\| Binary OR
53+^ Binary XOR
54+<< Shift Left
55+>> Shift Right
56+\>>> Zero-Fill Shift Right
57+++ String concatenation
58+==== =====================
59+
60+Literal Values
61+--------------
62+
63+Numeric literals can be integers or floating point numbers. Numbers in hexadecimal notation should be preceded by the characters ``0x``::
64+
65+ 16
66+ 16.0
67+ 0xF0
68+
69+String literals are enclosed in double-quotes and may extend over multiple lines. Line breaks should be surrounded by slashes as follows::
70+
71+ "Hello World"
72+
73+ "Hello \
74+ \World"
75+
76+The two boolean literals are ``true`` and ``false``.
77+
78+Array Literals
79+--------------
80+
81+Array literals are surrounded by square brackets, as in Javascript::
82+
83+ []
84+ [1, 2, 3]
85+
86+Record Literals
87+---------------
88+
89+Record literals are surrounded by braces, as in Javascript::
90+
91+ {}
92+ { foo: "Foo", bar: 1 }
93+
94+Array Indexing
95+--------------
96+
97+To retrieve the element of an array at an index, use the ``!!`` operator::
98+
99+ arr !! 0
100+
101+This example corresponds to the Javascript ``arr[0]``.
102+
103+Property Accessors
104+------------------
105+
106+To access a property of a record, use a dot, followed by the property name, as in Javascript::
107+
108+ rec.propertyName
109+
110+Functions
111+---------
112+
113+Functions are introduced by using a backslash followed by a list of argument names::
114+
115+ example1 = \a b -> a + b
116+
117+which would correspond to the following Javascript::
118+
119+ function example1(a) {
120+ return function (b) {
121+ return a + b;
122+ }
123+ }
124+
125+Function application is indicated by just the juxtaposition of a function with its arugments::
126+
127+ example1 10 20
128+
129+Functions can also be defined at the top level by providing a list of patterns and an optional guard on the left hand side of the equals sign::
130+
131+ f [] [] = []
132+ f (x:xs) (y:ys) = x + y : f xs ys
133+
134+If-Then-Else Expressions
135+------------------------
136+
137+The ``if``, ``then`` and ``else`` keywords can be used to create conditional expressions. In this case, the ``else`` block is always required.
138+
139+For example::
140+
141+ conditional = if 2 > 1 then "ok" else "oops"
142+
143+Do Notation
144+-----------
145+
146+The `do` keyword introduces simple syntactic sugar for monadic expressions.
147+
148+Here is an example, using the maybe monad::
149+
150+ data Maybe a = Nothing | Just a
151+
152+ instance Monad Maybe where
153+ ret = Just
154+ (>>=) Nothing _ = Nothing
155+ (>>=) (Just a) f = f a
156+
157+ isEven n | n % 2 == 0 = Just {}
158+ isEven _ = Nothing
159+
160+ evenSum a b = do
161+ n <- a
162+ m <- b
163+ let sum = n + m
164+ isEven sum
165+ ret sum
166+
167+``isEven`` adds two values of type ``Maybe Number`` and returns their sum, if the sum is even. If the sum is odd, ``evenSum`` returns ``Nothing``.
168+
169+When using `do` notation, the corresponding type constructor must be an instance of the `Prelude.Monad` type class, which defines the ``ret`` and ``>>=`` functions.
170+
171+Statements can have the following form:
172+
173+- ``a <- x`` which desugars to ``m.bind x (\a -> ...)` `
174+- ``let a = x`` which desugars to ``(\a -> ...)(x)``
175+- ``x`` which desugars to ``m.bind x (\_ -> ...)`` or just ``x`` if this is the last statement.
176+
177+Binders can be used on the left hand side of ``<-`` or ``=``. For example::
178+
179+ test arr = do
180+ (x:y:_) <- arr
181+ ret (x + y)
182+
183+A pattern match failure will generate a runtime exception, just as in the case of a regular ``case`` statement.
184+
185+Operators
186+---------
187+
188+In addition to the standard operators, user-defined infix operators can be created by enclosing names in parentheses.
189+
190+E.g. to create a synonym for string concatenation::
191+
192+ (<>) = \s1 s2 -> s1 ++ s2
193+
194+ greeting = "Hello" <> "World!"
195+
196+Regular functions can be used as operators by enclosing their names in backticks::
197+
198+ foo = \x y -> x * y + y
199+
200+ test = 10 `foo` 20
201+
202+Fixity declarations can associate a precedence level, which is a natural number, to a user-defined operator, and specify which way it associates::
203+
204+ infixl 5 <>
205+ infixr 7 %%
206+
207+Record Updates
208+--------------
209+
210+Properties on records can be updated using the following syntax::
211+
212+ o { key = value, ..., key = value }
213+
214+For example, the following function increments the ``foo`` property on its argument::
215+
216+ incr o = o { foo = o.foo + 1 }
217+
218+The generated Javascript assumes the existence of a method called ``Object.extend`` such that ``Object.extend(o, p)`` takes an object ``o`` and generates a shallow copy of ``o`` including the properties of ``p``. A simple JQuery implementation of this specification is::
219+
220+ Object.prototype.extend = function(o, p) {
221+ return $.extend({}, o, p);
222+ };
docs/source/typeclasses.rstnew file+26
@@ -0,0 +1,26 @@
1+Type Classes
2+============
3+
4+PureScript has basic support for type classes via the `class` and `instance` keywords.
5+
6+Type class instances must be of the form `String`, `Number`, `Boolean`, `[t]` or `C t1 ... tn`, and only a single type class parameter is supported.
7+
8+Type class instances are resolved based on the order in which they appeared in the source files. In particular, overlapping instances are permitted.
9+
10+Here is an example of the `Show` typeclass, with instances for Strings, Booleans and arrays::
11+
12+ class Show a where
13+ show :: a -> String
14+
15+ instance Show String where
16+ show s = s
17+
18+ instance Show Boolean where
19+ show true = "true"
20+ show false = "false"
21+
22+ instance (Show a) => Show [a] where
23+ show [] = "[]"
24+ show (x:xs) = show x ++ " : " ++ showArray xs
25+
26+ example = show [true, false]
docs/source/types.rstnew file+159
@@ -0,0 +1,159 @@
1+Types
2+=====
3+
4+The type system defines the following types:
5+
6+- Primitive Types: Number, String, Boolean
7+- Arrays
8+- Records
9+- Tagged Unions
10+- Functions
11+- Polymorphic Types
12+- Constrained Types
13+- Type Synonyms
14+- Rows
15+
16+Primitive Types
17+---------------
18+
19+The three primitive types ``String``, ``Number`` and ``Boolean`` correspond to their Javascript equivalents at runtime.
20+
21+Arrays
22+------
23+
24+PureScript arrays correspond to Javascript arrays at runtime, but all elements in an array must have the same type.
25+
26+Records
27+-------
28+
29+PureScript records correspond to Javascript objects. They may have zero or more named fields, each with their own types.
30+
31+Tagged Unions
32+-------------
33+
34+Tagged unions consist of one or more constructors, each of which takes zero or more arguments.
35+
36+Tagged unions can only be created using their constructors, and deconstructed through pattern matching (see later).
37+
38+For example::
39+
40+ data Foo a = Foo | Bar String
41+
42+ runFoo Foo = "It's a Foo"
43+ runFoo (Bar s) = "It's a Bar. The string is " ++ s
44+
45+ test = runFoo Foo ++ runFoo (Bar "Test")
46+
47+In the example, Foo is a tagged union type which has two constructors. It's first constructor `Foo` takes no argument, and it's second ``Bar`` takes one, which must be a String.
48+
49+``runFoo`` is an example of pattern matching on a tagged union type to discover its constructor, and the last line shows how ``Foo``s are constructed.
50+
51+Functions
52+---------
53+
54+Functions in PureScript are like their Javascript counterparts, but always have exactly one argument.
55+
56+Polymorphic Types
57+-----------------
58+
59+Expressions defined at the top level may have polymorphic types.
60+
61+Here is an example::
62+
63+ identity x = x
64+
65+`identity` is inferred to have (polymorphic) type ``forall t0. t0 -> t0``. This means that for any type ``t0``, ``identity`` can be given a value of type ``t0`` and will give back a value of the same type.
66+
67+A type annotation can also be provided::
68+
69+ identity :: forall a. a -> a
70+ identity x = x
71+
72+Row Polymorphism
73+----------------
74+
75+Polymorphism is not limited to abstracting over types. Values may also be polymorphic in types with other kinds, such as rows or effects (see "Kind System").
76+
77+For example, the following function accesses two properties on a record::
78+
79+ addProps o = o.foo + o.bar
80+
81+The inferred type of `addProps` is
82+
83+::
84+ forall r. { foo :: Number, bar :: Number | r } -> Number
85+
86+Here, the type variable ``r`` has kind ``# *`` - it represents a `row` of `types`. It can be instantiated with any row of named types.
87+
88+In other words, ``addProps`` accepts any record which has properties ``Foo`` and ``Bar``, and *any other record properties*.
89+
90+Therefore, the following application compiles::
91+
92+ addProps { foo: 1, bar: 2, baz: 3 }
93+
94+even though the type of ``addProps`` does not mention the property ``baz``. However, the following does not compile::
95+
96+ addProps { foo: 1 }
97+
98+since the `bar` property is missing.
99+
100+Rank N Types
101+------------
102+
103+It is also possible for the ``forall`` quantifier to appear on the left of a function arrow, inside types record fields and data constructors, and in type synonyms.
104+
105+In most cases, a type annotation is necessary when using this feature.
106+
107+As an example, we can pass a polymorphic function as an argument to another function::
108+
109+ poly :: (forall a. a -> a) -> Boolean
110+ poly f = (f 0 < 1) == f true
111+
112+Notice that the polymorphic function's type argument is instantiated to both `Number` and `Boolean`.
113+
114+An argument to ``poly`` must indeed be polymorphic. For example, the following fails::
115+
116+ test = poly (\n -> n + 1)
117+
118+since the skolemized type variable ``a`` does not unify with ``Number``.
119+
120+Rows
121+----
122+
123+A row of types represents an unordered collection of named types without duplicates.
124+
125+Rows have kind ``# k`` for some kind ``k``, and so values do not have types which are rows. Rather, rows can be used in type signatures to define record types or other type where labelled, unordered types are useful.
126+
127+To denote a closed row, separate the fields with commas, with each label separated from its type with a double colon::
128+
129+ (name :: String, age :: Number)
130+
131+It may be necessary, depending on the context, to surround a row in parentheses.
132+
133+To denote an open row (i.e. one which may unify with another row to add new fields), separate the specified terms from a row variable by a pipe::
134+
135+ (name :: String, age :: Number | r)
136+
137+Type Synonyms
138+-------------
139+
140+For convenience, it is possible to declare a synonym for a type using the ``type`` keyword. Type synonyms can include type arguments.
141+
142+For example::
143+
144+ type Foo = { foo :: Number, bar Number }
145+
146+ addFoo :: Foo -> Number
147+ addFoo = \o -> o.foo + o.bar
148+
149+Constrained Types
150+-----------------
151+
152+Polymorphic types may be predicated on one or more ``constraints``. See the chapter on type classes for more information.
153+
154+Type Annotations
155+----------------
156+
157+Most types can be inferred (not including Rank N Types and constrained types), but annotations can optionally be provided using a double-colon::
158+
159+ one = 1 :: Number
examples/.gitignorenew file+1
@@ -0,0 +1 @@
1+shelltest/tests
examples/failing/Arrays.pursnew file+5
@@ -0,0 +1,5 @@
1+module Data.Array where
2+
3+ import Prelude
4+
5+ test = \arr -> arr !! (0 !! 0)
examples/failing/Do.pursnew file+8
@@ -0,0 +1,8 @@
1+module Do where
2+
3+test1 = do let x = 1
4+
5+test2 y = do x <- y
6+
7+test3 = do return 1
8+ return 2
examples/failing/Import.pursnew file+3
@@ -0,0 +1,3 @@
1+module Module where
2+
3+ import UndefinedModule
examples/failing/ImportExplicit.pursnew file+14
@@ -0,0 +1,14 @@
1+module M1 where
2+
3+ data X = X | Y
4+ data Z = Z
5+
6+module Main where
7+
8+ import M1 (X)
9+
10+ testX = X
11+ testY = Y
12+ testZ = Z
13+
14+ main = Debug.Trace.trace "Done"
examples/failing/ImportExplicit2.pursnew file+7
@@ -0,0 +1,7 @@
1+module M1 where
2+
3+ foo = "foo"
4+
5+module Main where
6+
7+ import M1 (X)
examples/failing/KindError.pursnew file+3
@@ -0,0 +1,3 @@
1+module KindError where
2+
3+ data KindError f a = One f | Two (f a)
examples/failing/MPTCs.pursnew file+7
@@ -0,0 +1,7 @@
1+module Main where
2+
3+class Foo a where
4+ f :: a -> a
5+
6+instance Foo String String where
7+ f a = a
examples/failing/ModuleDeps.pursnew file+7
@@ -0,0 +1,7 @@
1+module M1 where
2+
3+import M2
4+
5+module M2 where
6+
7+import M1
examples/failing/MutRec.pursnew file+5
@@ -0,0 +1,5 @@
1+module MutRec where
2+
3+x = y
4+
5+y = x
examples/failing/MutRec2.pursnew file+3
@@ -0,0 +1,3 @@
1+module MutRec2 where
2+
3+x = x
examples/failing/NullaryAbs.pursnew file+3
@@ -0,0 +1,3 @@
1+module NullaryAbs where
2+
3+ func = \ -> "no"
examples/failing/Object.pursnew file+5
@@ -0,0 +1,5 @@
1+module Object where
2+
3+test o = o.foo
4+
5+test1 = test {}
examples/failing/OverlappingVars.pursnew file+12
@@ -0,0 +1,12 @@
1+module Main where
2+
3+class OverlappingVars a where
4+ f :: a -> a
5+
6+data Foo a b = Foo a b
7+
8+instance OverlappingVars (Foo a a) where
9+ f a = a
10+
11+test = f (Foo "" 0)
12+
examples/failing/Rank2Types.pursnew file+7
@@ -0,0 +1,7 @@
1+module Rank2Types where
2+
3+ import Prelude
4+
5+ foreign import test :: (forall a. a -> a) -> Number
6+
7+ test1 = test (\n -> n + 1)
examples/failing/ReadShow.pursnew file+7
@@ -0,0 +1,7 @@
1+module ReadShow where
2+
3+ foreign import read :: forall a. String -> a
4+
5+ foreign import show :: forall a. a -> String
6+
7+ test = \x -> show (read x)
examples/failing/Reserved.pursnew file+4
@@ -0,0 +1,4 @@
1+module Reserved where
2+
3+(<) :: Number -> Number -> Number
4+(<) a b = !(a >= b)
examples/failing/SkolemEscape.pursnew file+5
@@ -0,0 +1,5 @@
1+module SkolemEscape where
2+
3+ foreign import foo :: (forall a. a -> a) -> Number
4+
5+ test = \x -> foo x
examples/failing/SkolemEscape2.pursnew file+9
@@ -0,0 +1,9 @@
1+module SkolemEscape where
2+
3+import Prelude
4+import Control.Monad.Eff
5+import Control.Monad.ST
6+
7+test _ = do
8+ r <- runST (newSTRef 0)
9+ return 0
examples/failing/TypeClassInstances.pursnew file+8
@@ -0,0 +1,8 @@
1+module TypeClassInstances where
2+
3+class A a where
4+ a :: a -> String
5+ b :: a -> Number
6+
7+instance A String where
8+ a s = s
examples/failing/TypeClasses.pursnew file+7
@@ -0,0 +1,7 @@
1+module TypeClasses where
2+
3+class Show a where
4+ show :: a -> String
5+
6+instance TypeClasses.Show ([[String]]) where
7+ show _ = "array"
examples/failing/TypeClasses2.pursnew file+15
@@ -0,0 +1,15 @@
1+module TC1 where
2+
3+class Show a where
4+ show :: a -> String
5+
6+module TC2 where
7+
8+instance TC1.Show String where
9+ show s = s
10+
11+module TC3 where
12+
13+import TC1
14+
15+test = show "testing"
examples/failing/TypeError.pursnew file+5
@@ -0,0 +1,5 @@
1+module TypeError where
2+
3+ import Prelude
4+
5+ test = 1 ++ "A"
examples/failing/TypeSynonyms.pursnew file+5
@@ -0,0 +1,5 @@
1+module TypeSynonyms where
2+
3+type T1 = [T2]
4+
5+type T2 = T1
examples/failing/TypeSynonyms2.pursnew file+9
@@ -0,0 +1,9 @@
1+module TypeSynonyms2 where
2+
3+class Foo a where
4+ foo :: a -> String
5+
6+type Bar = String
7+
8+instance Foo Bar where
9+ foo s = s
examples/failing/TypeSynonyms3.pursnew file+13
@@ -0,0 +1,13 @@
1+module TypeSynonyms2 where
2+
3+class Foo a where
4+ foo :: a -> String
5+
6+type Bar = String
7+
8+module M where
9+
10+import TypeSynonyms2
11+
12+instance TypeSynonyms2.Foo Bar where
13+ foo s = s
examples/passing/Applicative.pursnew file+16
@@ -0,0 +1,16 @@
1+module Applicative where
2+
3+class Applicative f where
4+ pure :: forall a. a -> f a
5+ (<*>) :: forall a b. f (a -> b) -> f a -> f b
6+
7+data Maybe a = Nothing | Just a
8+
9+instance Applicative Maybe where
10+ pure = Just
11+ (<*>) (Just f) (Just a) = Just (f a)
12+ (<*>) _ _ = Nothing
13+
14+module Main where
15+
16+main = Debug.Trace.trace "Done"
examples/passing/ArrayType.pursnew file+17
@@ -0,0 +1,17 @@
1+module ArrayType where
2+
3+test :: [] Number
4+test = [1, 2, 3]
5+
6+class Functor f where
7+ fmap :: forall a b. (a -> b) -> f a -> f b
8+
9+foreign import (:) :: forall a. a -> [a] -> [a]
10+
11+instance Functor [] where
12+ fmap _ [] = []
13+ fmap f (x:xs) = f x : fmap f xs
14+
15+module Main where
16+
17+main = Debug.Trace.trace "Done"
examples/passing/Arrays.pursnew file+34
@@ -0,0 +1,34 @@
1+module Data.ArrayTests where
2+
3+import Prelude
4+
5+test1 arr = arr !! 0 + arr !! 1 + 1
6+
7+test2 = \arr -> case arr of
8+ [x, y] -> x + y
9+ [x] -> x
10+ [] -> 0
11+ (x : y : _) -> x + y
12+
13+data Tree = One Number | Some [Tree]
14+
15+test3 = \tree sum -> case tree of
16+ One n -> n
17+ Some (n1 : n2 : rest) -> test3 n1 sum * 10 + test3 n2 sum * 5 + sum rest
18+
19+test4 = \arr -> case arr of
20+ [] -> 0
21+ [_] -> 0
22+ x : y : xs -> x * y + test4 xs
23+
24+module Main where
25+
26+import Data.Array
27+import Prelude
28+
29+main = do
30+ let x = [3,2,1]
31+ let y = sort x
32+ if x == [3,2,1]
33+ then Debug.Trace.trace "Done"
34+ else Control.Monad.Error.throwError "Not done"
examples/passing/Auto.pursnew file+15
@@ -0,0 +1,15 @@
1+module Auto where
2+
3+ data Auto s i o = Auto { state :: s, step :: s -> i -> o }
4+
5+ type SomeAuto i o = forall r. (forall s. Auto s i o -> r) -> r
6+
7+ exists :: forall s i o. s -> (s -> i -> o) -> SomeAuto i o
8+ exists = \state step f -> f (Auto { state: state, step: step })
9+
10+ run :: forall i o. SomeAuto i o -> i -> o
11+ run = \s i -> s (\a -> case a of Auto a -> a.step a.state i)
12+
13+module Main where
14+
15+main = Debug.Trace.trace "Done"
examples/passing/BindersInFunctions.pursnew file+12
@@ -0,0 +1,12 @@
1+module Main where
2+
3+import Prelude
4+import Data.Array
5+
6+tails = map (\(_:xs) -> xs)
7+
8+main =
9+ let ts = tails [[1, 2, 3], [4, 5], [6]] in
10+ if ts == [[2, 3], [5], []]
11+ then Debug.Trace.trace "Done"
12+ else Control.Monad.Error.throwError "Incorrect result from 'tails'."
examples/passing/Church.pursnew file+18
@@ -0,0 +1,18 @@
1+module Church where
2+
3+ type List a = forall r. r -> (a -> r -> r) -> r
4+
5+ empty :: forall a. List a
6+ empty = \r f -> r
7+
8+ cons :: forall a. a -> List a -> List a
9+ cons = \a l r f -> f a (l r f)
10+
11+ append :: forall a. List a -> List a -> List a
12+ append = \l1 l2 r f -> l2 (l1 r f) f
13+
14+ test = append (cons 1 empty) (cons 2 empty)
15+
16+module Main where
17+
18+main = Debug.Trace.trace "Done"
examples/passing/Collatz.pursnew file+18
@@ -0,0 +1,18 @@
1+module Main where
2+
3+import Prelude
4+import Control.Monad.Eff
5+import Control.Monad.ST
6+
7+collatz :: Number -> Number
8+collatz n = runPure (runST (do
9+ r <- newSTRef n
10+ count <- newSTRef 0
11+ untilE $ do
12+ modifySTRef count $ (+) 1
13+ m <- readSTRef r
14+ writeSTRef r $ if m % 2 == 0 then m / 2 else 3 * m + 1
15+ return $ m == 1
16+ readSTRef count))
17+
18+main = Debug.Trace.print $ collatz 1000
examples/passing/Conditional.pursnew file+9
@@ -0,0 +1,9 @@
1+module Conditional where
2+
3+ fns = \f -> if f true then f else \x -> x
4+
5+ not = \x -> if x then false else true
6+
7+module Main where
8+
9+main = Debug.Trace.trace "Done"
examples/passing/Cons.pursnew file+12
@@ -0,0 +1,12 @@
1+module Cons where
2+
3+ import Prelude
4+ import Data.Array
5+
6+ test1 = \xs -> 1 : xs
7+
8+ test2 = 1 : 2 : 3 : []
9+
10+module Main where
11+
12+main = Debug.Trace.trace "Done"
examples/passing/Console.pursnew file+13
@@ -0,0 +1,13 @@
1+module Main where
2+
3+import Prelude
4+import Control.Monad.Eff
5+import Debug.Trace
6+
7+replicateM_ :: forall m a. (Monad m) => Number -> m a -> m {}
8+replicateM_ 0 _ = return {}
9+replicateM_ n act = do
10+ act
11+ replicateM_ (n - 1) act
12+
13+main = replicateM_ 10 (trace "Hello World!")
examples/passing/DataAndType.pursnew file+9
@@ -0,0 +1,9 @@
1+module DataAndType where
2+
3+data A = A B
4+
5+type B = A
6+
7+module Main where
8+
9+main = Debug.Trace.trace "Done"
examples/passing/DataImport.pursnew file+13
@@ -0,0 +1,13 @@
1+module M1 where
2+
3+data Test = Test String
4+
5+module Main where
6+
7+import M1
8+
9+unTest (Test s) = s
10+
11+main = do
12+ let x = unTest (Test "Done")
13+ Debug.Trace.trace x
examples/passing/Do.pursnew file+49
@@ -0,0 +1,49 @@
1+module Do where
2+
3+import Prelude
4+
5+data Maybe a = Nothing | Just a
6+
7+instance Prelude.Monad Maybe where
8+ return = Just
9+ (>>=) Nothing _ = Nothing
10+ (>>=) (Just a) f = f a
11+
12+test1 = \_ -> do
13+ Just "abc"
14+
15+test2 = \_ -> do
16+ (x : _) <- Just [1, 2, 3]
17+ (y : _) <- Just [4, 5, 6]
18+ Just (x + y)
19+
20+test3 = \_ -> do
21+ Just 1
22+ Nothing :: Maybe Number
23+ Just 2
24+
25+test4 mx my = do
26+ x <- mx
27+ y <- my
28+ Just (x + y + 1)
29+
30+test5 mx my mz = do
31+ x <- mx
32+ y <- my
33+ let sum = x + y
34+ z <- mz
35+ Just (z + sum + 1)
36+
37+test6 mx = \_ -> do
38+ let Just x = mx
39+ Just x
40+
41+test8 = \_ -> do
42+ Just (do
43+ Just 1)
44+
45+test9 = \_ -> (+) <$> Just 1 <*> Just 2
46+
47+module Main where
48+
49+main = Debug.Trace.trace "Done"
examples/passing/Dollar.pursnew file+16
@@ -0,0 +1,16 @@
1+module Dollar where
2+
3+($) :: forall a b. (a -> b) -> a -> b
4+($) f x = f x
5+
6+infixr 1000 $
7+
8+id x = x
9+
10+test1 x = id $ id $ id $ id $ x
11+
12+test2 x = id id $ id x
13+
14+module Main where
15+
16+main = Debug.Trace.trace "Done"
examples/passing/DottedModules.pursnew file+20
@@ -0,0 +1,20 @@
1+module Some.Module.Name where
2+
3+ class Foo a where
4+ foo :: a -> a
5+
6+ data Text = Text String
7+
8+ x = Text "Done"
9+
10+module Main where
11+
12+ import Prelude
13+ import Some.Module.Name
14+
15+ instance Some.Module.Name.Foo String where
16+ foo s = s
17+
18+ unwrap (Text x) = x
19+
20+ main = Debug.Trace.print $ foo $ unwrap x
examples/passing/Eff.pursnew file+27
@@ -0,0 +1,27 @@
1+module TestEff where
2+
3+import Prelude
4+import Control.Monad.Eff
5+import Control.Monad.ST
6+import Control.Monad.Error
7+import Debug.Trace
8+
9+test1 = catchError (\s -> return 0) $ do
10+ trace "Testing"
11+ throwError "Error!"
12+
13+test2 = runPure (runST (do
14+ ref <- newSTRef 0
15+ modifySTRef ref $ \n -> n + 1
16+ readSTRef ref))
17+
18+module Main where
19+
20+import Prelude
21+import Control.Monad.Eff
22+import TestEff
23+
24+main = do
25+ n <- test1
26+ Debug.Trace.print n
27+ Debug.Trace.print test2
examples/passing/EmptyDataDecls.pursnew file+20
@@ -0,0 +1,20 @@
1+module Main where
2+
3+import Prelude
4+import Data.Array
5+
6+data Z
7+data S n
8+
9+data Array n a = Array [a]
10+
11+nil :: forall a. Array Z a
12+nil = Array []
13+
14+cons :: forall a n. a -> Array n a -> Array (S n) a
15+cons x (Array xs) = Array $ x : xs
16+
17+main = let (Array xs) = cons 1 $ cons 2 $ cons 3 nil
18+ in if xs == [1, 2, 3]
19+ then Debug.Trace.trace "Done"
20+ else Control.Monad.Error.throwError "Failed"
examples/passing/EmptyTypeClass.pursnew file+18
@@ -0,0 +1,18 @@
1+module EmptyTypeClass where
2+
3+class Partial
4+
5+head :: forall a. (Partial) => [a] -> a
6+head (x:xs) = x
7+
8+module AllowPartialFns where
9+
10+instance EmptyTypeClass.Partial
11+
12+module Main where
13+
14+import Prelude
15+import AllowPartialFns
16+import EmptyTypeClass
17+
18+main = Debug.Trace.trace $ head ["Done"]
examples/passing/ExternData.pursnew file+19
@@ -0,0 +1,19 @@
1+module ExternData where
2+
3+ foreign import data IO :: * -> *
4+
5+ foreign import fmap :: forall a b. IO a -> (a -> b) -> IO b
6+
7+ foreign import return :: forall a. a -> IO a
8+
9+ foreign import bind :: forall a b. IO a -> (a -> IO b) -> IO b
10+
11+ foreign import showMessage :: String -> IO { }
12+
13+ foreign import prompt :: IO String
14+
15+ main = \_ -> prompt `bind` \s -> showMessage s
16+
17+module Main where
18+
19+main = Debug.Trace.trace "Done"
examples/passing/ExternRaw.pursnew file+15
@@ -0,0 +1,15 @@
1+module ExternRaw where
2+
3+foreign import first "function first(xs) { return xs[0]; }" :: forall a. [a] -> a
4+
5+foreign import loop "function loop() { while (true) {} }" :: forall a. a
6+
7+foreign import concat "function concat(xs) { \
8+ \ return function(ys) { \
9+ \ return xs.concat(ys); \
10+ \ };\
11+ \}" :: forall a. [a] -> [a] -> [a]
12+
13+module Main where
14+
15+main = Debug.Trace.trace "Done"
examples/passing/FFI.pursnew file+16
@@ -0,0 +1,16 @@
1+module FFI where
2+
3+foreign import foo :: String -> String
4+
5+bar :: String -> String
6+bar _ = foo "test"
7+
8+module FFIModuleTest where
9+
10+import FFI
11+
12+baz _ = foo "test"
13+
14+module Main where
15+
16+main = Debug.Trace.trace "Done"
examples/passing/FunctionScope.pursnew file+17
@@ -0,0 +1,17 @@
1+module FunctionScope where
2+
3+ import Prelude
4+
5+ mkValue :: Number -> Number
6+ mkValue id = id
7+
8+module Main where
9+
10+ import Prelude
11+ import FunctionScope
12+
13+ main = do
14+ let value = mkValue 1
15+ if value == 1
16+ then Debug.Trace.trace "Done"
17+ else Control.Monad.Error.throwError "Not done"
examples/passing/Functions.pursnew file+17
@@ -0,0 +1,17 @@
1+module Functions where
2+
3+ import Prelude
4+
5+ test1 = \_ -> 0
6+
7+ test2 = \a b -> a + b + 1
8+
9+ test3 = \a -> a
10+
11+ test4 = \(%%) -> 1 %% 2
12+
13+ test5 = \(+++) (***) -> 1 +++ 2 *** 3
14+
15+module Main where
16+
17+main = Debug.Trace.trace "Done"
examples/passing/Functions2.pursnew file+17
@@ -0,0 +1,17 @@
1+module Functions2 where
2+
3+ import Prelude
4+
5+ test :: forall a b. a -> b -> a
6+ test = \const _ -> const
7+
8+module Main where
9+
10+ import Prelude
11+ import Functions2
12+
13+ main = do
14+ let value = test "Done" {}
15+ if value == "Done"
16+ then Debug.Trace.trace "Done"
17+ else Control.Monad.Error.throwError "Not done"
examples/passing/Guards.pursnew file+16
@@ -0,0 +1,16 @@
1+module Guards where
2+
3+ import Prelude
4+
5+ collatz = \x -> case x of
6+ y | y % 2 == 0 -> y / 2
7+ y -> y * 3 + 1
8+
9+ -- Guards have access to current scope
10+ collatz2 = \x y -> case x of
11+ z | y > 0 -> z / 2
12+ z -> z * 3 + 1
13+
14+module Main where
15+
16+main = Debug.Trace.trace "Done"
examples/passing/Import.pursnew file+16
@@ -0,0 +1,16 @@
1+module M1 where
2+
3+ id :: forall a. a -> a
4+ id = \x -> x
5+
6+ foo = id
7+
8+module M2 where
9+
10+ import M1
11+
12+ main = \_ -> foo 42
13+
14+module Main where
15+
16+main = Debug.Trace.trace "Done"
examples/passing/ImportExplicit.pursnew file+14
@@ -0,0 +1,14 @@
1+module M1 where
2+
3+ data X = X | Y
4+ data Z = Z
5+
6+module Main where
7+
8+ import M1 (X)
9+
10+ testX :: X
11+ testX = X
12+ testY = Y
13+
14+ main = Debug.Trace.trace "Done"
examples/passing/InferRecFunWithConstrainedArgument.pursnew file+8
@@ -0,0 +1,8 @@
1+module Main where
2+
3+import Prelude
4+
5+test 100 = 100
6+test n = test(1 + n)
7+
8+main = Debug.Trace.print $ test 0
examples/passing/JSReserved.pursnew file+21
@@ -0,0 +1,21 @@
1+module JSReserved where
2+
3+ import Prelude
4+
5+ yield = 0
6+ member = 1
7+
8+ public = \return -> return
9+
10+ this catch = catch
11+
12+module Main where
13+
14+ import Prelude
15+ import Data.Array
16+ import JSReserved
17+
18+ main = Debug.Trace.print [ yield
19+ , member
20+ , this 1
21+ , public 1 ]
examples/passing/Let.pursnew file+18
@@ -0,0 +1,18 @@
1+module Main where
2+
3+import Prelude
4+import Control.Monad.Eff
5+
6+test1 x = let y = x + 1 in y
7+
8+test2 x y =
9+ let x' = x + 1 in
10+ let y' = y + 1 in
11+ x' + y'
12+
13+test3 x = let 1 = x in 2
14+
15+main = do
16+ Debug.Trace.print (test1 1)
17+ Debug.Trace.print (test2 1 2)
18+ Debug.Trace.print (test3 1)
examples/passing/List.pursnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+import Prelude
4+import Control.Monad.Eff
5+import Data.Array
6+import Global
7+
8+main = do
9+ let test1 = concat [1, 2, 3] [4, 5, 6]
10+ Debug.Trace.print test1
examples/passing/MPTCs.pursnew file+24
@@ -0,0 +1,24 @@
1+module Main where
2+
3+import Prelude
4+import Data.Array
5+
6+class NullaryTypeClass where
7+ greeting :: String
8+
9+instance NullaryTypeClass where
10+ greeting = "Hello, World!"
11+
12+class Coerce a b where
13+ coerce :: a -> b
14+
15+instance Coerce a a where
16+ coerce a = a
17+
18+instance (Prelude.Show a) => Coerce a String where
19+ coerce = show
20+
21+instance (Coerce a b) => Coerce [a] [b] where
22+ coerce = map coerce
23+
24+main = Debug.Trace.print $ coerce [greeting] :: [String]
examples/passing/Match.pursnew file+9
@@ -0,0 +1,9 @@
1+module Match where
2+
3+ data Foo a = Foo
4+
5+ foo = \f -> case f of Foo -> "foo"
6+
7+module Main where
8+
9+main = Debug.Trace.trace "Done"
examples/passing/Math.pursnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+ import Prelude
4+ import Debug.Trace
5+ import Control.Monad.Eff
6+
7+ main = do
8+ print $ Math.sin 0
9+ print $ Math.sin $ Math.pi * 0.5
10+ print $ Math.e / Math.ln2
examples/passing/Maybe.pursnew file+12
@@ -0,0 +1,12 @@
1+module Main where
2+
3+import Prelude
4+import Data.Maybe
5+import Global
6+
7+main = do
8+ let test1 = fromMaybe 0 $ do
9+ a <- Just 1
10+ b <- Just 2
11+ return (a + b)
12+ Debug.Trace.print test1
examples/passing/Module.pursnew file+28
@@ -0,0 +1,28 @@
1+module M1 where
2+
3+ import Prelude
4+
5+ data Foo = Foo String
6+
7+ foo :: M1.Foo -> String
8+ foo = \f -> case f of Foo s -> s ++ "foo"
9+
10+ bar :: Foo -> String
11+ bar = foo
12+
13+ incr :: Number -> Number
14+ incr x = x + 1
15+
16+module M2 where
17+
18+ import Prelude
19+
20+ baz :: M1.Foo -> String
21+ baz = M1.foo
22+
23+ match :: M1.Foo -> String
24+ match = \f -> case f of M1.Foo s -> s ++ "foo"
25+
26+module Main where
27+
28+main = Debug.Trace.trace "Done"
examples/passing/ModuleDeps.pursnew file+17
@@ -0,0 +1,17 @@
1+module M1 where
2+
3+import M2
4+
5+foo = M3.baz
6+
7+module M2 where
8+
9+bar = M3.baz
10+
11+module M3 where
12+
13+baz = 1
14+
15+module Main where
16+
17+main = Debug.Trace.trace "Done"
examples/passing/Monad.pursnew file+32
@@ -0,0 +1,32 @@
1+module MonadTest where
2+
3+ type Monad m = { return :: forall a. a -> m a
4+ , bind :: forall a b. m a -> (a -> m b) -> m b }
5+
6+ data Id a = Id a
7+
8+ id :: Monad Id
9+ id = { return : Id
10+ , bind : \ma f -> case ma of Id a -> f a }
11+
12+ data Maybe a = Nothing | Just a
13+
14+ maybe :: Monad Maybe
15+ maybe = { return : Just
16+ , bind : \ma f -> case ma of
17+ Nothing -> Nothing
18+ Just a -> f a
19+ }
20+
21+ test :: forall m. Monad m -> m Number
22+ test = \m -> m.bind (m.return 1) (\n1 ->
23+ m.bind (m.return "Test") (\n2 ->
24+ m.return n1))
25+
26+ test1 = test id
27+
28+ test2 = test maybe
29+
30+module Main where
31+
32+main = Debug.Trace.trace "Done"
examples/passing/MonadState.pursnew file+35
@@ -0,0 +1,35 @@
1+module Main where
2+
3+import Prelude
4+import Data.Tuple
5+
6+class MonadState s m where
7+ get :: m s
8+ put :: s -> m {}
9+
10+data State s a = State (s -> Tuple s a)
11+
12+runState s (State f) = f s
13+
14+instance Prelude.Monad (State s) where
15+ return a = State $ \s -> Tuple s a
16+ (>>=) f g = State $ \s -> let (Tuple s1 a) = runState s f in
17+ runState s1 (g a)
18+
19+instance MonadState s (State s) where
20+ get = State (\s -> Tuple s s)
21+ put s = State (\_ -> Tuple s {})
22+
23+modify :: forall m s. (Prelude.Monad m, MonadState s m) => (s -> s) -> m {}
24+modify f = do
25+ s <- get
26+ put (f s)
27+
28+test :: Tuple String String
29+test = runState "" $ do
30+ modify $ (++) "World!"
31+ modify $ (++) "Hello, "
32+ get
33+
34+main = Debug.Trace.print test
35+
examples/passing/MultipleConstructorArgs.pursnew file+28
@@ -0,0 +1,28 @@
1+module MultipleConstructorArgs where
2+
3+import Data.Array
4+
5+data P a b = P a b
6+
7+runP :: forall a b r. (a -> b -> r) -> P a b -> r
8+runP f (P a b) = f a b
9+
10+idP = runP P
11+
12+testCase = \p -> case p of
13+ P (x:xs) (y:ys) -> x : y : testCase (P xs ys)
14+ P _ _ -> []
15+
16+test1 = testCase (P [1, 2, 3] [4, 5, 6])
17+
18+module Main where
19+
20+import Prelude
21+import MultipleConstructorArgs
22+import Global
23+import Control.Monad.Eff
24+import Data.Array
25+
26+main = do
27+ Debug.Trace.trace (runP (\s n -> s ++ show n) (P "Test" 1))
28+ Debug.Trace.print test1
examples/passing/MutRec.pursnew file+21
@@ -0,0 +1,21 @@
1+module MutRec where
2+
3+ import Prelude
4+
5+ f 0 = 0
6+ f x = g x + 1
7+
8+ g x = f (x / 2)
9+
10+ data Even = Zero | Even Odd
11+
12+ data Odd = Odd Even
13+
14+ evenToNumber Zero = 0
15+ evenToNumber (Even n) = oddToNumber n + 1
16+
17+ oddToNumber (Odd n) = evenToNumber n + 1
18+
19+module Main where
20+
21+main = Debug.Trace.trace "Done"
examples/passing/NamedPatterns.pursnew file+9
@@ -0,0 +1,9 @@
1+module NamedPatterns where
2+
3+ foo = \x -> case x of
4+ y@{ foo = "Foo" } -> y
5+ y -> y
6+
7+module Main where
8+
9+main = Debug.Trace.trace "Done"
examples/passing/Nested.pursnew file+9
@@ -0,0 +1,9 @@
1+module Nested where
2+
3+ data Extend r a = Extend { prev :: r a, next :: a }
4+
5+ data Matrix r a = Square (r (r a)) | Bigger (Matrix (Extend r) a)
6+
7+module Main where
8+
9+main = Debug.Trace.trace "Done"
examples/passing/NestedTypeSynonyms.pursnew file+13
@@ -0,0 +1,13 @@
1+module NestedTypeSynonyms where
2+
3+ type X = String
4+ type Y = X -> X
5+
6+ fn :: Y
7+ fn a = a
8+
9+module Main where
10+
11+ import Prelude
12+
13+ main = Debug.Trace.print (NestedTypeSynonyms.fn "Done")
examples/passing/ObjectSynonym.pursnew file+15
@@ -0,0 +1,15 @@
1+module ObjectSynonym where
2+
3+type Inner = Number
4+
5+inner :: Inner
6+inner = 0
7+
8+type Outer = { inner :: Inner }
9+
10+outer :: Outer
11+outer = { inner: inner }
12+
13+module Main where
14+
15+main = Debug.Trace.trace "Done"
examples/passing/ObjectUpdate.pursnew file+20
@@ -0,0 +1,20 @@
1+module ObjectUpdate where
2+
3+ update1 = \o -> o { foo = "Foo" }
4+
5+ update2 :: forall r. { foo :: String | r } -> { foo :: String | r }
6+ update2 = \o -> o { foo = "Foo" }
7+
8+ replace = \o -> case o of
9+ { foo = "Foo" } -> o { foo = "Bar" }
10+ { foo = "Bar" } -> o { bar = "Baz" }
11+ o -> o
12+
13+ polyUpdate :: forall a r. { foo :: a | r } -> { foo :: String | r }
14+ polyUpdate = \o -> o { foo = "Foo" }
15+
16+ inferPolyUpdate = \o -> o { foo = "Foo" }
17+
18+module Main where
19+
20+main = Debug.Trace.trace "Done"
examples/passing/Objects.pursnew file+20
@@ -0,0 +1,20 @@
1+module Objects where
2+
3+ import Prelude
4+
5+ test = \x -> x.foo + x.bar + 1
6+
7+ append = \o -> { foo: o.foo, bar: 1 }
8+
9+ apTest = append({foo : "Foo", baz: "Baz"})
10+
11+ f = (\a -> a.b.c) { b: { c: 1, d: "Hello" }, e: "World" }
12+
13+ g = (\a -> a.f { x: 1, y: "y" }) { f: \o -> o.x + 1 }
14+
15+ typed :: { foo :: Number }
16+ typed = { foo: 0 }
17+
18+module Main where
19+
20+main = Debug.Trace.trace "Done"
examples/passing/OneConstructor.pursnew file+9
@@ -0,0 +1,9 @@
1+module OneConstructor where
2+
3+data One a = One a
4+
5+one (One a) = a
6+
7+module Main where
8+
9+main = Debug.Trace.trace "Done"
examples/passing/Operators.pursnew file+82
@@ -0,0 +1,82 @@
1+module Operators1 where
2+
3+ import Prelude ((++))
4+
5+ (@@) :: forall a b. (a -> b) -> a -> b
6+ (@@) = \f x -> f x
7+
8+ foo :: String -> String
9+ foo = \s -> s
10+
11+ test8 = foo @@ "Hello World"
12+
13+ bar = \s1 s2 -> s1 ++ s2
14+
15+module Operators2 where
16+
17+ import Prelude
18+ import Operators1 ((@@))
19+
20+ test1 :: forall n. (Num n) => n -> n -> (n -> n -> n) -> n
21+ test1 x y z = x * y + z x y
22+
23+ test2 = (\x -> x.foo false) { foo : \_ -> 1 }
24+
25+ test3 = (\x y -> x)(1 + 2 * (1 + 2)) (true && (false || false))
26+
27+ k = \x -> \y -> x
28+
29+ test4 = 1 `k` 2
30+
31+ infixl 5 %%
32+
33+ (%%) :: Number -> Number -> Number
34+ (%%) x y = x * y + y
35+
36+ test5 = 1 %% 2 %% 3
37+
38+ test6 = ((\x -> x) `k` 2) 3
39+
40+ (<>) = \s1 s2 -> s1 ++ s2
41+
42+ test7 = "Hello" <> "World!"
43+
44+ test9 = Operators1.foo @@ "Hello World"
45+
46+ test10 = "Hello" `Operators1.bar` "World"
47+
48+ (...) :: forall a. [a] -> [a] -> [a]
49+ (...) = \as -> \bs -> as
50+
51+ test11 = [1, 2, 3] ... [4, 5, 6]
52+
53+ test12 (<%>) a b = a <%> b
54+
55+ test13 = \(<%>) a b -> a <%> b
56+
57+module Main where
58+
59+import Operators1
60+import Operators2
61+
62+import Prelude
63+import Control.Monad.Eff
64+import Debug.Trace
65+import Global
66+import Data.Array
67+
68+main =
69+ print [ show $ test1 1 2 $ \x y -> x + y
70+ , show test2
71+ , show test3
72+ , show test4
73+ , show test5
74+ , show test6
75+ , show test7
76+ , show test8
77+ , show test9
78+ , show test10
79+ , show test11
80+ , show (test12 k 1 2)
81+ , show (test13 k 1 2)
82+ ]
examples/passing/OptimizerBug.pursnew file+11
@@ -0,0 +1,11 @@
1+module OptimizerBug where
2+
3+import Prelude
4+
5+x a = 1 + y a
6+
7+y a = x a
8+
9+module Main where
10+
11+main = Debug.Trace.trace "Done"
examples/passing/Patterns.pursnew file+30
@@ -0,0 +1,30 @@
1+module Patterns where
2+
3+ import Prelude
4+
5+ test = \x -> case x of
6+ { str = "Foo", bool = true } -> true
7+ { str = "Bar", bool = b } -> b
8+ _ -> false
9+
10+ f = \o -> case o of
11+ { foo = "Foo" } -> o.bar
12+ _ -> 0
13+
14+ g = \o -> case o of
15+ { arr = [x : xs], take = "car" } -> x
16+ { arr = [_, x : xs], take = "cadr" } -> x
17+ _ -> 0
18+
19+
20+ h = \o -> case o of
21+ a@[_,_,_] -> a
22+ _ -> []
23+
24+ isDesc :: [Number] -> Boolean
25+ isDesc [x, y] | x > y = true
26+ isDesc _ = false
27+
28+module Main where
29+
30+main = Debug.Trace.trace "Done"
examples/passing/Person.pursnew file+15
@@ -0,0 +1,15 @@
1+module Person where
2+
3+ import Prelude ((++))
4+
5+ data Person = Person { name :: String, age :: Number }
6+
7+ foreign import itoa :: Number -> String
8+
9+ showPerson :: Person -> String
10+ showPerson = \p -> case p of
11+ Person o -> o.name ++ ", aged " ++ itoa(o.age)
12+
13+module Main where
14+
15+main = Debug.Trace.trace "Done"
examples/passing/Rank2Data.pursnew file+31
@@ -0,0 +1,31 @@
1+module Rank2Data where
2+
3+ import Prelude
4+
5+ data Id = Id forall a. a -> a
6+
7+ runId = \id a -> case id of
8+ Id f -> f a
9+
10+ data Nat = Nat forall r. r -> (r -> r) -> r
11+
12+ runNat = \nat -> case nat of
13+ Nat f -> f 0 (\n -> n + 1)
14+
15+ zero = Nat (\zero _ -> zero)
16+
17+ succ = \n -> case n of
18+ Nat f -> Nat (\zero succ -> succ (f zero succ))
19+
20+ add = \n m -> case n of
21+ Nat f -> case m of
22+ Nat g -> Nat (\zero succ -> g (f zero succ) succ)
23+
24+ one = succ zero
25+ two = succ zero
26+ four = add two two
27+ fourNumber = runNat four
28+
29+module Main where
30+
31+main = Debug.Trace.trace "Done"
examples/passing/Rank2Types.pursnew file+25
@@ -0,0 +1,25 @@
1+module Rank2Types where
2+
3+ import Prelude
4+
5+ test1 :: (forall a. (a -> a)) -> Number
6+ test1 = \f -> f 0
7+
8+ foreign import data ST :: * -> * -> *
9+
10+ foreign import runST :: forall a. (forall s. ST s a) -> a
11+
12+ foreign import exampleST :: forall s. ST s Number
13+
14+ testST = \_ -> runST exampleST
15+
16+ foreign import push :: forall el. el -> [el] -> [el]
17+
18+ replicateM :: forall m a. (forall a. a -> m a) -> (forall a b. m a -> (a -> m b) -> m b) -> Number -> m a -> m [a]
19+ replicateM = \return bind n m -> case n of
20+ 0 -> return []
21+ n -> bind m (\x -> bind (replicateM return bind (n - 1) m) (\xs -> return (push x xs)))
22+
23+module Main where
24+
25+main = Debug.Trace.trace "Done"
examples/passing/Recursion.pursnew file+12
@@ -0,0 +1,12 @@
1+module Recursion where
2+
3+ import Prelude
4+
5+ fib = \n -> case n of
6+ 0 -> 1
7+ 1 -> 1
8+ n -> fib (n - 1) + fib (n - 2)
9+
10+module Main where
11+
12+main = Debug.Trace.trace "Done"
examples/passing/RedefinedFixity.pursnew file+18
@@ -0,0 +1,18 @@
1+module M1 where
2+
3+($) f a = f a
4+
5+infixr 1000 $
6+
7+module M2 where
8+
9+import M1
10+
11+module M3 where
12+
13+import M1
14+import M2
15+
16+module Main where
17+
18+main = Debug.Trace.trace "Done"
examples/passing/RuntimeScopeIssue.pursnew file+25
@@ -0,0 +1,25 @@
1+module RuntimeScopeIssue where
2+
3+import Prelude
4+
5+class A a where
6+ a :: a -> Boolean
7+
8+class B a where
9+ b :: a -> Boolean
10+
11+instance A Number where
12+ a 0 = true
13+ a n = b (n - 1)
14+
15+instance B Number where
16+ b 0 = false
17+ b n = a (n - 1)
18+
19+module Main where
20+
21+import RuntimeScopeIssue
22+
23+import Prelude
24+
25+main = Debug.Trace.print $ a 10
examples/passing/STArray.pursnew file+23
@@ -0,0 +1,23 @@
1+module Main where
2+
3+import Prelude
4+import Control.Monad.Eff
5+import Control.Monad.ST
6+import Data.Array
7+
8+test = runSTArray (do
9+ a <- newSTArray 2 0
10+ pokeSTArray a 0 1
11+ pokeSTArray a 1 2
12+ return a)
13+
14+fromTo' lo hi _ arr | lo > hi = return arr
15+fromTo' lo hi i arr = do
16+ pokeSTArray arr i lo
17+ fromTo' (lo + 1) hi (i + 1) arr
18+
19+fromTo lo hi = runSTArray (do
20+ arr <- newSTArray (hi - lo + 1) 0
21+ fromTo' lo hi 0 arr)
22+
23+main = Debug.Trace.print $ runPure (fromTo 10 20)
examples/passing/TailCall.pursnew file+20
@@ -0,0 +1,20 @@
1+module TailCall where
2+
3+import Prelude
4+
5+test :: Number -> [Number] -> Number
6+test n [] = n
7+test n (x:xs) = test (n + x) xs
8+
9+loop :: forall a. Number -> a
10+loop x = loop (x + 1)
11+
12+notATailCall = \x ->
13+ (\notATailCall -> notATailCall x) (\x -> x)
14+
15+module Main where
16+
17+import Prelude
18+import TailCall
19+
20+main = Debug.Trace.print (test 0 [1, 2, 3])
examples/passing/Tick.pursnew file+7
@@ -0,0 +1,7 @@
1+module Tick where
2+
3+test' x = x
4+
5+module Main where
6+
7+main = Debug.Trace.trace "Done"
examples/passing/TopLevelCase.pursnew file+20
@@ -0,0 +1,20 @@
1+module TopLevelCase where
2+
3+ import Prelude
4+
5+ gcd :: Number -> Number -> Number
6+ gcd 0 x = x
7+ gcd x 0 = x
8+ gcd x y | x > y = gcd (x % y) y
9+ gcd x y = gcd (y % x) x
10+
11+ guardsTest (x:xs) | x > 0 = guardsTest xs
12+ guardsTest xs = xs
13+
14+ data A = A
15+
16+ parseTest A 0 = 0
17+
18+module Main where
19+
20+main = Debug.Trace.trace "Done"
examples/passing/TypeClasses.pursnew file+69
@@ -0,0 +1,69 @@
1+module TypeClasses where
2+
3+import Prelude
4+
5+test1 = \_ -> show "testing"
6+
7+f :: forall a. (Prelude.Show a) => a -> String
8+f x = show x
9+
10+test2 = \_ -> f "testing"
11+
12+test7 :: forall a. (Prelude.Show a) => a -> String
13+test7 = show
14+
15+test8 = \_ -> show $ "testing"
16+
17+data Data a = Data a
18+
19+instance (Prelude.Show a) => Prelude.Show (Data a) where
20+ show (Data a) = "Data (" ++ show a ++ ")"
21+
22+test3 = \_ -> show (Data "testing")
23+
24+instance Prelude.Monad Data where
25+ return = Data
26+ (>>=) (Data a) f = f a
27+
28+data Maybe a = Nothing | Just a
29+
30+instance Prelude.Monad Maybe where
31+ return = Just
32+ (>>=) Nothing _ = Nothing
33+ (>>=) (Just a) f = f a
34+
35+test4 :: forall a m. (Monad m) => a -> m Number
36+test4 = \_ -> return 1
37+
38+test5 = \_ -> Just 1 >>= \n -> return (n + 1)
39+
40+module TypeClasses2 where
41+
42+import Prelude
43+import TypeClasses
44+
45+instance (Prelude.Show a) => Prelude.Show [a] where
46+ show [] = "[]"
47+ show (x:xs) = show x ++ ", " ++ show xs
48+
49+test6 = \_ -> show ["testing"]
50+
51+instance Prelude.Monad ((->) r) where
52+ return a r = a
53+ (>>=) f g r = g (f r) r
54+
55+ask r = r
56+
57+runReader r f = f r
58+
59+test9 _ = runReader 0 $ do
60+ n <- ask
61+ return $ n + 1
62+
63+module Main where
64+
65+import Prelude
66+import TypeClasses
67+
68+main = Debug.Trace.trace (test7 "Done")
69+
examples/passing/TypeClassesInOrder.pursnew file+11
@@ -0,0 +1,11 @@
1+module Main where
2+
3+import Prelude
4+
5+class Foo a where
6+ foo :: a -> String
7+
8+instance Foo String where
9+ foo s = s
10+
11+main = Debug.Trace.trace $ foo "Done"
examples/passing/TypeClassesWithOverlappingTypeVariables.pursnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+ import Prelude
4+ import Data.Either
5+
6+ instance Prelude.Functor (Either a) where
7+ (<$>) _ (Left x) = Left x
8+ (<$>) f (Right y) = Right (f y)
9+
10+ main = Debug.Trace.trace "Done"
examples/passing/TypeDecl.pursnew file+14
@@ -0,0 +1,14 @@
1+module TypeDecl where
2+
3+ import Prelude
4+
5+ k :: String -> Number -> String
6+ k x y = x
7+
8+ iterate :: forall a. Number -> (a -> a) -> a -> a
9+ iterate 0 f a = a
10+ iterate n f a = iterate (n - 1) f (f a)
11+
12+module Main where
13+
14+main = Debug.Trace.trace "Done"
examples/passing/TypeSynonyms.pursnew file+40
@@ -0,0 +1,40 @@
1+module TypeSynonyms where
2+
3+ type Lens a b =
4+ { get :: a -> b
5+ , set :: a -> b -> a
6+ }
7+
8+ composeLenses :: forall a b c. Lens a b -> Lens b c -> Lens a c
9+ composeLenses = \l1 -> \l2 ->
10+ { get: \a -> l2.get (l1.get a)
11+ , set: \a c -> l1.set a (l2.set (l1.get a) c)
12+ }
13+
14+ type Pair a b = { fst :: a, snd :: b }
15+
16+ fst :: forall a b. Lens (Pair a b) a
17+ fst =
18+ { get: \p -> p.fst
19+ , set: \p a -> { fst: a, snd: p.snd }
20+ }
21+
22+ test1 :: forall a b c. Lens (Pair (Pair a b) c) a
23+ test1 = composeLenses fst fst
24+
25+ import Data.Array ((:))
26+ import Data.Array.Unsafe
27+
28+ headLens :: forall a. Lens [a] a
29+ headLens =
30+ { get: \l -> head l
31+ , set: \l a -> case l of
32+ _:xs -> a : xs
33+ }
34+
35+ test2 :: forall a b c. Lens (Pair [Pair a b] c) a
36+ test2 = composeLenses fst (composeLenses headLens fst)
37+
38+module Main where
39+
40+main = Debug.Trace.trace "Done"
examples/passing/iota.pursnew file+11
@@ -0,0 +1,11 @@
1+module Iota where
2+
3+ s = \x -> \y -> \z -> x z (y z)
4+
5+ k = \x -> \y -> x
6+
7+ iota = \x -> x s k
8+
9+module Main where
10+
11+main = Debug.Trace.trace "Done"
examples/passing/s.pursnew file+7
@@ -0,0 +1,7 @@
1+module S where
2+
3+ s = \x y z -> x z (y z)
4+
5+module Main where
6+
7+main = Debug.Trace.trace "Done"
package.yamldeleted−86
@@ -1,86 +0,0 @@
1−name: psgo
2−version: 0.1.0.0
3−github: "andyarvanitis/purescript-native"
4−license: BSD3
5−author: "Andy Arvanitis"
6−maintainer: "example@example.com"
7−copyright: "2018 Andy Arvanitis"
8−
9−extra-source-files:
10−- README.md
11−- ChangeLog.md
12−- stack.yaml
13−- support/*
14−
15−# Metadata used when publishing your package
16−# synopsis: Short description of your package
17−# category: Web
18−
19−# To avoid duplicated efforts in documentation and dealing with the
20−# complications of embedding Haddock markup inside cabal files, it is
21−# common to point users to the README.md file.
22−description: Please see the README on Github at <https://github.com/andyarvanitis/purescript-native#readme>
23−
24−dependencies:
25−- base >= 4.7 && < 5
26−- bytestring >= 0.10.8.2 && < 0.11
27−- purescript
28−- base-compat >=0.6.0
29−- protolude >=0.1.6
30−- text
31−- containers
32−- filepath
33−- monad-parallel >= 0.7.2.2 && <0.8
34−- pattern-arrows >=0.0.2 && <0.1
35−- safe >=0.3.9 && <0.4
36−- transformers >=0.3.0 && <0.6
37−- mtl >=2.1.0 && <2.3.0
38−- aeson >=1.0 && <1.5
39−- directory
40−- process
41−- file-embed
42−- filemanip
43−- gitrev
44−
45−library:
46− source-dirs: src
47− default-extensions:
48− - ConstraintKinds
49− - DataKinds
50− - DeriveFunctor
51− - EmptyDataDecls
52− - FlexibleContexts
53− - KindSignatures
54− - LambdaCase
55− - MultiParamTypeClasses
56− - NoImplicitPrelude
57− - PatternGuards
58− - PatternSynonyms
59− - RankNTypes
60− - RecordWildCards
61− - OverloadedStrings
62− - ScopedTypeVariables
63− - TupleSections
64− - ViewPatterns
65−
66−executables:
67− psgo:
68− main: Main.hs
69− source-dirs: app
70− ghc-options:
71− - -threaded
72− - -rtsopts
73− - -with-rtsopts=-N
74− dependencies:
75− - psgo
76−
77−tests:
78− psgo-test:
79− main: Spec.hs
80− source-dirs: test
81− ghc-options:
82− - -threaded
83− - -rtsopts
84− - -with-rtsopts=-N
85− dependencies:
86− - psgo
prelude/README.mdnew file+758
@@ -0,0 +1,758 @@
1+# Module Documentation
2+## Module Prelude
3+
4+### Types
5+
6+ data Ref a where
7+ Ref :: a -> Ref a
8+
9+
10+### Type Classes
11+
12+ class Alternative f where
13+ empty :: forall a. f a
14+ (<|>) :: forall a. f a -> f a -> f a
15+
16+ class Applicative f where
17+ pure :: forall a. a -> f a
18+ (<*>) :: forall b. forall a. f (a -> b) -> f a -> f b
19+
20+ class Bits b where
21+ (&) :: b -> b -> b
22+ (|) :: b -> b -> b
23+ (^) :: b -> b -> b
24+ shl :: b -> Prim.Number -> b
25+ shr :: b -> Prim.Number -> b
26+ zshr :: b -> Prim.Number -> b
27+ complement :: b -> b
28+
29+ class BoolLike b where
30+ (&&) :: b -> b -> b
31+ (||) :: b -> b -> b
32+ not :: b -> b
33+
34+ class Category a where
35+ id :: forall t. a t t
36+ (<<<) :: forall d. forall c. forall b. a c d -> a b c -> a b d
37+ (>>>) :: forall d. forall c. forall b. a b c -> a c d -> a b d
38+
39+ class Eq a where
40+ (==) :: a -> a -> Prim.Boolean
41+ (/=) :: a -> a -> Prim.Boolean
42+
43+ class Functor f where
44+ (<$>) :: forall b. forall a. (a -> b) -> f a -> f b
45+
46+ class Monad m where
47+ return :: forall a. a -> m a
48+ (>>=) :: forall b. forall a. m a -> (a -> m b) -> m b
49+
50+ class Num a where
51+ (+) :: a -> a -> a
52+ (-) :: a -> a -> a
53+ (*) :: a -> a -> a
54+ (/) :: a -> a -> a
55+ (%) :: a -> a -> a
56+ negate :: a -> a
57+
58+ class Ord a where
59+ (<) :: a -> a -> Prim.Boolean
60+ (>) :: a -> a -> Prim.Boolean
61+ (<=) :: a -> a -> Prim.Boolean
62+ (>=) :: a -> a -> Prim.Boolean
63+
64+ class Read a where
65+ read :: Prim.String -> a
66+
67+ class Show a where
68+ show :: a -> Prim.String
69+
70+
71+### Type Class Instances
72+
73+ (Monad (m)) => instance Applicative m
74+
75+ instance Bits Prim.Number
76+
77+ instance BoolLike Prim.Boolean
78+
79+ instance Category Prim.Function
80+
81+ instance Eq Ref a
82+
83+ instance Eq Prim.String
84+
85+ instance Eq Prim.Number
86+
87+ instance Eq Prim.Boolean
88+
89+ (Eq (a)) => instance Eq [a]
90+
91+ (Applicative (f)) => instance Functor f
92+
93+ instance Num Prim.Number
94+
95+ instance Ord Prim.Number
96+
97+ instance Prelude.Show Prim.Number
98+
99+ instance Read Prim.String
100+
101+ instance Read Prim.Boolean
102+
103+ instance Read Prim.Number
104+
105+ instance Show Prim.String
106+
107+ instance Show Prim.Boolean
108+
109+
110+### Values
111+
112+ (!!) :: forall a. [a] -> Prim.Number -> a
113+
114+ (#) :: forall b. forall a. a -> (a -> b) -> b
115+
116+ ($) :: forall b. forall a. (a -> b) -> a -> b
117+
118+ (++) :: Prim.String -> Prim.String -> Prim.String
119+
120+ boolAnd :: Prim.Boolean -> Prim.Boolean -> Prim.Boolean
121+
122+ boolNot :: Prim.Boolean -> Prim.Boolean
123+
124+ boolOr :: Prim.Boolean -> Prim.Boolean -> Prim.Boolean
125+
126+ const :: forall b. forall a. a -> b -> a
127+
128+ flip :: forall c. forall b. forall a. (a -> b -> c) -> b -> a -> c
129+
130+ liftRef :: forall b. forall a. (a -> a -> b) -> Ref a -> Ref a -> b
131+
132+ numAdd :: Prim.Number -> Prim.Number -> Prim.Number
133+
134+ numAnd :: Prim.Number -> Prim.Number -> Prim.Number
135+
136+ numComplement :: Prim.Number -> Prim.Number
137+
138+ numDiv :: Prim.Number -> Prim.Number -> Prim.Number
139+
140+ numGreater :: Prim.Number -> Prim.Number -> Prim.Boolean
141+
142+ numGreaterEq :: Prim.Number -> Prim.Number -> Prim.Boolean
143+
144+ numLess :: Prim.Number -> Prim.Number -> Prim.Boolean
145+
146+ numLessEq :: Prim.Number -> Prim.Number -> Prim.Boolean
147+
148+ numMod :: Prim.Number -> Prim.Number -> Prim.Number
149+
150+ numMul :: Prim.Number -> Prim.Number -> Prim.Number
151+
152+ numNegate :: Prim.Number -> Prim.Number
153+
154+ numOr :: Prim.Number -> Prim.Number -> Prim.Number
155+
156+ numShl :: Prim.Number -> Prim.Number -> Prim.Number
157+
158+ numShr :: Prim.Number -> Prim.Number -> Prim.Number
159+
160+ numSub :: Prim.Number -> Prim.Number -> Prim.Number
161+
162+ numXor :: Prim.Number -> Prim.Number -> Prim.Number
163+
164+ numZshr :: Prim.Number -> Prim.Number -> Prim.Number
165+
166+ readNumber :: Prim.String -> Prim.Number
167+
168+ refEq :: forall a. Ref a -> Ref a -> Prim.Boolean
169+
170+ refIneq :: forall a. Ref a -> Ref a -> Prim.Boolean
171+
172+ showNumber :: Prim.Number -> Prim.String
173+
174+ unsafeRefEq :: forall a. a -> a -> Prim.Boolean
175+
176+ unsafeRefIneq :: forall a. a -> a -> Prim.Boolean
177+
178+
179+## Module Data.Monoid
180+
181+### Types
182+
183+
184+### Type Classes
185+
186+ class Monoid m where
187+ mempty :: m
188+ (<>) :: m -> m -> m
189+
190+
191+### Type Class Instances
192+
193+ instance Monoid Prim.String
194+
195+ instance Monoid [a]
196+
197+
198+### Values
199+
200+ mconcat :: forall m. (Monoid (m)) => [m] -> m
201+
202+
203+## Module Control.Monad
204+
205+### Types
206+
207+
208+### Type Classes
209+
210+
211+### Type Class Instances
212+
213+
214+### Values
215+
216+ (<=<) :: forall c. forall b. forall a. forall m. (Monad (m)) => (b -> m c) -> (a -> m b) -> a -> m c
217+
218+ (>=>) :: forall c. forall b. forall a. forall m. (Monad (m)) => (a -> m b) -> (b -> m c) -> a -> m c
219+
220+ foldM :: forall b. forall a. forall m. (Monad (m)) => (a -> b -> m a) -> a -> [b] -> m a
221+
222+ join :: forall a. forall m. (Monad (m)) => m (m a) -> m a
223+
224+ mapM :: forall b. forall a. forall m. (Monad (m)) => (a -> m b) -> [a] -> m [b]
225+
226+ replicateM :: forall a. forall m. (Monad (m)) => Prim.Number -> m a -> m [a]
227+
228+ sequence :: forall a. forall m. (Monad (m)) => [m a] -> m [a]
229+
230+ when :: forall m. (Monad (m)) => Prim.Boolean -> m { } -> m { }
231+
232+
233+## Module Data.Maybe
234+
235+### Types
236+
237+ data Maybe a where
238+ Nothing :: Maybe a
239+ Just :: a -> Maybe a
240+
241+
242+### Type Classes
243+
244+
245+### Type Class Instances
246+
247+ instance Prelude.Applicative Maybe
248+
249+ instance Prelude.Functor Maybe
250+
251+ instance Prelude.Monad Maybe
252+
253+ (Show (a)) => instance Prelude.Show Maybe a
254+
255+
256+### Values
257+
258+ fromMaybe :: forall a. a -> Maybe a -> a
259+
260+ maybe :: forall b. forall a. b -> (a -> b) -> Maybe a -> b
261+
262+
263+## Module Data.Either
264+
265+### Types
266+
267+ data Either a b where
268+ Left :: a -> Either a b
269+ Right :: b -> Either a b
270+
271+
272+### Type Classes
273+
274+
275+### Type Class Instances
276+
277+ instance Prelude.Applicative Either e
278+
279+ instance Prelude.Functor Either a
280+
281+ instance Prelude.Monad Either e
282+
283+ (Show (a),Show (b)) => instance Prelude.Show Either a b
284+
285+
286+### Values
287+
288+ either :: forall c. forall b. forall a. (a -> c) -> (b -> c) -> Either a b -> c
289+
290+
291+## Module Data.Array
292+
293+### Types
294+
295+
296+### Type Classes
297+
298+
299+### Type Class Instances
300+
301+ instance Prelude.Alternative Prim.Array
302+
303+ instance Prelude.Functor Prim.Array
304+
305+ instance Prelude.Monad Prim.Array
306+
307+ (Prelude.Show (a)) => instance Prelude.Show [a]
308+
309+
310+### Values
311+
312+ (:) :: forall a. a -> [a] -> [a]
313+
314+ all :: forall a. (a -> Prim.Boolean) -> [a] -> Prim.Boolean
315+
316+ any :: forall a. (a -> Prim.Boolean) -> [a] -> Prim.Boolean
317+
318+ concat :: forall a. [a] -> [a] -> [a]
319+
320+ concatMap :: forall b. forall a. [a] -> (a -> [b]) -> [b]
321+
322+ filter :: forall a. (a -> Prim.Boolean) -> [a] -> [a]
323+
324+ find :: forall a. (a -> Prim.Boolean) -> [a] -> Maybe a
325+
326+ foldl :: forall b. forall a. (a -> b -> b) -> b -> [a] -> b
327+
328+ foldr :: forall b. forall a. (a -> b -> a) -> a -> [b] -> a
329+
330+ head :: forall a. [a] -> Maybe a
331+
332+ indexOf :: forall a. [a] -> a -> Prim.Number
333+
334+ isEmpty :: forall a. [a] -> Prim.Boolean
335+
336+ joinS :: [Prim.String] -> Prim.String
337+
338+ joinWith :: [Prim.String] -> Prim.String -> Prim.String
339+
340+ lastIndexOf :: forall a. [a] -> a -> Prim.Number
341+
342+ length :: forall a. [a] -> Prim.Number
343+
344+ map :: forall b. forall a. (a -> b) -> [a] -> [b]
345+
346+ push :: forall a. [a] -> a -> [a]
347+
348+ range :: Prim.Number -> Prim.Number -> [Prim.Number]
349+
350+ reverse :: forall a. [a] -> [a]
351+
352+ shift :: forall a. [a] -> [a]
353+
354+ singleton :: forall a. a -> [a]
355+
356+ slice :: forall a. Prim.Number -> Prim.Number -> [a] -> [a]
357+
358+ sort :: forall a. [a] -> [a]
359+
360+ splice :: forall a. Prim.Number -> Prim.Number -> [a] -> [a] -> [a]
361+
362+ tail :: forall a. [a] -> Maybe [a]
363+
364+ zipWith :: forall c. forall b. forall a. (a -> b -> c) -> [a] -> [b] -> [c]
365+
366+
367+## Module Data.Array.Unsafe
368+
369+### Types
370+
371+
372+### Type Classes
373+
374+
375+### Type Class Instances
376+
377+
378+### Values
379+
380+ head :: forall a. [a] -> a
381+
382+ tail :: forall a. [a] -> [a]
383+
384+
385+## Module Data.Tuple
386+
387+### Types
388+
389+ data Tuple a b where
390+ Tuple :: a -> b -> Tuple a b
391+
392+
393+### Type Classes
394+
395+
396+### Type Class Instances
397+
398+ (Prelude.Show (a),Prelude.Show (b)) => instance Prelude.Show Tuple a b
399+
400+
401+### Values
402+
403+ curry :: forall c. forall b. forall a. (Tuple a b -> c) -> a -> b -> c
404+
405+ uncurry :: forall c. forall b. forall a. (a -> b -> c) -> Tuple a b -> c
406+
407+ unzip :: forall b. forall a. [Tuple a b] -> Tuple [a] [b]
408+
409+ zip :: forall b. forall a. [a] -> [b] -> [Tuple a b]
410+
411+
412+## Module Data.String
413+
414+### Types
415+
416+
417+### Type Classes
418+
419+
420+### Type Class Instances
421+
422+
423+### Values
424+
425+ charAt :: Prim.Number -> Prim.String -> Prim.String
426+
427+ indexOfS :: Prim.String -> Prim.String -> Prim.Number
428+
429+ lastIndexOfS :: Prim.String -> Prim.String -> Prim.Number
430+
431+ lengthS :: Prim.String -> Prim.Number
432+
433+ localeCompare :: Prim.String -> Prim.String -> Prim.Number
434+
435+ replace :: Prim.String -> Prim.String -> Prim.String -> Prim.String
436+
437+ sliceS :: Prim.Number -> Prim.Number -> Prim.String -> Prim.String
438+
439+ split :: Prim.String -> Prim.String -> [Prim.String]
440+
441+ substr :: Prim.Number -> Prim.Number -> Prim.String -> Prim.String
442+
443+ substring :: Prim.Number -> Prim.Number -> Prim.String -> Prim.String
444+
445+ toLower :: Prim.String -> Prim.String
446+
447+ toUpper :: Prim.String -> Prim.String
448+
449+ trim :: Prim.String -> Prim.String
450+
451+
452+## Module Data.String.Regex
453+
454+### Types
455+
456+ data Regex :: *
457+
458+
459+### Type Classes
460+
461+
462+### Type Class Instances
463+
464+
465+### Values
466+
467+ match :: Regex -> Prim.String -> [Prim.String]
468+
469+ regex :: Prim.String -> Prim.String -> Regex
470+
471+ replaceR :: Regex -> Prim.String -> Prim.String -> Prim.String
472+
473+ search :: Regex -> Prim.String -> Prim.Number
474+
475+ test :: Regex -> Prim.String -> Prim.Boolean
476+
477+
478+## Module Global
479+
480+### Types
481+
482+
483+### Type Classes
484+
485+
486+### Type Class Instances
487+
488+
489+### Values
490+
491+ decodeURI :: Prim.String -> Prim.String
492+
493+ decodeURIComponent :: Prim.String -> Prim.String
494+
495+ encodeURI :: Prim.String -> Prim.String
496+
497+ encodeURIComponent :: Prim.String -> Prim.String
498+
499+ infinity :: Prim.Number
500+
501+ isFinite :: Prim.Number -> Prim.Boolean
502+
503+ isNaN :: Prim.Number -> Prim.Boolean
504+
505+ nan :: Prim.Number
506+
507+ parseFloat :: Prim.String -> Prim.Number
508+
509+ parseInt :: Prim.String -> Prim.Number
510+
511+ toExponential :: Prim.Number -> Prim.String
512+
513+ toFixed :: Prim.Number -> Prim.Number -> Prim.String
514+
515+ toPrecision :: Prim.Number -> Prim.Number -> Prim.String
516+
517+
518+## Module Math
519+
520+### Types
521+
522+
523+### Type Classes
524+
525+
526+### Type Class Instances
527+
528+
529+### Values
530+
531+ abs :: Prim.Number -> Prim.Number
532+
533+ aceil :: Prim.Number -> Prim.Number
534+
535+ acos :: Prim.Number -> Prim.Number
536+
537+ asin :: Prim.Number -> Prim.Number
538+
539+ atan :: Prim.Number -> Prim.Number
540+
541+ atan2 :: Prim.Number -> Prim.Number -> Prim.Number
542+
543+ cos :: Prim.Number -> Prim.Number
544+
545+ e :: Prim.Number
546+
547+ exp :: Prim.Number -> Prim.Number
548+
549+ floor :: Prim.Number -> Prim.Number
550+
551+ ln10 :: Prim.Number
552+
553+ ln2 :: Prim.Number
554+
555+ log :: Prim.Number -> Prim.Number
556+
557+ log10e :: Prim.Number
558+
559+ log2e :: Prim.Number
560+
561+ max :: Prim.Number -> Prim.Number
562+
563+ min :: Prim.Number -> Prim.Number
564+
565+ pi :: Prim.Number
566+
567+ pow :: Prim.Number -> Prim.Number
568+
569+ round :: Prim.Number -> Prim.Number
570+
571+ sin :: Prim.Number -> Prim.Number
572+
573+ sqrt :: Prim.Number -> Prim.Number
574+
575+ sqrt1_2 :: Prim.Number
576+
577+ sqrt2 :: Prim.Number
578+
579+ tan :: Prim.Number -> Prim.Number
580+
581+
582+## Module Control.Monad.Eff
583+
584+### Types
585+
586+ data Eff :: # ! -> * -> *
587+
588+ type Pure a = forall e. Eff e a
589+
590+
591+### Type Classes
592+
593+
594+### Type Class Instances
595+
596+ instance Prelude.Monad Eff e
597+
598+
599+### Values
600+
601+ bindEff :: forall b. forall a. forall e. Eff e a -> (a -> Eff e b) -> Eff e b
602+
603+ forE :: forall e. Prim.Number -> Prim.Number -> (Prim.Number -> Eff e { }) -> Eff e { }
604+
605+ foreachE :: forall a. forall e. [a] -> (a -> Eff e { }) -> Eff e { }
606+
607+ retEff :: forall a. forall e. a -> Eff e a
608+
609+ runPure :: forall a. Pure a -> a
610+
611+ untilE :: forall e. Eff e Prim.Boolean -> Eff e { }
612+
613+ whileE :: forall a. forall e. Eff e Prim.Boolean -> Eff e a -> Eff e { }
614+
615+
616+## Module Random
617+
618+### Types
619+
620+ data Random :: !
621+
622+
623+### Type Classes
624+
625+
626+### Type Class Instances
627+
628+
629+### Values
630+
631+ random :: forall e. Eff (random :: Random | e) Prim.Number
632+
633+
634+## Module Control.Monad.Error
635+
636+### Types
637+
638+ data Error :: * -> !
639+
640+
641+### Type Classes
642+
643+
644+### Type Class Instances
645+
646+
647+### Values
648+
649+ catchError :: forall a. forall r. forall e. (e -> Eff r a) -> Eff (err :: Error e | r) a -> Eff r a
650+
651+ throwError :: forall r. forall e. forall a. e -> Eff (err :: Error e | r) a
652+
653+
654+## Module Data.IORef
655+
656+### Types
657+
658+ data IORef :: * -> *
659+
660+ data Ref :: !
661+
662+
663+### Type Classes
664+
665+
666+### Type Class Instances
667+
668+
669+### Values
670+
671+ modifyIORef :: forall r. forall s. IORef s -> (s -> s) -> Eff (ref :: Ref | r) { }
672+
673+ newIORef :: forall r. forall s. s -> Eff (ref :: Ref | r) (IORef s)
674+
675+ readIORef :: forall r. forall s. IORef s -> Eff (ref :: Ref | r) s
676+
677+ unsafeRunIORef :: forall a. forall eff. Eff (ref :: Ref | eff) a -> Eff eff a
678+
679+ writeIORef :: forall r. forall s. IORef s -> s -> Eff (ref :: Ref | r) { }
680+
681+
682+## Module Debug.Trace
683+
684+### Types
685+
686+ data Trace :: !
687+
688+
689+### Type Classes
690+
691+
692+### Type Class Instances
693+
694+
695+### Values
696+
697+ print :: forall r. forall a. (Prelude.Show (a)) => a -> Eff (trace :: Trace | r) { }
698+
699+ trace :: forall r. Prim.String -> Eff (trace :: Trace | r) { }
700+
701+
702+## Module Control.Monad.ST
703+
704+### Types
705+
706+ data ST :: * -> !
707+
708+ data STArray :: * -> * -> *
709+
710+ data STRef :: * -> * -> *
711+
712+
713+### Type Classes
714+
715+
716+### Type Class Instances
717+
718+
719+### Values
720+
721+ modifySTRef :: forall r. forall h. forall a. STRef h a -> (a -> a) -> Eff (st :: ST h | r) a
722+
723+ newSTArray :: forall r. forall h. forall a. Prim.Number -> a -> Eff (st :: ST h | r) (STArray h a)
724+
725+ newSTRef :: forall r. forall h. forall a. a -> Eff (st :: ST h | r) (STRef h a)
726+
727+ peekSTArray :: forall r. forall h. forall a. STArray h a -> Eff (st :: ST h | r) a
728+
729+ pokeSTArray :: forall r. forall h. forall a. STArray h a -> Prim.Number -> a -> Eff (st :: ST h | r) a
730+
731+ readSTRef :: forall r. forall h. forall a. STRef h a -> Eff (st :: ST h | r) a
732+
733+ runST :: forall r. forall a. forall h. Eff (st :: ST h | r) a -> Eff r a
734+
735+ runSTArray :: forall r. forall a. forall h. Eff (st :: ST h | r) (STArray h a) -> Eff r [a]
736+
737+ writeSTRef :: forall r. forall h. forall a. STRef h a -> a -> Eff (st :: ST h | r) a
738+
739+
740+## Module Data.Enum
741+
742+### Types
743+
744+
745+### Type Classes
746+
747+ class Enum a where
748+ toEnum :: Prim.Number -> Maybe a
749+ fromEnum :: a -> Prim.Number
750+
751+
752+### Type Class Instances
753+
754+
755+### Values
756+
757+
758+
prelude/prelude.pursnew file+1199
@@ -0,0 +1,1199 @@
1+module Prelude where
2+
3+ flip :: forall a b c. (a -> b -> c) -> b -> a -> c
4+ flip f b a = f a b
5+
6+ const :: forall a b. a -> b -> a
7+ const a _ = a
8+
9+ infixr 9 >>>
10+ infixr 9 <<<
11+
12+ class Category a where
13+ id :: forall t. a t t
14+ (<<<) :: forall b c d. a c d -> a b c -> a b d
15+ (>>>) :: forall b c d. a b c -> a c d -> a b d
16+
17+ instance Category (->) where
18+ id x = x
19+ (<<<) f g x = f (g x)
20+ (>>>) f g x = g (f x)
21+
22+ infixr 0 $
23+ infixl 0 #
24+
25+ ($) :: forall a b. (a -> b) -> a -> b
26+ ($) f x = f x
27+
28+ (#) :: forall a b. a -> (a -> b) -> b
29+ (#) x f = f x
30+
31+ class Show a where
32+ show :: a -> String
33+
34+ instance Show String where
35+ show s = s
36+
37+ instance Show Boolean where
38+ show true = "true"
39+ show false = "false"
40+
41+ foreign import showNumber "function showNumber(n) {\
42+ \ return n.toString();\
43+ \}" :: Number -> String
44+
45+ instance Show Number where
46+ show = showNumber
47+
48+ class Read a where
49+ read :: String -> a
50+
51+ instance Read String where
52+ read s = s
53+
54+ instance Read Boolean where
55+ read "true" = true
56+ read _ = false
57+
58+ foreign import readNumber "function readNumber(n) {\
59+ \ return parseFloat(n);\
60+ \}" :: String -> Number
61+
62+ instance Read Number where
63+ read = readNumber
64+
65+ infixl 4 <$>
66+
67+ class Functor f where
68+ (<$>) :: forall a b. (a -> b) -> f a -> f b
69+
70+ infixl 4 <*>
71+
72+ class Applicative f where
73+ pure :: forall a. a -> f a
74+ (<*>) :: forall a b. f (a -> b) -> f a -> f b
75+
76+ instance (Applicative f) => Functor f where
77+ (<$>) f a = pure f <*> a
78+
79+ infixl 3 <|>
80+
81+ class Alternative f where
82+ empty :: forall a. f a
83+ (<|>) :: forall a. f a -> f a -> f a
84+
85+ infixl 1 >>=
86+
87+ class Monad m where
88+ return :: forall a. a -> m a
89+ (>>=) :: forall a b. m a -> (a -> m b) -> m b
90+
91+ instance (Monad m) => Applicative m where
92+ pure = return
93+ (<*>) f a = do
94+ f' <- f
95+ a' <- a
96+ return (f' a')
97+
98+ infixl 7 *
99+ infixl 7 /
100+ infixl 7 %
101+
102+ infixl 6 -
103+ infixl 6 +
104+
105+ class Num a where
106+ (+) :: a -> a -> a
107+ (-) :: a -> a -> a
108+ (*) :: a -> a -> a
109+ (/) :: a -> a -> a
110+ (%) :: a -> a -> a
111+ negate :: a -> a
112+
113+ foreign import numAdd "function numAdd(n1) {\
114+ \ return function(n2) {\
115+ \ return n1 + n2;\
116+ \ };\
117+ \}" :: Number -> Number -> Number
118+
119+ foreign import numSub "function numSub(n1) {\
120+ \ return function(n2) {\
121+ \ return n1 - n2;\
122+ \ };\
123+ \}" :: Number -> Number -> Number
124+
125+ foreign import numMul "function numMul(n1) {\
126+ \ return function(n2) {\
127+ \ return n1 * n2;\
128+ \ };\
129+ \}" :: Number -> Number -> Number
130+
131+ foreign import numDiv "function numDiv(n1) {\
132+ \ return function(n2) {\
133+ \ return n1 / n2;\
134+ \ };\
135+ \}" :: Number -> Number -> Number
136+
137+ foreign import numMod "function numMod(n1) {\
138+ \ return function(n2) {\
139+ \ return n1 % n2;\
140+ \ };\
141+ \}" :: Number -> Number -> Number
142+
143+ foreign import numNegate "function numNegate(n) {\
144+ \ return -n;\
145+ \}" :: Number -> Number
146+
147+ instance Num Number where
148+ (+) = numAdd
149+ (-) = numSub
150+ (*) = numMul
151+ (/) = numDiv
152+ (%) = numMod
153+ negate = numNegate
154+
155+ infixl 4 ==
156+ infixl 4 /=
157+
158+ class Eq a where
159+ (==) :: a -> a -> Boolean
160+ (/=) :: a -> a -> Boolean
161+
162+ -- Referential equality
163+ data Ref a = Ref a
164+
165+ liftRef :: forall a b. (a -> a -> b) -> Ref a -> Ref a -> b
166+ liftRef f (Ref x) (Ref y) = f x y
167+
168+ refEq :: forall a. Ref a -> Ref a -> Boolean
169+ refEq = liftRef unsafeRefEq
170+
171+ refIneq :: forall a. Ref a -> Ref a -> Boolean
172+ refIneq = liftRef unsafeRefIneq
173+
174+ foreign import unsafeRefEq "function unsafeRefEq(r1) {\
175+ \ return function(r2) {\
176+ \ return r1 === r2;\
177+ \ };\
178+ \}" :: forall a. a -> a -> Boolean
179+
180+ foreign import unsafeRefIneq "function unsafeRefIneq(r1) {\
181+ \ return function(r2) {\
182+ \ return r1 !== r2;\
183+ \ };\
184+ \}" :: forall a. a -> a -> Boolean
185+
186+ instance Eq (Ref a) where
187+ (==) = refEq
188+ (/=) = refIneq
189+
190+ instance Eq String where
191+ (==) = unsafeRefEq
192+ (/=) = unsafeRefIneq
193+
194+ instance Eq Number where
195+ (==) = unsafeRefEq
196+ (/=) = unsafeRefIneq
197+
198+ instance Eq Boolean where
199+ (==) = unsafeRefEq
200+ (/=) = unsafeRefIneq
201+
202+ instance (Eq a) => Eq [a] where
203+ (==) [] [] = true
204+ (==) (x:xs) (y:ys) = x == y && xs == ys
205+ (==) _ _ = false
206+ (/=) xs ys = not (xs == ys)
207+
208+ infixl 4 <
209+ infixl 4 >
210+ infixl 4 <=
211+ infixl 4 >=
212+
213+ class Ord a where
214+ (<) :: a -> a -> Boolean
215+ (>) :: a -> a -> Boolean
216+ (<=) :: a -> a -> Boolean
217+ (>=) :: a -> a -> Boolean
218+
219+ foreign import numLess "function numLess(n1) {\
220+ \ return function(n2) {\
221+ \ return n1 < n2;\
222+ \ };\
223+ \}" :: Number -> Number -> Boolean
224+
225+ foreign import numLessEq "function numLessEq(n1) {\
226+ \ return function(n2) {\
227+ \ return n1 <= n2;\
228+ \ };\
229+ \}" :: Number -> Number -> Boolean
230+
231+ foreign import numGreater "function numGreater(n1) {\
232+ \ return function(n2) {\
233+ \ return n1 > n2;\
234+ \ };\
235+ \}" :: Number -> Number -> Boolean
236+
237+ foreign import numGreaterEq "function numGreaterEq(n1) {\
238+ \ return function(n2) {\
239+ \ return n1 >= n2;\
240+ \ };\
241+ \}" :: Number -> Number -> Boolean
242+
243+ instance Ord Number where
244+ (<) = numLess
245+ (>) = numGreater
246+ (<=) = numLessEq
247+ (>=) = numGreaterEq
248+
249+ infixl 10 &
250+ infixl 10 |
251+ infixl 10 ^
252+
253+ class Bits b where
254+ (&) :: b -> b -> b
255+ (|) :: b -> b -> b
256+ (^) :: b -> b -> b
257+ shl :: b -> Number -> b
258+ shr :: b -> Number -> b
259+ zshr :: b -> Number -> b
260+ complement :: b -> b
261+
262+ foreign import numShl "function numShl(n1) {\
263+ \ return function(n2) {\
264+ \ return n1 << n2;\
265+ \ };\
266+ \}" :: Number -> Number -> Number
267+
268+ foreign import numShr "function numShr(n1) {\
269+ \ return function(n2) {\
270+ \ return n1 >> n2;\
271+ \ };\
272+ \}" :: Number -> Number -> Number
273+
274+ foreign import numZshr "function numZshr(n1) {\
275+ \ return function(n2) {\
276+ \ return n1 >>> n2;\
277+ \ };\
278+ \}" :: Number -> Number -> Number
279+
280+ foreign import numAnd "function numAnd(n1) {\
281+ \ return function(n2) {\
282+ \ return n1 & n2;\
283+ \ };\
284+ \}" :: Number -> Number -> Number
285+
286+ foreign import numOr "function numOr(n1) {\
287+ \ return function(n2) {\
288+ \ return n1 | n2;\
289+ \ };\
290+ \}" :: Number -> Number -> Number
291+
292+ foreign import numXor "function numXor(n1) {\
293+ \ return function(n2) {\
294+ \ return n1 ^ n2;\
295+ \ };\
296+ \}" :: Number -> Number -> Number
297+
298+ foreign import numComplement "function numComplement(n) {\
299+ \ return ~n;\
300+ \}" :: Number -> Number
301+
302+ instance Bits Number where
303+ (&) = numAnd
304+ (|) = numOr
305+ (^) = numXor
306+ shl = numShl
307+ shr = numShr
308+ zshr = numZshr
309+ complement = numComplement
310+
311+ infixl 8 !!
312+
313+ foreign import (!!) "function $bang$bang(xs) {\
314+ \ return function(n) {\
315+ \ return xs[n];\
316+ \ };\
317+ \}" :: forall a. [a] -> Number -> a
318+
319+ infixr 2 ||
320+ infixr 3 &&
321+
322+ class BoolLike b where
323+ (&&) :: b -> b -> b
324+ (||) :: b -> b -> b
325+ not :: b -> b
326+
327+ foreign import boolAnd "function boolAnd(b1) {\
328+ \ return function(b2) {\
329+ \ return b1 && b2;\
330+ \ };\
331+ \}" :: Boolean -> Boolean -> Boolean
332+
333+ foreign import boolOr "function boolOr(b1) {\
334+ \ return function(b2) {\
335+ \ return b1 || b2;\
336+ \ };\
337+ \}" :: Boolean -> Boolean -> Boolean
338+
339+ foreign import boolNot "function boolNot(b) {\
340+ \ return !b;\
341+ \}" :: Boolean -> Boolean
342+
343+ instance BoolLike Boolean where
344+ (&&) = boolAnd
345+ (||) = boolOr
346+ not = boolNot
347+
348+ infixr 5 ++
349+
350+ foreign import (++) "function $plus$plus(s1) {\
351+ \ return function(s2) {\
352+ \ return s1 + s2;\
353+ \ };\
354+ \}" :: String -> String -> String
355+
356+module Data.Monoid where
357+
358+ import Prelude
359+ import Data.Array (foldl)
360+
361+ infixr 6 <>
362+
363+ class Monoid m where
364+ mempty :: m
365+ (<>) :: m -> m -> m
366+
367+ instance Monoid String where
368+ mempty = ""
369+ (<>) = (++)
370+
371+ instance Monoid [a] where
372+ mempty = []
373+ (<>) = Data.Array.concat
374+
375+ mconcat :: forall m. (Monoid m) => [m] -> m
376+ mconcat = foldl (<>) mempty
377+
378+module Control.Monad where
379+
380+ import Prelude
381+ import Data.Array
382+
383+ replicateM :: forall m a. (Monad m) => Number -> m a -> m [a]
384+ replicateM 0 _ = return []
385+ replicateM n m = do
386+ a <- m
387+ as <- replicateM (n - 1) m
388+ return (a : as)
389+
390+ mapM :: forall m a b. (Monad m) => (a -> m b) -> [a] -> m [b]
391+ mapM _ [] = return []
392+ mapM f (a:as) = do
393+ b <- f a
394+ bs <- mapM f as
395+ return (b : bs)
396+
397+ infixr 1 >=>
398+ infixr 1 <=<
399+
400+ (>=>) :: forall m a b c. (Monad m) => (a -> m b) -> (b -> m c) -> a -> m c
401+ (>=>) f g a = do
402+ b <- f a
403+ g b
404+
405+ (<=<) :: forall m a b c. (Monad m) => (b -> m c) -> (a -> m b) -> a -> m c
406+ (<=<) = flip (>=>)
407+
408+ sequence :: forall m a. (Monad m) => [m a] -> m [a]
409+ sequence [] = return []
410+ sequence (m:ms) = do
411+ a <- m
412+ as <- sequence ms
413+ return (a : as)
414+
415+ join :: forall m a. (Monad m) => m (m a) -> m a
416+ join mm = do
417+ m <- mm
418+ m
419+
420+ foldM :: forall m a b. (Monad m) => (a -> b -> m a) -> a -> [b] -> m a
421+ foldM _ a [] = return a
422+ foldM f a (b:bs) = f a b >>= \a' -> foldM f a' bs
423+
424+ when :: forall m. (Monad m) => Boolean -> m {} -> m {}
425+ when true m = m
426+ when false _ = return {}
427+
428+ zipWithM :: forall m a b c. (Monad m) => (a -> b -> m c) -> [a] -> [b] -> m [c]
429+ zipWithM f xs ys = sequence $ zipWith f xs ys
430+
431+module Data.Maybe where
432+
433+ import Prelude
434+
435+ data Maybe a = Nothing | Just a
436+
437+ maybe :: forall a b. b -> (a -> b) -> Maybe a -> b
438+ maybe b _ Nothing = b
439+ maybe _ f (Just a) = f a
440+
441+ fromMaybe :: forall a. a -> Maybe a -> a
442+ fromMaybe a = maybe a (id :: forall a. a -> a)
443+
444+ instance Monad Maybe where
445+ return = Just
446+ (>>=) m f = maybe Nothing f m
447+
448+ instance Applicative Maybe where
449+ pure = Just
450+ (<*>) (Just fn) x = fn <$> x
451+ (<*>) Nothing _ = Nothing
452+
453+ instance Functor Maybe where
454+ (<$>) fn (Just x) = Just (fn x)
455+ (<$>) _ _ = Nothing
456+
457+ instance (Show a) => Show (Maybe a) where
458+ show (Just x) = "Just " ++ (show x)
459+ show Nothing = "Nothing"
460+
461+module Data.Either where
462+
463+ import Prelude
464+
465+ data Either a b = Left a | Right b
466+
467+ either :: forall a b c. (a -> c) -> (b -> c) -> Either a b -> c
468+ either f _ (Left a) = f a
469+ either _ g (Right b) = g b
470+
471+ instance Monad (Either e) where
472+ return = Right
473+ (>>=) = either (\e _ -> Left e) (\a f -> f a)
474+
475+ instance Applicative (Either e) where
476+ pure = Right
477+ (<*>) (Left e) _ = Left e
478+ (<*>) (Right f) r = f <$> r
479+
480+ instance Functor (Either a) where
481+ (<$>) _ (Left x) = Left x
482+ (<$>) f (Right y) = Right (f y)
483+
484+ instance (Show a, Show b) => Show (Either a b) where
485+ show (Left x) = "Left " ++ (show x)
486+ show (Right y) = "Right " ++ (show y)
487+
488+module Data.Array where
489+
490+ import Prelude
491+ import Data.Maybe
492+
493+ head :: forall a. [a] -> Maybe a
494+ head (x : _) = Just x
495+ head _ = Nothing
496+
497+ tail :: forall a. [a] -> Maybe [a]
498+ tail (_ : xs) = Just xs
499+ tail _ = Nothing
500+
501+ map :: forall a b. (a -> b) -> [a] -> [b]
502+ map _ [] = []
503+ map f (x:xs) = f x : map f xs
504+
505+ foldr :: forall a b. (a -> b -> a) -> a -> [b] -> a
506+ foldr f a (b : bs) = f (foldr f a bs) b
507+ foldr _ a [] = a
508+
509+ foldl :: forall a b. (b -> a -> b) -> b -> [a] -> b
510+ foldl _ b [] = b
511+ foldl f b (a:as) = foldl f (f b a) as
512+
513+ foreign import length "function length(xs) {\
514+ \ return xs.length;\
515+ \}" :: forall a. [a] -> Number
516+
517+ foreign import indexOf "function indexOf(l) {\
518+ \ return function (e) {\
519+ \ return l.indexOf(e);\
520+ \ };\
521+ \}" :: forall a. [a] -> a -> Number
522+
523+ foreign import lastIndexOf "function lastIndexOf(l) {\
524+ \ return function (e) {\
525+ \ return l.lastIndexOf(e);\
526+ \ };\
527+ \}" :: forall a. [a] -> a -> Number
528+
529+ foreign import concat "function concat(l1) {\
530+ \ return function (l2) {\
531+ \ return l1.concat(l2);\
532+ \ };\
533+ \}" :: forall a. [a] -> [a] -> [a]
534+
535+ foreign import joinS "function joinS(l) {\
536+ \ return l.join();\
537+ \}" :: [String] -> String
538+
539+ foreign import joinWith "function joinWith(l) {\
540+ \ return function (s) {\
541+ \ return l.join(s);\
542+ \ };\
543+ \}" :: [String] -> String -> String
544+
545+ foreign import push "function push(l) {\
546+ \ return function (e) {\
547+ \ var l1 = l.slice();\
548+ \ l1.push(e); \
549+ \ return l1;\
550+ \ };\
551+ \}" :: forall a. [a] -> a -> [a]
552+
553+ foreign import reverse "function reverse(l) {\
554+ \ var l1 = l.slice();\
555+ \ l1.reverse(); \
556+ \ return l1;\
557+ \}" :: forall a. [a] -> [a]
558+
559+ foreign import shift "function shift(l) {\
560+ \ var l1 = l.slice();\
561+ \ l1.shift();\
562+ \ return l1;\
563+ \}" :: forall a. [a] -> [a]
564+
565+ foreign import slice "function slice(s) {\
566+ \ return function(e) {\
567+ \ return function (l) {\
568+ \ return l.slice(s, e);\
569+ \ };\
570+ \ };\
571+ \}" :: forall a. Number -> Number -> [a] -> [a]
572+
573+ foreign import sort "function sort(l) {\
574+ \ var l1 = l.slice();\
575+ \ l1.sort();\
576+ \ return l1;\
577+ \}" :: forall a. [a] -> [a]
578+
579+ foreign import insertAt
580+ "function insertAt(index) {\
581+ \ return function(a) {\
582+ \ return function(l) {\
583+ \ var l1 = l.slice();\
584+ \ l1.splice(index, 0, a);\
585+ \ return l1;\
586+ \ }; \
587+ \ };\
588+ \}":: forall a. Number -> a -> [a] -> [a]
589+
590+ foreign import deleteAt
591+ "function deleteAt(index) {\
592+ \ return function(n) {\
593+ \ return function(l) {\
594+ \ var l1 = l.slice();\
595+ \ l1.splice(index, n);\
596+ \ return l1;\
597+ \ }; \
598+ \ };\
599+ \}":: forall a. Number -> Number -> [a] -> [a]
600+
601+ foreign import updateAt
602+ "function updateAt(index) {\
603+ \ return function(a) {\
604+ \ return function(l) {\
605+ \ var l1 = l.slice();\
606+ \ l1[index] = a;\
607+ \ return l1;\
608+ \ }; \
609+ \ };\
610+ \}":: forall a. Number -> a -> [a] -> [a]
611+
612+ infixr 6 :
613+
614+ (:) :: forall a. a -> [a] -> [a]
615+ (:) a = concat [a]
616+
617+ singleton :: forall a. a -> [a]
618+ singleton a = [a]
619+
620+ concatMap :: forall a b. [a] -> (a -> [b]) -> [b]
621+ concatMap [] f = []
622+ concatMap (a:as) f = f a `concat` concatMap as f
623+
624+ filter :: forall a. (a -> Boolean) -> [a] -> [a]
625+ filter _ [] = []
626+ filter p (x:xs) | p x = x : filter p xs
627+ filter p (_:xs) = filter p xs
628+
629+ find :: forall a. (a -> Boolean) -> [a] -> Maybe a
630+ find _ [] = Nothing
631+ find p (x:xs) | p x = Just x
632+ find p (_:xs) = find p xs
633+
634+ isEmpty :: forall a. [a] -> Boolean
635+ isEmpty [] = true
636+ isEmpty _ = false
637+
638+ range :: Number -> Number -> [Number]
639+ range lo hi | lo > hi = []
640+ range lo hi = lo : range (lo + 1) hi
641+
642+ zipWith :: forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
643+ zipWith f (a:as) (b:bs) = f a b : zipWith f as bs
644+ zipWith _ _ _ = []
645+
646+ any :: forall a. (a -> Boolean) -> [a] -> Boolean
647+ any _ [] = false
648+ any p (a:as) = p a || any p as
649+
650+ all :: forall a. (a -> Boolean) -> [a] -> Boolean
651+ all _ [] = true
652+ all p (a:as) = p a && all p as
653+
654+ drop :: forall a. Number -> [a] -> [a]
655+ drop 0 xs = xs
656+ drop _ [] = []
657+ drop n (x:xs) = drop (n - 1) xs
658+
659+ take :: forall a. Number -> [a] -> [a]
660+ take 0 _ = []
661+ take _ [] = []
662+ take n (x:xs) = x : take (n - 1) xs
663+
664+ instance (Show a) => Show [a] where
665+ show xs = "[" ++ joinWith (map show xs) "," ++ "]"
666+
667+ instance Functor [] where
668+ (<$>) = map
669+
670+ instance Monad [] where
671+ return = singleton
672+ (>>=) = concatMap
673+
674+ instance Alternative [] where
675+ empty = []
676+ (<|>) = concat
677+
678+module Data.Array.Unsafe where
679+
680+ head :: forall a. [a] -> a
681+ head (x : _) = x
682+
683+ tail :: forall a. [a] -> [a]
684+ tail (_ : xs) = xs
685+
686+module Data.Tuple where
687+
688+ import Prelude
689+ import Data.Array
690+
691+ data Tuple a b = Tuple a b
692+
693+ instance (Show a, Show b) => Show (Tuple a b) where
694+ show (Tuple a b) = "Tuple(" ++ show a ++ ", " ++ show b ++ ")"
695+
696+ curry :: forall a b c. (Tuple a b -> c) -> a -> b -> c
697+ curry f a b = f (Tuple a b)
698+
699+ uncurry :: forall a b c. (a -> b -> c) -> Tuple a b -> c
700+ uncurry f (Tuple a b) = f a b
701+
702+ zip :: forall a b. [a] -> [b] -> [Tuple a b]
703+ zip = zipWith Tuple
704+
705+ unzip :: forall a b. [Tuple a b] -> Tuple [a] [b]
706+ unzip ((Tuple a b):ts) = case unzip ts of
707+ Tuple as bs -> Tuple (a : as) (b : bs)
708+ unzip [] = Tuple [] []
709+
710+module Data.String where
711+
712+ foreign import lengthS "function lengthS(s) {\
713+ \ return s.length;\
714+ \}" :: String -> Number
715+
716+ foreign import charAt "function charAt(i) {\
717+ \ return function(s) {\
718+ \ return s.charAt(i); \
719+ \ };\
720+ \}" :: Number -> String -> String
721+
722+ foreign import indexOfS "function indexOfS(s1) {\
723+ \ return function(s2) {\
724+ \ return s1.indexOf(s2);\
725+ \ }; \
726+ \}" :: String -> String -> Number
727+
728+ foreign import lastIndexOfS "function lastIndexOfS(s1) {\
729+ \ return function(s2) {\
730+ \ return s1.lastIndexOf(s2);\
731+ \ };\
732+ \}" :: String -> String -> Number
733+
734+ foreign import localeCompare "function localeCompare(s1) {\
735+ \ return function(s2) {\
736+ \ return s1.localeCompare(s2);\
737+ \ };\
738+ \}" :: String -> String -> Number
739+
740+ foreign import replace "function replace(s1) {\
741+ \ return function(s2) {\
742+ \ return function(s3) {\
743+ \ return s3.replace(s1, s2);\
744+ \ };\
745+ \ };\
746+ \}" :: String -> String -> String -> String
747+
748+ foreign import sliceS "function sliceS(st) {\
749+ \ return function(e) {\
750+ \ return function(s) {\
751+ \ return s.slice(st, e);\
752+ \ };\
753+ \ };\
754+ \}" :: Number -> Number -> String -> String
755+
756+ foreign import split "function split(sep) {\
757+ \ return function(s) {\
758+ \ return s.split(s);\
759+ \ };\
760+ \}" :: String -> String -> [String]
761+
762+ foreign import substr "function substr(n1) {\
763+ \ return function(n2) {\
764+ \ return function(s) {\
765+ \ return s.substr(n1, n2);\
766+ \ };\
767+ \ };\
768+ \}" :: Number -> Number -> String -> String
769+
770+ foreign import substring "function substring(n1) {\
771+ \ return function(n2) {\
772+ \ return function(s) {\
773+ \ return s.substring(n1, n2);\
774+ \ };\
775+ \ };\
776+ \}" :: Number -> Number -> String -> String
777+
778+ foreign import toLower "function toLower(s) {\
779+ \ return s.toLower();\
780+ \}" :: String -> String
781+
782+ foreign import toUpper "function toUpper(s) {\
783+ \ return s.toUpper();\
784+ \}" :: String -> String
785+
786+ foreign import trim "function trim(s) {\
787+ \ return s.trim();\
788+ \}" :: String -> String
789+
790+module Data.String.Regex where
791+
792+ foreign import data Regex :: *
793+
794+ foreign import regex "function regex(s1) {\
795+ \ return function(s2) {\
796+ \ return new Regex(s1, s2);\
797+ \ };\
798+ \}" :: String -> String -> Regex
799+
800+ foreign import test "function test(r) {\
801+ \ return function (s) {\
802+ \ return r.test(s);\
803+ \ };\
804+ \}" :: Regex -> String -> Boolean
805+
806+ foreign import match "function match(r) {\
807+ \ return function (s) {\
808+ \ return s.match(r); \
809+ \ };\
810+ \}" :: Regex -> String -> [String]
811+
812+ foreign import replaceR "function replaceR(r) {\
813+ \ return function(s1) {\
814+ \ return function(s2) {\
815+ \ return s2.replace(r, s1);\
816+ \ };\
817+ \ };\
818+ \}" :: Regex -> String -> String -> String
819+
820+ foreign import search "function search(r) {\
821+ \ return function (s) {\
822+ \ return s.search(r);\
823+ \ };\
824+ \}" :: Regex -> String -> Number
825+
826+module Global where
827+
828+ foreign import nan "var nan = NaN;" :: Number
829+
830+ foreign import infinity "var infinity = Infinity;" :: Number
831+
832+ foreign import toExponential "function toExponential(n) {\
833+ \ return n.toExponential();\
834+ \}" :: Number -> String
835+
836+ foreign import toFixed "function toFixed(d) {\
837+ \ return function(n) {\
838+ \ return n.toFixed(d);\
839+ \ };\
840+ \}" :: Number -> Number -> String
841+
842+ foreign import toPrecision "function toPrecision(d) {\
843+ \ return function(n) {\
844+ \ return n.toPrecision(d);\
845+ \ };\
846+ \}" :: Number -> Number -> String
847+
848+ foreign import isFinite :: Number -> Boolean
849+
850+ foreign import parseFloat :: String -> Number
851+
852+ foreign import parseInt :: String -> Number
853+
854+ foreign import encodeURIComponent :: String -> String
855+
856+ foreign import decodeURIComponent :: String -> String
857+
858+ foreign import encodeURI :: String -> String
859+
860+ foreign import decodeURI :: String -> String
861+
862+ foreign import isNaN :: Number -> Boolean
863+
864+module Math where
865+
866+ foreign import abs "function abs(n){\
867+ \ return Math.abs(n);\
868+ \}" :: Number -> Number
869+
870+ foreign import acos "function acos(n){\
871+ \ return Math.acos(n);\
872+ \}" :: Number -> Number
873+
874+ foreign import asin "function asin(n){\
875+ \ return Math.asin(n);\
876+ \}" :: Number -> Number
877+
878+ foreign import atan "function atan(n){\
879+ \ return Math.atan(n);\
880+ \}" :: Number -> Number
881+
882+ foreign import atan2 "function atan2(y){\
883+ \ return function (x) {\
884+ \ return Math.atan2(y, x);\
885+ \ };\
886+ \}" :: Number -> Number -> Number
887+
888+ foreign import aceil "function aceil(n){\
889+ \ return Math.aceil(n);\
890+ \}" :: Number -> Number
891+
892+ foreign import cos "function cos(n){\
893+ \ return Math.cos(n);\
894+ \}" :: Number -> Number
895+
896+ foreign import exp "function exp(n){\
897+ \ return Math.exp(n);\
898+ \}" :: Number -> Number
899+
900+ foreign import floor "function floor(n){\
901+ \ return Math.floor(n);\
902+ \}" :: Number -> Number
903+
904+ foreign import log "function log(n){\
905+ \ return Math.log(n);\
906+ \}" :: Number -> Number
907+
908+ foreign import max "function max(n){\
909+ \ return Math.max(n);\
910+ \}" :: Number -> Number
911+
912+ foreign import min "function min(n){\
913+ \ return Math.min(n);\
914+ \}" :: Number -> Number
915+
916+ foreign import pow "function pow(n){\
917+ \ return Math.pow(n);\
918+ \}" :: Number -> Number
919+
920+ foreign import round "function round(n){\
921+ \ return Math.round(n);\
922+ \}" :: Number -> Number
923+
924+ foreign import sin "function sin(n){\
925+ \ return Math.sin(n);\
926+ \}" :: Number -> Number
927+
928+ foreign import sqrt "function sqrt(n){\
929+ \ return Math.sqrt(n);\
930+ \}" :: Number -> Number
931+
932+ foreign import tan "function tan(n){\
933+ \ return Math.tan(n);\
934+ \}" :: Number -> Number
935+
936+ foreign import e "var e = Math.E;" :: Number
937+ foreign import ln2 "var ln2 = Math.LN2;" :: Number
938+ foreign import ln10 "var ln10 = Math.LN10;" :: Number
939+ foreign import log2e "var log2e = Math.LOG2E;" :: Number
940+ foreign import log10e "var log10e = Math.LOG10E;" :: Number
941+ foreign import pi "var pi = Math.PI;" :: Number
942+ foreign import sqrt1_2 "var sqrt1_2 = Math.SQRT1_2;" :: Number
943+ foreign import sqrt2 "var sqrt2 = Math.SQRT2;" :: Number
944+
945+module Control.Monad.Eff where
946+
947+ import Prelude
948+
949+ foreign import data Eff :: # ! -> * -> *
950+
951+ foreign import retEff "function retEff(a) {\
952+ \ return function() {\
953+ \ return a;\
954+ \ };\
955+ \}" :: forall e a. a -> Eff e a
956+
957+ foreign import bindEff "function bindEff(a) {\
958+ \ return function(f) {\
959+ \ return function() {\
960+ \ return f(a())();\
961+ \ };\
962+ \ };\
963+ \}" :: forall e a b. Eff e a -> (a -> Eff e b) -> Eff e b
964+
965+ type Pure a = forall e. Eff e a
966+
967+ foreign import runPure "function runPure(f) {\
968+ \ return f();\
969+ \}" :: forall a. Pure a -> a
970+
971+ instance Monad (Eff e) where
972+ return = retEff
973+ (>>=) = bindEff
974+
975+ foreign import untilE "function untilE(f) {\
976+ \ return function() {\
977+ \ while (!f()) { }\
978+ \ return {};\
979+ \ };\
980+ \}" :: forall e. Eff e Boolean -> Eff e {}
981+
982+ foreign import whileE "function whileE(f) {\
983+ \ return function(a) {\
984+ \ return function() {\
985+ \ while (f()) {\
986+ \ a();\
987+ \ }\
988+ \ return {};\
989+ \ };\
990+ \ };\
991+ \}" :: forall e a. Eff e Boolean -> Eff e a -> Eff e {}
992+
993+ foreign import forE "function forE(lo) {\
994+ \ return function(hi) {\
995+ \ return function(f) {\
996+ \ return function() {\
997+ \ for (var i = lo; i < hi; i++) {\
998+ \ f(i)();\
999+ \ }\
1000+ \ };\
1001+ \ };\
1002+ \ };\
1003+ \}" :: forall e. Number -> Number -> (Number -> Eff e {}) -> Eff e {}
1004+
1005+
1006+ foreign import foreachE "function foreachE(as) {\
1007+ \ return function(f) {\
1008+ \ for (var i = 0; i < as.length; i++) {\
1009+ \ f(as[i])();\
1010+ \ }\
1011+ \ };\
1012+ \}" :: forall e a. [a] -> (a -> Eff e {}) -> Eff e {}
1013+
1014+module Control.Monad.Eff.Unsafe where
1015+
1016+ import Control.Monad.Eff
1017+
1018+ foreign import unsafeInterleaveEff
1019+ "function unsafeInterleaveEff(f) {\
1020+ \ return f;\
1021+ \}" :: forall eff1 eff2 a. Eff eff1 a -> Eff eff2 a
1022+
1023+module Random where
1024+
1025+ import Control.Monad.Eff
1026+
1027+ foreign import data Random :: !
1028+
1029+ foreign import random "function random() {\
1030+ \ return Math.random();\
1031+ \}" :: forall e. Eff (random :: Random | e) Number
1032+
1033+module Control.Monad.Error where
1034+
1035+ import Control.Monad.Eff
1036+
1037+ foreign import data Error :: * -> !
1038+
1039+ foreign import throwError "function throwError(e) {\
1040+ \ return function() {\
1041+ \ throw e;\
1042+ \ };\
1043+ \}" :: forall a e r. e -> Eff (err :: Error e | r) a
1044+
1045+ foreign import catchError "function catchError(c) {\
1046+ \ return function(t) {\
1047+ \ return function() {\
1048+ \ try {\
1049+ \ return t();\
1050+ \ } catch(e) {\
1051+ \ return c(e)();\
1052+ \ }\
1053+ \ };\
1054+ \ };\
1055+ \}" :: forall e r a. (e -> Eff r a) -> Eff (err :: Error e | r) a -> Eff r a
1056+
1057+module Data.IORef where
1058+
1059+ import Control.Monad.Eff
1060+
1061+ foreign import data Ref :: !
1062+
1063+ foreign import data IORef :: * -> *
1064+
1065+ foreign import newIORef "function newIORef(val) {\
1066+ \ return function () {\
1067+ \ return { value: val };\
1068+ \ };\
1069+ \}" :: forall s r. s -> Eff (ref :: Ref | r) (IORef s)
1070+
1071+ foreign import readIORef "function readIORef(ref) {\
1072+ \ return function() {\
1073+ \ return ref.value;\
1074+ \ };\
1075+ \}" :: forall s r. IORef s -> Eff (ref :: Ref | r) s
1076+
1077+
1078+ foreign import modifyIORef "function modifyIORef(ref) {\
1079+ \ return function(f) {\
1080+ \ return function() {\
1081+ \ ref.value = f(ref.value);\
1082+ \ return {};\
1083+ \ };\
1084+ \ };\
1085+ \}" :: forall s r. IORef s -> (s -> s) -> Eff (ref :: Ref | r) {}
1086+
1087+ foreign import writeIORef "function writeIORef(ref) {\
1088+ \ return function(val) {\
1089+ \ return function() {\
1090+ \ ref.value = val;\
1091+ \ return {};\
1092+ \ };\
1093+ \ };\
1094+ \}" :: forall s r. IORef s -> s -> Eff (ref :: Ref | r) {}
1095+
1096+ foreign import unsafeRunIORef "function unsafeRunIORef(f) {\
1097+ \ return f;\
1098+ \}" :: forall eff a. Eff (ref :: Ref | eff) a -> Eff eff a
1099+
1100+module Debug.Trace where
1101+
1102+ import Prelude
1103+ import Control.Monad.Eff
1104+
1105+ foreign import data Trace :: !
1106+
1107+ foreign import trace "function trace(s) {\
1108+ \ return function() {\
1109+ \ console.log(s);\
1110+ \ return {};\
1111+ \ };\
1112+ \}" :: forall r. String -> Eff (trace :: Trace | r) {}
1113+
1114+ print :: forall a r. (Show a) => a -> Eff (trace :: Trace | r) {}
1115+ print o = trace (show o)
1116+
1117+module Control.Monad.ST where
1118+
1119+ import Control.Monad.Eff
1120+
1121+ foreign import data ST :: * -> !
1122+
1123+ foreign import data STRef :: * -> * -> *
1124+
1125+ foreign import data STArray :: * -> * -> *
1126+
1127+ foreign import newSTRef "function newSTRef(val) {\
1128+ \ return function () {\
1129+ \ return { value: val };\
1130+ \ };\
1131+ \}" :: forall a h r. a -> Eff (st :: ST h | r) (STRef h a)
1132+
1133+ foreign import readSTRef "function readSTRef(ref) {\
1134+ \ return function() {\
1135+ \ return ref.value;\
1136+ \ };\
1137+ \}" :: forall a h r. STRef h a -> Eff (st :: ST h | r) a
1138+
1139+ foreign import modifySTRef "function modifySTRef(ref) {\
1140+ \ return function(f) {\
1141+ \ return function() {\
1142+ \ return ref.value = f(ref.value);\
1143+ \ };\
1144+ \ };\
1145+ \}" :: forall a h r. STRef h a -> (a -> a) -> Eff (st :: ST h | r) a
1146+
1147+ foreign import writeSTRef "function writeSTRef(ref) {\
1148+ \ return function(a) {\
1149+ \ return function() {\
1150+ \ return ref.value = a;\
1151+ \ };\
1152+ \ };\
1153+ \}" :: forall a h r. STRef h a -> a -> Eff (st :: ST h | r) a
1154+
1155+ foreign import newSTArray "function newSTArray(len) {\
1156+ \ return function(a) {\
1157+ \ return function() {\
1158+ \ var arr = [];\
1159+ \ for (var i = 0; i < len; i++) {\
1160+ \ arr[i] = a;\
1161+ \ };\
1162+ \ return arr;\
1163+ \ };\
1164+ \ };\
1165+ \}" :: forall a h r. Number -> a -> Eff (st :: ST h | r) (STArray h a)
1166+
1167+ foreign import peekSTArray "function peekSTArray(arr) {\
1168+ \ return function(i) {\
1169+ \ return function() {\
1170+ \ return arr[i];\
1171+ \ };\
1172+ \ };\
1173+ \}" :: forall a h r. STArray h a -> Eff (st :: ST h | r) a
1174+
1175+ foreign import pokeSTArray "function pokeSTArray(arr) {\
1176+ \ return function(i) {\
1177+ \ return function(a) {\
1178+ \ return function() {\
1179+ \ return arr[i] = a;\
1180+ \ };\
1181+ \ };\
1182+ \ };\
1183+ \}" :: forall a h r. STArray h a -> Number -> a -> Eff (st :: ST h | r) a
1184+
1185+ foreign import runST "function runST(f) {\
1186+ \ return f;\
1187+ \}" :: forall a r. (forall h. Eff (st :: ST h | r) a) -> Eff r a
1188+
1189+ foreign import runSTArray "function runSTArray(f) {\
1190+ \ return f;\
1191+ \}" :: forall a r. (forall h. Eff (st :: ST h | r) (STArray h a)) -> Eff r [a]
1192+
1193+module Data.Enum where
1194+
1195+ import Data.Maybe
1196+
1197+ class Enum a where
1198+ toEnum :: Number -> Maybe a
1199+ fromEnum :: a -> Number
prelude/tests/.gitignorenew file+1
@@ -0,0 +1 @@
1+Eff.js
prelude/tests/Eff.pursnew file+60
@@ -0,0 +1,60 @@
1+module Tests where
2+
3+import Prelude
4+import Eff
5+import Errors
6+import Trace
7+import Global
8+
9+test1 n = runPure (catchError (\s -> return 0) $ do
10+ case {} of
11+ _ | n > 10 -> do
12+ throwError "Error!"
13+ _ -> return n)
14+
15+test2 = do
16+ trace "Hello World"
17+ throwError "Error!"
18+
19+test3 n = catchError (\s -> return 0) $ do
20+ case {} of
21+ _ | n > 10 -> do
22+ trace "n > 10"
23+ throwError "Error!"
24+ _ -> return n
25+
26+test4 = do
27+ trace "Hello World!"
28+ return 0
29+
30+test5 _ = do
31+ trace "Hello World!"
32+ test5 {}
33+
34+test6 s = do
35+ trace s
36+ test6 (s ++ " test")
37+
38+import ST
39+
40+test7 _ = do
41+ n <- runST (do
42+ r <- newSTRef 0
43+ modifySTRef r $ \n -> n + 1
44+ readSTRef r)
45+ print n
46+
47+test8 _ = (\_1 _2 -> {}) <$> print "Test" <*> print 8
48+
49+test9 _ = runST (do
50+ r <- newSTRef 1
51+ whileE (return true) $ do
52+ n <- readSTRef r
53+ trace $ "Count " ++ show n
54+ modifySTRef r $ (+) 1)
55+
56+module Main where
57+
58+import Tests
59+
60+main = test5 {}
prelude/tests/build.shnew file+2
@@ -0,0 +1,2 @@
1+psc ../prelude.purs Eff.purs --magic-do --tco --run-main --no-prelude --entry-point Main -o Eff.js
2+
prelude/updateDocs.shnew file+2
@@ -0,0 +1,2 @@
1+../dist/build/docgen/docgen prelude.purs > README.md
2+pandoc -o ../docs/source/prelude.rst README.md
psc/Main.hsnew file+128
@@ -0,0 +1,128 @@
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+module Main where
16+
17+import qualified Language.PureScript as P
18+import System.Console.CmdTheLine
19+import Control.Applicative
20+import Control.Monad (forM)
21+import System.Exit (exitSuccess, exitFailure)
22+import qualified System.IO.UTF8 as U
23+import Text.Parsec (ParseError)
24+import qualified Paths_purescript as Paths
25+import Data.Version (showVersion)
26+
27+preludeFilename :: IO FilePath
28+preludeFilename = Paths.getDataFileName "prelude/prelude.purs"
29+
30+readInput :: Maybe [FilePath] -> IO (Either ParseError [P.Module])
31+readInput Nothing = P.runIndentParser "" P.parseModules <$> getContents
32+readInput (Just input) = fmap (fmap concat . sequence) $ forM input $ \inputFile -> do
33+ text <- U.readFile inputFile
34+ return $ P.runIndentParser inputFile P.parseModules text
35+
36+compile :: P.Options -> Maybe [FilePath] -> Maybe FilePath -> Maybe FilePath -> IO ()
37+compile opts input output externs = do
38+ modules <- readInput input
39+ case modules of
40+ Left err -> do
41+ U.print err
42+ exitFailure
43+ Right ms ->
44+ case P.compile opts ms of
45+ Left err -> do
46+ U.putStrLn err
47+ exitFailure
48+ Right (js, exts, _) -> do
49+ case output of
50+ Just path -> U.writeFile path js
51+ Nothing -> U.putStrLn js
52+ case externs of
53+ Nothing -> return ()
54+ Just filePath -> U.writeFile filePath exts
55+ exitSuccess
56+
57+useStdIn :: Term Bool
58+useStdIn = value . flag $ (optInfo [ "s", "stdin" ])
59+ { optDoc = "Read from standard input" }
60+
61+inputFiles :: Term [FilePath]
62+inputFiles = value $ posAny [] $ posInfo
63+ { posDoc = "The input .ps files" }
64+
65+outputFile :: Term (Maybe FilePath)
66+outputFile = value $ opt Nothing $ (optInfo [ "o", "output" ])
67+ { optDoc = "The output .js file" }
68+
69+externsFile :: Term (Maybe FilePath)
70+externsFile = value $ opt Nothing $ (optInfo [ "e", "externs" ])
71+ { optDoc = "The output .e.ps file" }
72+
73+tco :: Term Bool
74+tco = value $ flag $ (optInfo [ "tco" ])
75+ { optDoc = "Perform tail call optimizations" }
76+
77+performRuntimeTypeChecks :: Term Bool
78+performRuntimeTypeChecks = value $ flag $ (optInfo [ "runtime-type-checks" ])
79+ { optDoc = "Generate runtime type checks" }
80+
81+noPrelude :: Term Bool
82+noPrelude = value $ flag $ (optInfo [ "no-prelude" ])
83+ { optDoc = "Omit the Prelude" }
84+
85+magicDo :: Term Bool
86+magicDo = value $ flag $ (optInfo [ "magic-do" ])
87+ { optDoc = "Overload the do keyword to generate efficient code specifically for the Eff monad." }
88+
89+runMain :: Term (Maybe String)
90+runMain = value $ defaultOpt (Just "Main") Nothing $ (optInfo [ "main" ])
91+ { optDoc = "Generate code to run the main method in the specified module." }
92+
93+noOpts :: Term Bool
94+noOpts = value $ flag $ (optInfo [ "no-opts" ])
95+ { optDoc = "Skip the optimization phase." }
96+
97+browserNamespace :: Term String
98+browserNamespace = value $ opt "PS" $ (optInfo [ "browser-namespace" ])
99+ { optDoc = "Specify the namespace that PureScript modules will be exported to when running in the browser." }
100+
101+dceModules :: Term [String]
102+dceModules = value $ optAll [] $ (optInfo [ "m", "module" ])
103+ { optDoc = "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." }
104+
105+options :: Term P.Options
106+options = P.Options <$> tco <*> performRuntimeTypeChecks <*> magicDo <*> runMain <*> noOpts <*> browserNamespace <*> dceModules
107+
108+stdInOrInputFiles :: FilePath -> Term (Maybe [FilePath])
109+stdInOrInputFiles prelude = combine <$> useStdIn <*> (not <$> noPrelude) <*> inputFiles
110+ where
111+ combine False True input = Just (prelude : input)
112+ combine False False input = Just input
113+ combine True _ _ = Nothing
114+
115+term :: FilePath -> Term (IO ())
116+term prelude = compile <$> options <*> stdInOrInputFiles prelude <*> outputFile <*> externsFile
117+
118+termInfo :: TermInfo
119+termInfo = defTI
120+ { termName = "psc"
121+ , version = showVersion Paths.version
122+ , termDoc = "Compiles PureScript to Javascript"
123+ }
124+
125+main :: IO ()
126+main = do
127+ prelude <- preludeFilename
128+ run (term prelude, termInfo)
psci/Commands.hsnew file+68
@@ -0,0 +1,68 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Commands
4+-- Copyright : (c) Phil Freeman 2014
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+-- Commands for PSCI.
13+--
14+-----------------------------------------------------------------------------
15+
16+module Commands where
17+
18+import Language.PureScript
19+
20+-- |
21+-- Valid Meta-commands for PSCI
22+--
23+data Command
24+ -- |
25+ -- A purescript expression
26+ --
27+ = Expression Value
28+ -- |
29+ -- Show the help command
30+ --
31+ | Help
32+ -- |
33+ -- Import a module from a loaded file
34+ --
35+ | Import ModuleName
36+ -- |
37+ -- Load a file for use with importing
38+ --
39+ | LoadFile FilePath
40+ -- |
41+ -- Exit PSCI
42+ --
43+ | Quit
44+ -- |
45+ -- Reset the state of the REPL
46+ --
47+ | Reset
48+ -- |
49+ -- Binds a value to a name
50+ --
51+ | Let (Value -> Value)
52+ -- |
53+ -- Find the type of an expression
54+ --
55+ | TypeOf Value
56+
57+-- |
58+-- The help menu.
59+--
60+help :: [[String]]
61+help =
62+ [ [":? ", "Show this help menu"]
63+ , [":i <module> ", "Import <module> for use in PSCI"]
64+ , [":m <file> ", "Load <file> for importing"]
65+ , [":q ", "Quit PSCi"]
66+ , [":r ", "Reset"]
67+ , [":t <expr> ", "Show the type of <expr>"]
68+ ]
psci/Main.hsnew file+323
@@ -0,0 +1,323 @@
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+-- PureScript Compiler Interactive.
13+--
14+-----------------------------------------------------------------------------
15+
16+{-# LANGUAGE DoAndIfThenElse, FlexibleContexts #-}
17+
18+module Main where
19+
20+import Commands
21+
22+import Control.Applicative
23+import Control.Monad
24+import Control.Monad.Trans.Class
25+import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
26+import Control.Monad.Trans.State.Strict
27+
28+import Data.List (intercalate, isPrefixOf, nub, sortBy)
29+import Data.Maybe (mapMaybe)
30+import Data.Traversable (traverse)
31+import Data.Version (showVersion)
32+
33+import Parser
34+
35+import System.Console.Haskeline
36+import System.Directory (doesFileExist, findExecutable, getHomeDirectory)
37+import System.Exit
38+import System.Environment.XDG.BaseDir
39+import System.FilePath ((</>), isPathSeparator)
40+import qualified System.Console.CmdTheLine as Cmd
41+import System.Process
42+
43+import Text.Parsec (ParseError)
44+
45+import qualified Data.Map as M
46+import qualified Language.PureScript as P
47+import qualified Paths_purescript as Paths
48+import qualified System.IO.UTF8 as U (readFile)
49+
50+-- |
51+-- The PSCI state.
52+-- Holds a list of imported modules, loaded files, and partial let bindings.
53+-- The let bindings are partial,
54+-- because it makes more sense to apply the binding to the final evaluated expression.
55+--
56+data PSCiState = PSCiState
57+ { psciImportedFilenames :: [FilePath]
58+ , psciImportedModuleNames :: [P.ModuleName]
59+ , psciLoadedModules :: [P.Module]
60+ , psciLetBindings :: [P.Value -> P.Value]
61+ }
62+
63+-- State helpers
64+
65+-- |
66+-- Updates the state to have more imported modules.
67+--
68+updateImportedFiles :: FilePath -> PSCiState -> PSCiState
69+updateImportedFiles filename st = st { psciImportedFilenames = filename : psciImportedFilenames st }
70+
71+-- |
72+-- Updates the state to have more imported modules.
73+--
74+updateImports :: P.ModuleName -> PSCiState -> PSCiState
75+updateImports name st = st { psciImportedModuleNames = name : psciImportedModuleNames st }
76+
77+-- |
78+-- Updates the state to have more loaded files.
79+--
80+updateModules :: [P.Module] -> PSCiState -> PSCiState
81+updateModules modules st = st { psciLoadedModules = psciLoadedModules st ++ modules }
82+
83+-- |
84+-- Updates the state to have more let bindings.
85+--
86+updateLets :: (P.Value -> P.Value) -> PSCiState -> PSCiState
87+updateLets name st = st { psciLetBindings = name : psciLetBindings st }
88+
89+-- File helpers
90+-- |
91+-- Load the necessary modules.
92+--
93+defaultImports :: [P.ModuleName]
94+defaultImports = [P.ModuleName [P.ProperName "Prelude"]]
95+
96+-- |
97+-- Locates the node executable.
98+-- Checks for either @nodejs@ or @node@.
99+--
100+findNodeProcess :: IO (Maybe String)
101+findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names
102+ where names = ["nodejs", "node"]
103+
104+-- |
105+-- Grabs the filename where the history is stored.
106+--
107+getHistoryFilename :: IO FilePath
108+getHistoryFilename = getUserConfigFile "purescript" "psci_history"
109+
110+-- |
111+-- Grabs the filename where prelude is.
112+--
113+getPreludeFilename :: IO FilePath
114+getPreludeFilename = Paths.getDataFileName "prelude/prelude.purs"
115+
116+-- |
117+-- Loads a file for use with imports.
118+--
119+loadModule :: FilePath -> IO (Either String [P.Module])
120+loadModule filename = either (Left . show) Right . P.runIndentParser filename P.parseModules <$> U.readFile filename
121+
122+-- |
123+-- Expands tilde in path.
124+--
125+expandTilde :: FilePath -> IO FilePath
126+expandTilde ('~':p:rest) | isPathSeparator p = (</> rest) <$> getHomeDirectory
127+expandTilde p = return p
128+-- Messages
129+
130+-- |
131+-- The help message.
132+--
133+helpMessage :: String
134+helpMessage = "The following commands are available:\n\n " ++
135+ intercalate "\n " (map (intercalate " ") help)
136+
137+-- |
138+-- The welcome prologue.
139+--
140+prologueMessage :: String
141+prologueMessage = intercalate "\n"
142+ [ " ____ ____ _ _ "
143+ , "| _ \\ _ _ _ __ ___/ ___| ___ _ __(_)_ __ | |_ "
144+ , "| |_) | | | | '__/ _ \\___ \\ / __| '__| | '_ \\| __|"
145+ , "| __/| |_| | | | __/___) | (__| | | | |_) | |_ "
146+ , "|_| \\__,_|_| \\___|____/ \\___|_| |_| .__/ \\__|"
147+ , " |_| "
148+ , ""
149+ , ":? shows help"
150+ , ""
151+ , "Expressions are terminated using Ctrl+D"
152+ ]
153+
154+-- |
155+-- The quit message.
156+--
157+quitMessage :: String
158+quitMessage = "See ya!"
159+
160+-- Haskeline completions
161+
162+-- |
163+-- Loads module, function, and file completions.
164+--
165+completion :: CompletionFunc (StateT PSCiState IO)
166+completion = completeWord Nothing " \t\n\r" findCompletions
167+ where
168+ findCompletions :: String -> StateT PSCiState IO [Completion]
169+ findCompletions str = do
170+ ms <- psciLoadedModules <$> get
171+ files <- listFiles str
172+ let matches = filter (isPrefixOf str) (names ms)
173+ return $ sortBy sorter $ map simpleCompletion matches ++ files
174+ getDeclName :: P.Declaration -> Maybe P.Ident
175+ getDeclName (P.ValueDeclaration ident _ _ _) = Just ident
176+ getDeclName _ = Nothing
177+ names :: [P.Module] -> [String]
178+ names ms = nub [ show qual
179+ | P.Module moduleName ds <- ms
180+ , ident <- mapMaybe getDeclName ds
181+ , qual <- [ P.Qualified Nothing ident
182+ , P.Qualified (Just moduleName) ident]
183+ ]
184+ sorter :: Completion -> Completion -> Ordering
185+ sorter (Completion _ d1 _) (Completion _ d2 _) = compare d1 d2
186+
187+-- Compilation
188+
189+-- | Compilation options.
190+--
191+options :: P.Options
192+options = P.Options True False True (Just "Main") True "PS" []
193+
194+-- |
195+-- Makes a volatile module to execute the current expression.
196+--
197+createTemporaryModule :: Bool -> PSCiState -> P.Value -> P.Module
198+createTemporaryModule exec PSCiState{psciImportedModuleNames = imports, psciLetBindings = lets} value =
199+ let
200+ moduleName = P.ModuleName [P.ProperName "Main"]
201+ importDecl m = P.ImportDeclaration m Nothing
202+ traceModule = P.ModuleName [P.ProperName "Debug", P.ProperName "Trace"]
203+ trace = P.Var (P.Qualified (Just traceModule) (P.Ident "print"))
204+ itValue = foldl (\x f -> f x) value lets
205+ mainValue = P.App trace (P.Var (P.Qualified Nothing (P.Ident "it")))
206+ itDecl = P.ValueDeclaration (P.Ident "it") [] Nothing itValue
207+ mainDecl = P.ValueDeclaration (P.Ident "main") [] Nothing mainValue
208+ decls = if exec then [itDecl, mainDecl] else [itDecl]
209+ in
210+ P.Module moduleName $ map importDecl imports ++ decls
211+
212+-- |
213+-- Takes a value declaration and evaluates it with the current state.
214+--
215+handleDeclaration :: P.Value -> PSCiState -> InputT (StateT PSCiState IO) ()
216+handleDeclaration value st = do
217+ let m = createTemporaryModule True st value
218+ case P.compile options (psciLoadedModules st ++ [m]) of
219+ Left err -> outputStrLn err
220+ Right (js, _, _) -> do
221+ process <- lift . lift $ findNodeProcess
222+ result <- lift . lift $ traverse (\node -> readProcessWithExitCode node [] js) process
223+ case result of
224+ Just (ExitSuccess, out, _) -> outputStrLn out
225+ Just (ExitFailure _, _, err) -> outputStrLn err
226+ Nothing -> outputStrLn "Couldn't find node.js"
227+
228+-- |
229+-- Takes a value and prints its type
230+--
231+handleTypeOf :: P.Value -> PSCiState -> InputT (StateT PSCiState IO) ()
232+handleTypeOf value st = do
233+ let m = createTemporaryModule False st value
234+ case P.compile options { P.optionsMain = Nothing } (psciLoadedModules st ++ [m]) of
235+ Left err -> outputStrLn err
236+ Right (_, _, env') ->
237+ case M.lookup (P.ModuleName [P.ProperName "Main"], P.Ident "it") (P.names env') of
238+ Just (ty, _) -> outputStrLn . P.prettyPrintType $ ty
239+ Nothing -> outputStrLn "Could not find type"
240+
241+-- Commands
242+
243+-- |
244+-- Parses the input and returns either a Metacommand or an expression.
245+--
246+getCommand :: InputT (StateT PSCiState IO) (Either ParseError (Maybe Command))
247+getCommand = do
248+ firstLine <- getInputLine "> "
249+ case firstLine of
250+ Nothing -> return (Right Nothing)
251+ Just s@ (':' : _) -> return . either Left (Right . Just) $ parseCommand s -- The start of a command
252+ Just s -> either Left (Right . Just) . parseCommand <$> go [s]
253+ where
254+ go :: [String] -> InputT (StateT PSCiState IO) String
255+ go ls = maybe (return . unlines $ reverse ls) (go . (:ls)) =<< getInputLine " "
256+
257+-- |
258+-- Performs an action for each meta-command given, and also for expressions..
259+--
260+handleCommand :: Command -> InputT (StateT PSCiState IO) ()
261+handleCommand (Expression val) = lift get >>= handleDeclaration val
262+handleCommand Help = outputStrLn helpMessage
263+handleCommand (Import moduleName) = lift $ modify (updateImports moduleName)
264+handleCommand (Let l) = lift $ modify (updateLets l)
265+handleCommand (LoadFile filePath) = do
266+ absPath <- lift . lift $ expandTilde filePath
267+ exists <- lift . lift $ doesFileExist absPath
268+ if exists then do
269+ lift $ modify (updateImportedFiles absPath)
270+ either outputStrLn (lift . modify . updateModules) =<< (lift . lift $ loadModule absPath)
271+ else
272+ outputStrLn $ "Couldn't locate: " ++ filePath
273+handleCommand Reset = do
274+ files <- psciImportedFilenames <$> lift get
275+ modulesOrFirstError <- fmap concat . sequence <$> mapM (lift . lift . loadModule) files
276+ case modulesOrFirstError of
277+ Left err -> lift . lift $ putStrLn err >> exitFailure
278+ Right modules -> lift $ put (PSCiState files defaultImports modules [])
279+handleCommand (TypeOf val) = lift get >>= handleTypeOf val
280+handleCommand _ = outputStrLn "Unknown command"
281+
282+inputFiles :: Cmd.Term [FilePath]
283+inputFiles = Cmd.value $ Cmd.posAny [] $ Cmd.posInfo { Cmd.posName = "file(s)"
284+ , Cmd.posDoc = "Optional .purs files to load on start" }
285+
286+-- |
287+-- The PSCI main loop.
288+--
289+loop :: [FilePath] -> IO ()
290+loop files = do
291+ preludeFilename <- getPreludeFilename
292+ modulesOrFirstError <- fmap concat . sequence <$> mapM loadModule (preludeFilename : files)
293+ case modulesOrFirstError of
294+ Left err -> putStrLn err >> exitFailure
295+ Right modules -> do
296+ historyFilename <- getHistoryFilename
297+ let settings = defaultSettings {historyFile = Just historyFilename}
298+ flip evalStateT (PSCiState (preludeFilename : files) defaultImports modules []) . runInputT (setComplete completion settings) $ do
299+ outputStrLn prologueMessage
300+ go
301+ where
302+ go :: InputT (StateT PSCiState IO) ()
303+ go = do
304+ c <- getCommand
305+ case c of
306+ Left err -> outputStrLn (show err) >> go
307+ Right Nothing -> go
308+ Right (Just Quit) -> outputStrLn quitMessage
309+ Right (Just c') -> handleCommand c' >> go
310+
311+term :: Cmd.Term (IO ())
312+term = loop <$> inputFiles
313+
314+termInfo :: Cmd.TermInfo
315+termInfo = Cmd.defTI
316+ { Cmd.termName = "psci"
317+ , Cmd.version = showVersion Paths.version
318+ , Cmd.termDoc = "Interactive mode for PureScript"
319+ }
320+
321+main :: IO ()
322+main = Cmd.run (term, termInfo)
323+
psci/Parser.hsnew file+92
@@ -0,0 +1,92 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Parser
4+-- Copyright : (c) Phil Freeman 2014
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+-- Parser for PSCI.
13+--
14+-----------------------------------------------------------------------------
15+
16+module Parser (
17+ parseCommand
18+ ) where
19+
20+import Commands
21+
22+import Data.Char (isSpace)
23+
24+import Control.Applicative hiding (many)
25+
26+import Text.Parsec hiding ((<|>))
27+
28+import qualified Language.PureScript as P
29+
30+-- |
31+-- PSCI version of @let@.
32+-- This is essentially let from do-notation.
33+-- However, since we don't support the @Eff@ monad,
34+-- we actually want the normal @let@.
35+--
36+psciLet :: Parsec String P.ParseState Command
37+psciLet = Let <$> (P.Let <$> (P.reserved "let" *> P.indented *> P.parseBinder)
38+ <*> (P.indented *> P.reservedOp "=" *> P.parseValue))
39+
40+-- |
41+-- Parses PSCI metacommands or expressions input from the user.
42+--
43+parseCommand :: String -> Either ParseError Command
44+parseCommand = P.runIndentParser "" $ choice
45+ [ P.whiteSpace *> char ':' *> (psciHelp <|> psciImport <|> psciLoadFile <|> psciQuit <|> psciReload <|> psciTypeOf)
46+ , try psciLet
47+ , psciExpression
48+ ] <* eof
49+
50+-- |
51+-- Parses expressions entered at the PSCI repl.
52+--
53+psciExpression :: Parsec String P.ParseState Command
54+psciExpression = Expression <$> P.parseValue
55+
56+-- |
57+-- Parses 'Commands.Help' command.
58+--
59+psciHelp :: Parsec String P.ParseState Command
60+psciHelp = Help <$ char '?'
61+
62+-- |
63+-- Parses 'Commands.Import' command.
64+--
65+psciImport :: Parsec String P.ParseState Command
66+psciImport = Import <$> (char 'i' *> P.whiteSpace *> P.moduleName)
67+
68+-- |
69+-- Parses 'Commands.LoadFile' command.
70+--
71+psciLoadFile :: Parsec String P.ParseState Command
72+psciLoadFile = LoadFile . trimEnd <$> (char 'm' *> P.whiteSpace *> manyTill anyChar eof)
73+ where
74+ trimEnd = reverse . dropWhile isSpace . reverse
75+
76+-- |
77+-- Parses 'Commands.Quit' command.
78+--
79+psciQuit :: Parsec String P.ParseState Command
80+psciQuit = Quit <$ char 'q'
81+
82+-- |
83+-- Parses 'Commands.Reload' command.
84+--
85+psciReload :: Parsec String P.ParseState Command
86+psciReload = Reset <$ char 'r'
87+
88+-- |
89+-- Parses 'Commands.TypeOf' command.
90+--
91+psciTypeOf :: Parsec String P.ParseState Command
92+psciTypeOf = TypeOf <$> (char 't' *> P.whiteSpace *> P.parseValue)
psgo.cabaldeleted−145
@@ -1,145 +0,0 @@
1−cabal-version: 1.12
2−
3−-- This file has been generated from package.yaml by hpack version 0.35.0.
4−--
5−-- see: https://github.com/sol/hpack
6−
7−name: psgo
8−version: 0.1.0.0
9−description: Please see the README on Github at <https://github.com/andyarvanitis/purescript-native#readme>
10−homepage: https://github.com/andyarvanitis/purescript-native#readme
11−bug-reports: https://github.com/andyarvanitis/purescript-native/issues
12−author: Andy Arvanitis
13−maintainer: example@example.com
14−copyright: 2018 Andy Arvanitis
15−license: BSD3
16−license-file: LICENSE
17−build-type: Simple
18−extra-source-files:
19− README.md
20− ChangeLog.md
21− stack.yaml
22− support/ffi-loader.go
23− support/go.mod.ffi-loader
24− support/go.mod.output
25− support/go.mod.working
26−
27−source-repository head
28− type: git
29− location: https://github.com/andyarvanitis/purescript-native
30−
31−library
32− exposed-modules:
33− CodeGen.IL
34− CodeGen.IL.Common
35− CodeGen.IL.Optimizer
36− CodeGen.IL.Optimizer.Common
37− CodeGen.IL.Optimizer.Inliner
38− CodeGen.IL.Optimizer.MagicDo
39− CodeGen.IL.Optimizer.TCO
40− CodeGen.IL.Printer
41− Tests
42− other-modules:
43− Paths_psgo
44− hs-source-dirs:
45− src
46− default-extensions:
47− ConstraintKinds
48− DataKinds
49− DeriveFunctor
50− EmptyDataDecls
51− FlexibleContexts
52− KindSignatures
53− LambdaCase
54− MultiParamTypeClasses
55− NoImplicitPrelude
56− PatternGuards
57− PatternSynonyms
58− RankNTypes
59− RecordWildCards
60− OverloadedStrings
61− ScopedTypeVariables
62− TupleSections
63− ViewPatterns
64− build-depends:
65− aeson >=1.0 && <1.5
66− , base >=4.7 && <5
67− , base-compat >=0.6.0
68− , bytestring >=0.10.8.2 && <0.11
69− , containers
70− , directory
71− , file-embed
72− , filemanip
73− , filepath
74− , gitrev
75− , monad-parallel >=0.7.2.2 && <0.8
76− , mtl >=2.1.0 && <2.3.0
77− , pattern-arrows >=0.0.2 && <0.1
78− , process
79− , protolude >=0.1.6
80− , purescript
81− , safe >=0.3.9 && <0.4
82− , text
83− , transformers >=0.3.0 && <0.6
84− default-language: Haskell2010
85−
86−executable psgo
87− main-is: Main.hs
88− other-modules:
89− Paths_psgo
90− hs-source-dirs:
91− app
92− ghc-options: -threaded -rtsopts -with-rtsopts=-N
93− build-depends:
94− aeson >=1.0 && <1.5
95− , base >=4.7 && <5
96− , base-compat >=0.6.0
97− , bytestring >=0.10.8.2 && <0.11
98− , containers
99− , directory
100− , file-embed
101− , filemanip
102− , filepath
103− , gitrev
104− , monad-parallel >=0.7.2.2 && <0.8
105− , mtl >=2.1.0 && <2.3.0
106− , pattern-arrows >=0.0.2 && <0.1
107− , process
108− , protolude >=0.1.6
109− , psgo
110− , purescript
111− , safe >=0.3.9 && <0.4
112− , text
113− , transformers >=0.3.0 && <0.6
114− default-language: Haskell2010
115−
116−test-suite psgo-test
117− type: exitcode-stdio-1.0
118− main-is: Spec.hs
119− other-modules:
120− Paths_psgo
121− hs-source-dirs:
122− test
123− ghc-options: -threaded -rtsopts -with-rtsopts=-N
124− build-depends:
125− aeson >=1.0 && <1.5
126− , base >=4.7 && <5
127− , base-compat >=0.6.0
128− , bytestring >=0.10.8.2 && <0.11
129− , containers
130− , directory
131− , file-embed
132− , filemanip
133− , filepath
134− , gitrev
135− , monad-parallel >=0.7.2.2 && <0.8
136− , mtl >=2.1.0 && <2.3.0
137− , pattern-arrows >=0.0.2 && <0.1
138− , process
139− , protolude >=0.1.6
140− , psgo
141− , purescript
142− , safe >=0.3.9 && <0.4
143− , text
144− , transformers >=0.3.0 && <0.6
145− default-language: Haskell2010
purescript.cabalnew file+115
@@ -0,0 +1,115 @@
1+name: purescript
2+version: 0.4.2.1
3+cabal-version: >=1.8
4+build-type: Custom
5+license: MIT
6+license-file: LICENSE
7+copyright: (c) 2013-14 Phil Freeman, (c) 2014 Gary Burgess, and other contributors
8+maintainer: Phil Freeman <paf31@cantab.net>
9+stability: experimental
10+synopsis: PureScript Programming Language Compiler
11+description: A small compile-to-JS language with extensible records and type-safe blocks
12+category: Language
13+Homepage: http://www.purescript.org/
14+author: Phil Freeman <paf31@cantab.net>,
15+ Gary Burgess <gary.burgess@gmail.com>,
16+ Hardy Jones <jones3.hardy@gmail.com>
17+data-files: prelude/prelude.purs
18+data-dir: ""
19+
20+library
21+ build-depends: base >=4 && <5, cmdtheline -any, containers -any,
22+ directory -any, filepath -any, mtl -any, parsec -any, syb -any,
23+ transformers -any, utf8-string -any, pattern-arrows -any, monad-unify >= 0.2 && < 0.3,
24+ xdg-basedir -any
25+ if (!os(windows))
26+ build-depends: unix -any
27+ exposed-modules: Data.Generics.Extras
28+ Language.PureScript
29+ Language.PureScript.Options
30+ Language.PureScript.Declarations
31+ Language.PureScript.Kinds
32+ Language.PureScript.Names
33+ Language.PureScript.Types
34+ Language.PureScript.Values
35+ Language.PureScript.Scope
36+ Language.PureScript.DeadCodeElimination
37+ Language.PureScript.Sugar
38+ Language.PureScript.ModuleDependencies
39+ Language.PureScript.Sugar.CaseDeclarations
40+ Language.PureScript.Sugar.DoNotation
41+ Language.PureScript.Sugar.TypeDeclarations
42+ Language.PureScript.Sugar.BindingGroups
43+ Language.PureScript.Sugar.Operators
44+ Language.PureScript.Sugar.TypeClasses
45+ Language.PureScript.Sugar.Let
46+ Language.PureScript.Sugar.Names
47+ Language.PureScript.CodeGen
48+ Language.PureScript.CodeGen.Common
49+ Language.PureScript.CodeGen.Externs
50+ Language.PureScript.CodeGen.JS
51+ Language.PureScript.CodeGen.JS.AST
52+ Language.PureScript.CodeGen.Monad
53+ Language.PureScript.CodeGen.Optimize
54+ Language.PureScript.Parser
55+ Language.PureScript.Parser.Common
56+ Language.PureScript.Parser.Declarations
57+ Language.PureScript.Parser.Kinds
58+ Language.PureScript.Parser.State
59+ Language.PureScript.Parser.Types
60+ Language.PureScript.Parser.Values
61+ Language.PureScript.Pretty
62+ Language.PureScript.Pretty.Common
63+ Language.PureScript.Pretty.JS
64+ Language.PureScript.Pretty.Kinds
65+ Language.PureScript.Pretty.Types
66+ Language.PureScript.Pretty.Values
67+ Language.PureScript.TypeChecker
68+ Language.PureScript.TypeChecker.Kinds
69+ Language.PureScript.TypeChecker.Monad
70+ Language.PureScript.TypeChecker.Synonyms
71+ Language.PureScript.TypeChecker.Types
72+ exposed: True
73+ buildable: True
74+ hs-source-dirs: src
75+ other-modules:
76+
77+executable psc
78+ build-depends: base >=4 && <5, cmdtheline -any, containers -any,
79+ directory -any, filepath -any, mtl -any, parsec -any,
80+ purescript -any, syb -any, transformers -any, utf8-string -any
81+ main-is: Main.hs
82+ buildable: True
83+ hs-source-dirs: psc
84+ other-modules:
85+ ghc-options: -Wall -O2 -fno-warn-unused-do-bind
86+
87+executable psci
88+ build-depends: base >=4 && <5, containers -any, directory -any, filepath -any,
89+ mtl -any, parsec -any, haskeline <=0.7.1.1, purescript -any,
90+ syb -any, transformers -any, utf8-string -any, process -any,
91+ xdg-basedir -any, cmdtheline -any
92+ main-is: Main.hs
93+ buildable: True
94+ hs-source-dirs: psci
95+ other-modules: Commands
96+ Parser
97+ ghc-options: -Wall -O2
98+
99+executable docgen
100+ build-depends: base >=4 && <5, cmdtheline -any, purescript -any, utf8-string -any,
101+ process -any, mtl -any
102+ main-is: Main.hs
103+ buildable: True
104+ hs-source-dirs: docgen
105+ other-modules:
106+ ghc-options: -Wall -O2
107+
108+test-suite tests
109+ build-depends: base >=4 && <5, containers -any, directory -any,
110+ filepath -any, mtl -any, parsec -any, purescript -any, syb -any,
111+ transformers -any, utf8-string -any, process -any
112+ type: exitcode-stdio-1.0
113+ main-is: Main.hs
114+ buildable: True
115+ hs-source-dirs: tests
src/CodeGen/IL.hsdeleted−321
@@ -1,321 +0,0 @@
1−-- | This module generates code in the core imperative representation from
2−-- elaborated PureScript code.
3−module CodeGen.IL
4− ( module AST
5− , module Common
6− , moduleToIL
7− ) where
8−
9−import Prelude.Compat
10−import Protolude (ordNub)
11−
12−import Control.Arrow ((&&&))
13−import Control.Monad (forM, liftM, replicateM, void)
14−import Control.Monad.Supply.Class
15−
16−import Data.List ((\\), delete, intersect, nub)
17−import qualified Data.Foldable as F
18−import qualified Data.Map as M
19−import Data.Maybe (fromMaybe, isNothing, mapMaybe)
20−import Data.Monoid ((<>))
21−import Data.String (fromString)
22−import Data.Text (Text)
23−import qualified Data.Text as T
24−
25−import Language.PureScript.AST.SourcePos
26−import Language.PureScript.CoreImp.AST (AST)
27−import qualified Language.PureScript.CoreImp.AST as AST
28−import Language.PureScript.CoreFn
29−import Language.PureScript.Crash
30−import Language.PureScript.Names
31−import Language.PureScript.Options
32−import Language.PureScript.PSString (PSString, mkString)
33−import Language.PureScript.Traversals (sndM)
34−import qualified Language.PureScript.Constants as C
35−
36−import System.FilePath.Posix ((</>))
37−
38−import CodeGen.IL.Common as Common
39−import CodeGen.IL.Optimizer
40−import CodeGen.IL.Printer
41−
42−data DeclType = ModuleDecl | LetDecl | RecLetDecl deriving (Eq)
43−
44−-- | Generate code in the simplified intermediate representation for all declarations in a
45−-- module.
46−moduleToIL
47− :: forall m
48− -- . (Monad m, MonadReader Options m, MonadSupply m, MonadError MultipleErrors m)
49− . (Monad m, MonadSupply m)
50− => Module Ann
51− -> Text
52− -> m (Text, [Text], [AST], Text, Text)
53−moduleToIL (Module _ coms mn _ imps _ foreigns decls) project =
54− do
55− ilDecls <- mapM (bindToIL ModuleDecl) decls
56− optimized <- traverse (traverse (optimize modName')) ilDecls
57− let optimized' = concat optimized
58− values = annotValue <$> optimized'
59− foreigns' = moduleIdentToIL <$> foreigns
60− interface = interfaceSource modName values foreigns
61− imports = nub . concat $ importToIL <$> optimized'
62− implHeader = implHeaderSource modName imports project
63− implFooter = implFooterSource (runModuleName mn) foreigns
64− return $ (interface, foreigns', optimized', implHeader, implFooter)
65− where
66− modName = moduleNameToIL mn
67− modName' = AST.Var Nothing modName
68−
69− annotValue :: AST -> (Text, Bool)
70− annotValue (AST.Function _ (Just name) [] (AST.Block _ [AST.Return _ ret]))
71− | isLiteral ret = (name, True)
72− annotValue (AST.Function _ (Just name) [] _) = (name, False)
73− annotValue _ = error "Unexpected top-level value form"
74−
75− -- | Extracts all declaration names from a binding group.
76− getNames :: Bind Ann -> [Ident]
77− getNames (NonRec _ ident _) = [ident]
78− getNames (Rec vals) = map (snd . fst) vals
79−
80− -- | Generates IL code for a module import
81− --
82− importToIL :: AST -> [Text]
83− importToIL = AST.everything (++) modRef
84− where
85− modRef (AST.Indexer _ (AST.Var _ _) (AST.Var _ mname))
86− | not $ T.null mname = [extract mname]
87− modRef _ = []
88− extract :: Text -> Text
89− extract = T.replace "_" "." . T.dropWhileEnd (=='_')
90−
91− -- |
92− -- Generate code in the simplified intermediate representation for a declaration
93− --
94− bindToIL :: DeclType -> Bind Ann -> m [AST]
95− bindToIL dt (NonRec ann ident val) = return <$> nonRecToIL dt ann ident val
96− bindToIL dt (Rec vals) = forM vals (uncurry . uncurry $ nonRecToIL dt')
97− where
98− dt' = if dt == LetDecl then RecLetDecl else dt
99−
100− -- | Generate code in the simplified intermediate representation for a single non-recursive
101− -- declaration.
102− --
103− -- The main purpose of this function is to handle code generation for comments.
104− nonRecToIL :: DeclType -> Ann -> Ident -> Expr Ann -> m AST
105− nonRecToIL dt a i e@(extractAnn -> (_, com, _, _)) | not (null com) = do
106− -- withoutComment <- asks optionsNoComments
107− let withoutComment = False
108− if withoutComment
109− then nonRecToIL dt a i (modifyAnn removeComments e)
110− else AST.Comment Nothing com <$> nonRecToIL dt a i (modifyAnn removeComments e)
111− nonRecToIL ModuleDecl (ss, _, _, _) ident val = do
112− il <- valueToIL val
113− pure $ AST.Function Nothing (Just $ moduleIdentToIL ident) [] (AST.Block Nothing [AST.Return Nothing il])
114− nonRecToIL RecLetDecl (ss, _, _, _) ident val = do
115− ilExpr <- valueToIL val
116− pure $ AST.Assignment Nothing (AST.Var Nothing $ identToIL ident) ilExpr
117− nonRecToIL _ (ss, _, _, _) ident val = do
118− il <- valueToIL val
119− pure $ AST.VariableIntroduction Nothing (identToIL ident) (Just il)
120−
121− -- | Generate code in the simplified intermediate representation for a variable based on a
122− -- PureScript identifier.
123− var :: Ident -> AST
124− var = AST.Var Nothing . identToIL
125−
126− accessorString :: PSString -> AST -> AST
127− accessorString prop = AST.Indexer Nothing (AST.StringLiteral Nothing prop)
128−
129− -- | Generate code in the simplified intermediate representation for a value or expression.
130−
131− valueToIL :: Expr Ann -> m AST
132− valueToIL (Literal (pos, _, _, _) l) = literalToValueIL pos l
133− valueToIL (Accessor _ prop val) =
134− accessorString prop <$> valueToIL val
135− valueToIL (ObjectUpdate _ o ps) = do
136− obj <- valueToIL o
137− updates <- mapM (sndM valueToIL) ps
138− obj' <- freshName'
139− let objVar = AST.Var Nothing obj'
140− copy = AST.VariableIntroduction Nothing obj' (Just $ copyDict obj)
141− assign (k, v) = AST.Assignment Nothing (accessorString k objVar) v
142− sts = copy : (assign <$> updates) ++ [AST.Return Nothing objVar]
143− return $ AST.App Nothing (AST.Function Nothing Nothing [] (AST.Block Nothing sts)) []
144− valueToIL (Abs _ arg val) = do
145− ret <- valueToIL val
146− let ilArg = case arg of
147− UnusedIdent -> []
148− _ -> [identToIL arg]
149− return $ AST.Function Nothing Nothing ilArg (AST.Block Nothing [AST.Return Nothing ret])
150− valueToIL e@App{} = do
151− let (f, args) = unApp e []
152− args' <- mapM valueToIL args
153− fn <- valueToIL f
154− case f of
155− Var (_, _, _, Just IsNewtype) _ -> return (head args')
156− _ -> flip (foldl (\fn a -> AST.App Nothing fn [a])) args' <$> valueToIL f
157− where
158− unApp :: Expr Ann -> [Expr Ann] -> (Expr Ann, [Expr Ann])
159− unApp (App _ val arg) args = unApp val (arg : args)
160− unApp other args = (other, args)
161− valueToIL (Var _ ident) = return $ varToIL ident
162− valueToIL (Case (ss, _, _, _) values binders) = do
163− vals <- mapM valueToIL values
164− bindersToIL ss binders vals
165− valueToIL (Let _ ds val) = do
166− let recurs = concatMap getNames $ filter isRec ds
167− recurDs = (\v -> AST.VariableIntroduction Nothing (identToIL v) Nothing) <$> recurs
168− ds' <- concat <$> mapM (bindToIL LetDecl) ds
169− ret <- valueToIL val
170− return $ AST.App Nothing (AST.Function Nothing Nothing [] (AST.Block Nothing (recurDs ++ ds' ++ [AST.Return Nothing ret]))) []
171− where
172− isRec :: Bind Ann -> Bool
173− isRec (Rec _) = True
174− isRec _ = False
175− valueToIL (Constructor (_, _, _, Just IsNewtype) _ (ProperName ctor) _) = error "IsNewtype"
176− valueToIL (Constructor _ _ (ProperName ctor) fields) =
177− let body = AST.ObjectLiteral Nothing $ (mkString ctor, AST.BooleanLiteral Nothing True) :
178− ((\field -> (mkString (identToIL field), var field)) `map` fields)
179− fn = foldr (\f inner -> AST.Function Nothing Nothing [identToIL f] (AST.Block Nothing [AST.Return Nothing inner])) body fields
180− in return fn
181−
182−
183− iife :: Text -> [AST] -> AST
184− iife v exprs = AST.App Nothing (AST.Function Nothing Nothing [] (AST.Block Nothing $ exprs ++ [AST.Return Nothing $ AST.Var Nothing v])) []
185−
186− literalToValueIL :: SourceSpan -> Literal (Expr Ann) -> m AST
187− literalToValueIL ss (NumericLiteral (Left i)) = return $ AST.NumericLiteral (Just ss) (Left i)
188− literalToValueIL ss (NumericLiteral (Right n)) = return $ AST.NumericLiteral (Just ss) (Right n)
189− literalToValueIL ss (StringLiteral s) = return $ AST.StringLiteral (Just ss) s
190− literalToValueIL ss (CharLiteral c) = return $ AST.StringLiteral (Just ss) (fromString [c])
191− literalToValueIL ss (BooleanLiteral b) = return $ AST.BooleanLiteral (Just ss) b
192− literalToValueIL ss (ArrayLiteral xs) = AST.ArrayLiteral (Just ss) <$> mapM valueToIL xs
193− literalToValueIL ss (ObjectLiteral ps) = AST.ObjectLiteral (Just ss) <$> mapM (sndM valueToIL) ps
194−
195− -- | Generate code in the simplified intermediate representation for a reference to a
196− -- variable.
197− varToIL :: Qualified Ident -> AST
198− varToIL (Qualified Nothing ident) = var ident
199− varToIL qual = qualifiedToIL id qual
200−
201− -- | Generate code in the simplified intermediate representation for a reference to a
202− -- variable that may have a qualified name.
203− qualifiedToIL :: (a -> Ident) -> Qualified a -> AST
204− qualifiedToIL f (Qualified (Just (ModuleName mn')) a) | mn' == C.prim = AST.Var Nothing . moduleIdentToIL $ f a
205− qualifiedToIL f (Qualified (Just mn') a) | mn /= mn' = AST.Indexer Nothing (AST.Var Nothing . moduleIdentToIL $ f a) (AST.Var Nothing (moduleNameToIL mn'))
206− qualifiedToIL f (Qualified _ a) = AST.Indexer Nothing (AST.Var Nothing . moduleIdentToIL $ f a) (AST.Var Nothing "")
207−
208− -- foreignIdent :: Ident -> AST
209− -- foreignIdent ident = accessorString (mkString $ runIdent ident) (AST.Var Nothing "$foreign")
210−
211− -- | Generate code in the simplified intermediate representation for pattern match binders
212− -- and guards.
213− bindersToIL :: SourceSpan -> [CaseAlternative Ann] -> [AST] -> m AST
214− bindersToIL ss binders vals = do
215− valNames <- replicateM (length vals) freshName'
216− let assignments = zipWith (AST.VariableIntroduction Nothing) valNames (map Just vals)
217− ils <- forM binders $ \(CaseAlternative bs result) -> do
218− ret <- guardsToIL result
219− go valNames ret bs
220− return $ AST.App Nothing (AST.Function Nothing Nothing [] (AST.Block Nothing (assignments ++ concat ils ++ [AST.Throw Nothing (AST.StringLiteral Nothing $ mkString failedPatternMessage)])))
221− []
222− where
223− go :: [Text] -> [AST] -> [Binder Ann] -> m [AST]
224− go _ done [] = return done
225− go (v:vs) done' (b:bs) = do
226− done'' <- go vs done' bs
227− binderToIL v done'' b
228− go _ _ _ = internalError "Invalid arguments to bindersToIL"
229−
230− failedPatternMessage :: Text
231− failedPatternMessage = "Failed pattern match at " <> runModuleName mn <> " " <> displayStartEndPos ss
232−
233− guardsToIL :: Either [(Guard Ann, Expr Ann)] (Expr Ann) -> m [AST]
234− guardsToIL (Left gs) = traverse genGuard gs where
235− genGuard (cond, val) = do
236− cond' <- valueToIL cond
237− val' <- valueToIL val
238− return
239− (AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo cond' (AST.BooleanLiteral Nothing True))
240− (AST.Block Nothing [AST.Return Nothing val']) Nothing)
241−
242− guardsToIL (Right v) = return . AST.Return Nothing <$> valueToIL v
243−
244− -- | Generate code in the simplified intermediate representation for a pattern match
245− -- binder.
246− binderToIL :: Text -> [AST] -> Binder Ann -> m [AST]
247− binderToIL _ done NullBinder{} = return done
248− binderToIL varName done (LiteralBinder _ l) =
249− literalToBinderIL varName done l
250− binderToIL varName done (VarBinder _ ident) =
251− return (AST.VariableIntroduction Nothing (identToIL ident) (Just (AST.Var Nothing varName)) : done)
252− binderToIL varName done (ConstructorBinder (_, _, _, Just IsNewtype) _ _ [b]) =
253− binderToIL varName done b
254− binderToIL varName done (ConstructorBinder (_, _, _, Just (IsConstructor ctorType fields)) _ (Qualified _ (ProperName ctor)) bs) = do
255− il <- go (zip fields bs) done
256− return $ case ctorType of
257− ProductType -> il
258− SumType ->
259− [AST.IfElse Nothing (AST.InstanceOf Nothing (AST.Var Nothing varName) (AST.StringLiteral Nothing (mkString ctor)))
260− (AST.Block Nothing il)
261− Nothing]
262− where
263− go :: [(Ident, Binder Ann)] -> [AST] -> m [AST]
264− go [] done' = return done'
265− go ((field, binder) : remain) done' = do
266− argVar <- freshName'
267− done'' <- go remain done'
268− il <- binderToIL argVar done'' binder
269− return (AST.VariableIntroduction Nothing argVar (Just $ accessorString (mkString $ identToIL field) $ AST.Var Nothing varName) : il)
270−
271− binderToIL _ _ ConstructorBinder{} =
272− internalError "binderToIL: Invalid ConstructorBinder in binderToIL"
273− binderToIL varName done (NamedBinder _ ident binder) = do
274− il <- binderToIL varName done binder
275− return (AST.VariableIntroduction Nothing (identToIL ident) (Just (AST.Var Nothing varName)) : il)
276−
277− literalToBinderIL :: Text -> [AST] -> Literal (Binder Ann) -> m [AST]
278− literalToBinderIL varName done (NumericLiteral num) =
279− return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.NumericLiteral Nothing num)) (AST.Block Nothing done) Nothing]
280− literalToBinderIL varName done (CharLiteral c) =
281− return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.StringLiteral Nothing (fromString [c]))) (AST.Block Nothing done) Nothing]
282− literalToBinderIL varName done (StringLiteral str) =
283− return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.StringLiteral Nothing str)) (AST.Block Nothing done) Nothing]
284− literalToBinderIL varName done (BooleanLiteral True) =
285− return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.BooleanLiteral Nothing True)) (AST.Block Nothing done) Nothing]
286− literalToBinderIL varName done (BooleanLiteral False) =
287− return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.BooleanLiteral Nothing False)) (AST.Block Nothing done) Nothing]
288− -- return [AST.IfElse Nothing (AST.Unary Nothing AST.Not (AST.Var Nothing varName)) (AST.Block Nothing done) Nothing]
289− literalToBinderIL varName done (ObjectLiteral bs) = go done bs
290− where
291− go :: [AST] -> [(PSString, Binder Ann)] -> m [AST]
292− go done' [] = return done'
293− go done' ((prop, binder):bs') = do
294− propVar <- freshName'
295− done'' <- go done' bs'
296− il <- binderToIL propVar done'' binder
297− return (AST.VariableIntroduction Nothing propVar (Just (accessorString prop (AST.Var Nothing varName))) : il)
298− literalToBinderIL varName done (ArrayLiteral bs) = do
299− il <- go done 0 bs
300− return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo
301− (arrayLength $ AST.Var Nothing varName)
302− (AST.NumericLiteral Nothing (Left (fromIntegral $ length bs))))
303− (AST.Block Nothing il) Nothing]
304− where
305− go :: [AST] -> Integer -> [Binder Ann] -> m [AST]
306− go done' _ [] = return done'
307− go done' index (binder:bs') = do
308− elVar <- freshName'
309− done'' <- go done' (index + 1) bs'
310− il <- binderToIL elVar done'' binder
311− return (AST.VariableIntroduction Nothing elVar (Just (AST.Indexer Nothing (AST.NumericLiteral Nothing (Left index)) (AST.Var Nothing varName))) : il)
312−
313−emptyAnn :: Ann
314−emptyAnn = (SourceSpan "" (SourcePos 0 0) (SourcePos 0 0), [], Nothing, Nothing)
315−
316−arrayLength :: AST -> AST
317−arrayLength a = AST.App Nothing (AST.Var Nothing arrayLengthFn) [a]
318−-- arrayLength a = AST.Var Nothing (arrayLengthFn <> "(" <> prettyPrintIL1 a <> ")")
319−
320−copyDict :: AST -> AST
321−copyDict a = AST.App Nothing (AST.Var Nothing copyDictFn) [a]
src/CodeGen/IL/Common.hsdeleted−196
@@ -1,196 +0,0 @@
1−-- | Common code generation utility functions
2−module CodeGen.IL.Common where
3−
4−import Prelude.Compat
5−
6−import Control.Monad.Supply.Class (MonadSupply, freshName)
7−import Data.Char
8−import Data.Maybe (maybe)
9−import Data.Monoid ((<>))
10−import Data.Text (Text)
11−import qualified Data.Text as T
12−
13−import Language.PureScript.Crash
14−import Language.PureScript.Names
15−
16−import qualified Language.PureScript.Constants as C
17−
18−moduleNameToIL :: ModuleName -> Text
19−moduleNameToIL (ModuleName mn) =
20− let name = T.replace "." "_" mn
21− in if nameIsILBuiltIn name then (name <> moduleRenamerMarker) else name
22−
23−moduleNameToIL' :: ModuleName -> Text
24−moduleNameToIL' (ModuleName mn) = T.replace "_" "." mn
25−
26−-- | Convert an 'Ident' into a valid IL identifier:
27−--
28−-- * Alphanumeric characters are kept unmodified.
29−--
30−-- * Reserved IL identifiers are wrapped with '_'.
31−--
32−identToIL :: Ident -> Text
33−identToIL UnusedIdent = unusedName
34−identToIL (Ident "$__unused") = unusedName
35−identToIL (Ident name) | name == C.undefined = undefinedName -- Note: done in Printer.hs too
36−identToIL (Ident name) = properToIL name
37−identToIL (GenIdent _ _) = internalError "GenIdent in identToIL"
38−
39−moduleIdentToIL :: Ident -> Text
40−moduleIdentToIL UnusedIdent = unusedName
41−moduleIdentToIL (Ident name) | name == C.undefined = undefinedName
42−moduleIdentToIL (Ident name) = moduleProperToIL name
43−moduleIdentToIL (GenIdent _ _) = internalError "GenIdent in identToIL"
44−
45−undefinedName :: Text
46−undefinedName = "Undefined"
47−
48−unusedName :: Text
49−unusedName = "_"
50−
51−properToIL :: Text -> Text
52−properToIL name
53− | nameIsILReserved name = "ˉ" <> name
54− | otherwise = T.concatMap identCharToText name
55−
56−-- | Attempts to find a human-readable name for a symbol, if none has been specified returns the
57−-- ordinal value.
58−identCharToText :: Char -> Text
59−identCharToText 'ṩ' = "_ṩ"
60−identCharToText c | isAlphaNum c = T.singleton c
61−identCharToText '_' = "_"
62−identCharToText '\'' = "ꞌ" -- lowercase saltillo
63−identCharToText c = error (show (ord c)) -- TODO: should never occur now(?)
64−
65−moduleProperToIL :: Text -> Text
66−moduleProperToIL = T.concatMap identCharToText
67−
68−-- | Checks whether an identifier name is reserved in IL.
69−nameIsILReserved :: Text -> Bool
70−nameIsILReserved name =
71− name `elem` ilAnyReserved
72−
73−-- | Checks whether a name matches a built-in value in IL.
74−nameIsILBuiltIn :: Text -> Bool
75−nameIsILBuiltIn name =
76− name `elem`
77− [ "Any"
78− , "Apply"
79− , "Contains"
80− , "CopyDict"
81− , "Dict"
82− , "EffFn"
83− , "Fn"
84− , "Foreign"
85− , "Get"
86− , "Index"
87− , "Is"
88− , "Length"
89− , "Once"
90− , "Run"
91− , "Undefined"
92− ]
93−
94−ilAnyReserved :: [Text]
95−ilAnyReserved =
96− concat
97− [ ilKeywords
98− , ilLiterals
99− ]
100−
101−ilKeywords :: [Text]
102−ilKeywords =
103− [ "break"
104− , "case"
105− , "chan"
106− , "const"
107− , "continue"
108− , "default"
109− , "defer"
110− , "else"
111− , "fallthrough"
112− , "for"
113− , "func"
114− , "go"
115− , "goto"
116− , "if"
117− , "import"
118− , "interface"
119− , "map"
120− , "package"
121− , "range"
122− , "return"
123− , "select"
124− , "struct"
125− , "switch"
126− , "type"
127− , "var"
128− ]
129−
130−ilLiterals :: [Text]
131−ilLiterals =
132− [ "init"
133− , "nil"
134− , "int"
135− , "int8"
136− , "int16"
137− , "int32"
138− , "int64"
139− , "uint"
140− , "uint8"
141− , "uint16"
142− , "uint32"
143− , "uint64"
144− , "uintptr"
145− , "float32"
146− , "float64"
147− , "complex64"
148− , "complex128"
149− , "byte"
150− , "rune"
151− , "string"
152− ]
153−
154−withPrefix :: Text -> Text
155−withPrefix s = "Ꞌ" <> s -- uppercase saltillo
156−
157−anyType :: Text
158−anyType = "Any"
159−
160−dictType :: Text
161−dictType = "Dict"
162−
163−arrayType :: Text
164−arrayType = "[]" <> anyType
165−
166−uncurriedFnType :: Int -> Text
167−uncurriedFnType i = "Fn" <> (T.pack . show $ i)
168−
169−int :: Text
170−int = "int"
171−
172−float :: Text
173−float = "float64"
174−
175−bool :: Text
176−bool = "bool"
177−
178−string :: Text
179−string = "string"
180−
181−arrayLengthFn :: Text
182−arrayLengthFn = "Length"
183−
184−indexFn :: Text
185−indexFn = "Index"
186−
187−copyDictFn :: Text
188−copyDictFn = "CopyDict"
189−
190−freshName' :: MonadSupply m => m Text
191−freshName' = do
192− name <- freshName
193− return $ T.replace "$" "ṩ" name
194−
195−moduleRenamerMarker :: Text
196−moduleRenamerMarker = "__"
src/CodeGen/IL/Optimizer.hsdeleted−81
@@ -1,81 +0,0 @@
1−-- | This module optimizes code in the intermediate representation.
2−module CodeGen.IL.Optimizer (optimize) where
3−
4−import Prelude.Compat
5−
6−import Control.Monad.Supply.Class (MonadSupply)
7−import Data.Text (Text)
8−import Language.PureScript.CoreImp.AST
9−import Language.PureScript.CoreImp.Optimizer.Blocks
10−import Language.PureScript.CoreImp.Optimizer.Common hiding (isDict)
11−import Language.PureScript.CoreImp.Optimizer.Inliner (etaConvert, evaluateIifes, inlineVariables, unThunk)
12−import Language.PureScript.CoreImp.Optimizer.Unused
13−
14−import CodeGen.IL.Common (unusedName)
15−import CodeGen.IL.Optimizer.Inliner
16−import CodeGen.IL.Optimizer.MagicDo
17−import CodeGen.IL.Optimizer.TCO
18−
19−import qualified Language.PureScript.Constants as C
20−
21−-- | Apply a series of optimizer passes to simplified IL code
22−optimize :: MonadSupply m => AST -> AST -> m AST
23−optimize mn il = do
24− il' <- untilFixedPoint (inlineFnComposition . inlineUnsafeCoerce . inlineUnsafePartial . tidyUp) il
25− il'' <- untilFixedPoint (return . ignoreUnusedResults . inlineCommonValues . inlineCommonOperators . tidyUp) . tco mn . inlineST
26− =<< untilFixedPoint (return . magicDoST)
27− =<< untilFixedPoint (return . magicDoEff)
28− =<< untilFixedPoint (return . magicDoEffect) il'
29− untilFixedPoint (return . collapseVarDeclarations) il''
30− where
31− tidyUp :: AST -> AST
32− tidyUp = applyAll
33− [ collapseNestedBlocks
34− , collapseNestedIfs
35− , collapseIfChecks
36− , removeCodeAfterReturnStatements
37− , unThunk
38− , etaConvert
39− , evaluateIifes
40− , inlineVariables
41− ]
42−
43−untilFixedPoint :: (Monad m, Eq a) => (a -> m a) -> a -> m a
44−untilFixedPoint f = go
45− where
46− go a = do
47− a' <- f a
48− if a' == a then return a' else go a'
49−
50−collapseIfChecks :: AST -> AST
51−collapseIfChecks = everywhere collapse where
52− collapse :: AST -> AST
53− collapse (IfElse _ (Binary _ EqualTo (BooleanLiteral _ True) (BooleanLiteral _ True)) (Block _ [exprs]) _) = exprs
54− collapse (IfElse _ (Binary _ EqualTo (Indexer _ (Var _ prop) (Var _ val)) (BooleanLiteral _ True)) (Block _ [exprs]) _)
55− | prop == "otherwise" && val == "Data_Boolean" = exprs
56− collapse exprs = exprs
57−
58−collapseVarDeclarations :: AST -> AST
59−collapseVarDeclarations = everywhere collapse where
60− collapse :: AST -> AST
61− collapse (Block ss sts) = Block ss (go Nothing sts)
62− collapse s = s
63−
64− go :: Maybe Text -> [AST] -> [AST]
65− go _ [] = []
66− go Nothing (decl@(VariableIntroduction _ var (Just _)) : sts) = decl : go (Just var) (go Nothing sts)
67− go (Just var') ((VariableIntroduction ss var (Just val)) : sts)
68− | var == var' = (Assignment ss (Var Nothing var) val) : go (Just var') sts
69− go var' (s:sts) = s : go var' sts
70−
71−ignoreUnusedResults :: AST -> AST
72−ignoreUnusedResults = everywhere $ removeFromBlock go
73− where
74− go :: [AST] -> [AST]
75− go [] = []
76− go (VariableIntroduction ss var (Just s) : sts)
77− | not $ any (everything (||) (isUsed var)) sts = sts'
78− where
79− sts' | App{} <- s = s : (go sts)
80− | otherwise = go sts
81− go (s:sts) = s : go sts
src/CodeGen/IL/Optimizer/Common.hsdeleted−18
@@ -1,18 +0,0 @@
1−-- | Common functions used by the various optimizer phases
2−module CodeGen.IL.Optimizer.Common where
3−
4−import Prelude.Compat
5−
6−import Data.Text (Text)
7−
8−import Language.PureScript.CoreImp.AST
9−import Language.PureScript.PSString (PSString, decodeString)
10−
11−isDict :: (Text, PSString) -> AST -> Bool
12−isDict (moduleName, dictName) (Indexer _ (Var _ x) (Var _ y)) =
13− Just x == decodeString dictName && y == moduleName
14−isDict _ _ = False
15−
16−isDict' :: [(Text, PSString)] -> AST -> Bool
17−isDict' xs il = any (`isDict` il) xs
18−
src/CodeGen/IL/Optimizer/Inliner.hsdeleted−435
@@ -1,435 +0,0 @@
1−-- | This module performs basic inlining of known functions
2−module CodeGen.IL.Optimizer.Inliner
3− ( inlineCommonValues
4− , inlineCommonOperators
5− , inlineFnComposition
6− , inlineUnsafeCoerce
7− , inlineUnsafePartial
8− ) where
9−
10−import Prelude.Compat
11−
12−import Control.Monad.Supply.Class (MonadSupply)
13−
14−import Data.Either (rights)
15−import Data.Maybe (fromMaybe)
16−import Data.String (IsString, fromString)
17−import Data.Text (Text)
18−import qualified Data.Text as T
19−
20−import Language.PureScript.PSString (PSString, decodeString, mkString)
21−import Language.PureScript.CoreImp.AST
22−import Language.PureScript.CoreImp.Optimizer.Common hiding (isDict, isDict')
23−import Language.PureScript.AST (SourceSpan(..))
24−import qualified Language.PureScript.Constants as C
25−
26−import CodeGen.IL.Common
27−import CodeGen.IL.Optimizer.Common
28−
29−-- TODO: Potential bug:
30−-- Shouldn't just inline this case: { var x = 0; x.toFixed(10); }
31−-- Needs to be: { 0..toFixed(10); }
32−-- Probably needs to be fixed in pretty-printer instead.
33−shouldInline :: AST -> Bool
34−shouldInline (Var _ _) = True
35−shouldInline (NumericLiteral _ _) = True
36−shouldInline (StringLiteral _ _) = True
37−shouldInline (BooleanLiteral _ _) = True
38−shouldInline (Indexer _ index val) = shouldInline index && shouldInline val
39−shouldInline _ = False
40−
41−inlineCommonValues :: AST -> AST
42−inlineCommonValues = everywhere convert
43− where
44− convert :: AST -> AST
45− convert (App ss fn [dict])
46− | isDict' [semiringNumber, semiringInt] dict && isDict fnZero fn = NumericLiteral ss (Left 0)
47− | isDict' [semiringNumber, semiringInt] dict && isDict fnOne fn = NumericLiteral ss (Left 1)
48− | isDict boundedBoolean dict && isDict fnBottom fn = BooleanLiteral ss False
49− | isDict boundedBoolean dict && isDict fnTop fn = BooleanLiteral ss True
50− convert (App ss (App _ fn [dict]) [x])
51− | isDict ringInt dict && isDict fnNegate fn = Unary ss Negate (unbox x $ snd ringInt)
52− convert (App ss (App _ (App _ fn [dict]) [x]) [y])
53− | isDict semiringInt dict && isDict fnAdd fn = intOp ss Add semiringInt x y
54− | isDict semiringInt dict && isDict fnMultiply fn = intOp ss Multiply semiringInt x y
55− | isDict ringInt dict && isDict fnSubtract fn = intOp ss Subtract ringInt x y
56− convert other = other
57− fnZero = (C.dataSemiring, C.zero)
58− fnOne = (C.dataSemiring, C.one)
59− fnBottom = (C.dataBounded, C.bottom)
60− fnTop = (C.dataBounded, C.top)
61− fnAdd = (C.dataSemiring, C.add)
62− fnMultiply = (C.dataSemiring, C.mul)
63− fnSubtract = (C.dataRing, C.sub)
64− fnNegate = (C.dataRing, C.negate)
65− intOp ss op (_, d) x y = Binary ss op (unbox x d) (unbox y d)
66−
67−inlineCommonOperators :: AST -> AST
68−inlineCommonOperators = everywhereTopDown $ applyAll $
69− [ binary semiringNumber opAdd Add
70− , binary semiringNumber opMul Multiply
71−
72− , binary ringNumber opSub Subtract
73− , unary ringNumber opNegate Negate
74−
75− , binary euclideanRingNumber opDiv Divide
76−
77− -- , binary eqNumber opEq EqualTo
78− -- , binary eqNumber opNotEq NotEqualTo
79− , binary eqInt opEq EqualTo
80− , binary eqInt opNotEq NotEqualTo
81− , binary eqString opEq EqualTo
82− , binary eqString opNotEq NotEqualTo
83− , binary eqChar opEq EqualTo
84− , binary eqChar opNotEq NotEqualTo
85− , binary eqBoolean opEq EqualTo
86− , binary eqBoolean opNotEq NotEqualTo
87−
88− , binary ordBoolean opLessThan LessThan
89− , binary ordBoolean opLessThanOrEq LessThanOrEqualTo
90− , binary ordBoolean opGreaterThan GreaterThan
91− , binary ordBoolean opGreaterThanOrEq GreaterThanOrEqualTo
92− , binary ordChar opLessThan LessThan
93− , binary ordChar opLessThanOrEq LessThanOrEqualTo
94− , binary ordChar opGreaterThan GreaterThan
95− , binary ordChar opGreaterThanOrEq GreaterThanOrEqualTo
96− , binary ordInt opLessThan LessThan
97− , binary ordInt opLessThanOrEq LessThanOrEqualTo
98− , binary ordInt opGreaterThan GreaterThan
99− , binary ordInt opGreaterThanOrEq GreaterThanOrEqualTo
100− , binary ordNumber opLessThan LessThan
101− , binary ordNumber opLessThanOrEq LessThanOrEqualTo
102− , binary ordNumber opGreaterThan GreaterThan
103− , binary ordNumber opGreaterThanOrEq GreaterThanOrEqualTo
104− , binary ordString opLessThan LessThan
105− , binary ordString opLessThanOrEq LessThanOrEqualTo
106− , binary ordString opGreaterThan GreaterThan
107− , binary ordString opGreaterThanOrEq GreaterThanOrEqualTo
108−
109− , binary semigroupString opAppend Add
110−
111− , binary heytingAlgebraBoolean opConj And
112− , binary heytingAlgebraBoolean opDisj Or
113− , unary heytingAlgebraBoolean opNot Not
114−
115− , binary' C.dataIntBits C.or BitwiseOr
116− , binary' C.dataIntBits C.and BitwiseAnd
117− , binary' C.dataIntBits C.xor BitwiseXor
118− , binary' C.dataIntBits C.shl ShiftLeft
119− , binary' C.dataIntBits C.shr ShiftRight
120− , unary' C.dataIntBits C.complement BitwiseNot
121−
122− , inlineNonClassFunction (isModFn (C.dataFunction, C.apply)) $ \f x -> App Nothing f [x]
123− , inlineNonClassFunction (isModFn (C.dataFunction, C.applyFlipped)) $ \x f -> App Nothing f [x]
124− , inlineUnsafeIndex (isModFnWithDict (C.dataArray, C.unsafeIndex)) $ flip (Indexer Nothing)
125− ] ++
126− [ fn | i <- [0..10], fn <- [ mkFn i, runFn i ] ] ++
127− [ fn | i <- [0..10], fn <- [ mkEffFn C.controlMonadEffUncurried C.mkEffFn i, runEffFn C.controlMonadEffUncurried C.runEffFn i ] ] ++
128− [ fn | i <- [0..10], fn <- [ mkEffFn C.effectUncurried C.mkEffectFn i, runEffFn C.effectUncurried C.runEffectFn i ] ]
129− where
130− binary :: (Text, PSString) -> (Text, PSString) -> BinaryOperator -> AST -> AST
131− binary dict@(_, d) fns op = convert where
132− convert :: AST -> AST
133− convert (App ss (App _ (App _ fn [dict']) [x]) [y])
134− | isDict dict dict' && isDict fns fn = Binary ss op (unbox x d) (unbox y d)
135− convert other = other
136− binary' :: Text -> PSString -> BinaryOperator -> AST -> AST
137− binary' moduleName opString op = convert where
138− convert :: AST -> AST
139− convert (App ss (App _ fn [x]) [y]) | isDict (moduleName, opString) fn = Binary ss op (unbox x mn) (unbox y mn)
140− convert other = other
141− mn :: PSString
142− mn = mkString moduleName
143− unary :: (Text, PSString) -> (Text, PSString) -> UnaryOperator -> AST -> AST
144− unary dicts@(_, d) fns op = convert where
145− convert :: AST -> AST
146− convert (App ss (App _ fn [dict']) [x]) | isDict dicts dict' && isDict fns fn = Unary ss op (unbox x d)
147− convert other = other
148− unary' :: Text -> PSString -> UnaryOperator -> AST -> AST
149− unary' moduleName fnName op = convert where
150− convert :: AST -> AST
151− convert (App ss fn [x]) | isDict (moduleName, fnName) fn = Unary ss op (unbox x fnName)
152− convert other = other
153−
154− mkFn :: Int -> AST -> AST
155− mkFn = mkFn' C.dataFunctionUncurried C.mkFn $ \ss1 ss2 ss3 args il ->
156− Function ss1 Nothing args (Block ss2 [Return ss3 il])
157−
158− mkEffFn :: Text -> Text -> Int -> AST -> AST
159− mkEffFn modName fnName = mkFn' modName fnName $ \ss1 ss2 ss3 args il ->
160− Function ss1 Nothing args (Block ss2 [Return ss3 (App ss3 il [])])
161−
162− mkFn' :: Text -> Text -> (Maybe SourceSpan -> Maybe SourceSpan -> Maybe SourceSpan -> [Text] -> AST -> AST) -> Int -> AST -> AST
163− mkFn' modName fnName res 0 = convert where
164− convert :: AST -> AST
165− convert (App _ mkFnN [Function s1 Nothing [_] (Block s2 [Return s3 il])]) | isNFn modName fnName 0 mkFnN =
166− res s1 s2 s3 [] il
167− convert other = other
168− mkFn' modName fnName res n = convert where
169− convert :: AST -> AST
170− convert orig@(App ss mkFnN [fn]) | isNFn modName fnName n mkFnN =
171− case collectArgs n [] fn of
172− Just (args, [Return ss' ret]) -> res ss ss ss' args ret
173− _ -> orig
174− convert other = other
175− collectArgs :: Int -> [Text] -> AST -> Maybe ([Text], [AST])
176− collectArgs 1 acc (Function _ Nothing [oneArg] (Block _ il)) | length acc == n - 1 = Just (reverse (oneArg : acc), il)
177− collectArgs m acc (Function _ Nothing [oneArg] (Block _ [Return _ ret])) = collectArgs (m - 1) (oneArg : acc) ret
178− collectArgs _ _ _ = Nothing
179−
180− isNFn :: Text -> Text -> Int -> AST -> Bool
181− isNFn expectMod prefix n (Indexer _ (Var _ name) (Var _ modName)) | modName == expectMod =
182− name == fromString (T.unpack prefix <> show n)
183− isNFn _ _ _ _ = False
184−
185− runFn :: Int -> AST -> AST
186− runFn = runFn' C.dataFunctionUncurried C.runFn (\ss f args ->
187− let len = length args
188− typ = mkString $ uncurriedFnType len in
189− if len > 0
190− then App ss (App Nothing (StringLiteral Nothing typ) [f]) args
191− else App ss f args)
192− runEffFn :: Text -> Text -> Int -> AST -> AST
193− runEffFn modName fnName = runFn' modName fnName $ \ss fn acc ->
194− let typ = mkString . uncurriedFnType $ length acc in
195− Function ss Nothing [] (Block ss [Return ss (App ss (App Nothing (StringLiteral Nothing typ) [fn]) acc)])
196−
197− runFn' :: Text -> Text -> (Maybe SourceSpan -> AST -> [AST] -> AST) -> Int -> AST -> AST
198− runFn' modName runFnName res n = convert where
199− convert :: AST -> AST
200− convert il = fromMaybe il $ go n [] il
201−
202− go :: Int -> [AST] -> AST -> Maybe AST
203− go 0 acc (App ss runFnN [fn]) | isNFn modName runFnName n runFnN && length acc == n =
204− Just $ res ss fn acc
205− go m acc (App _ lhs [arg]) = go (m - 1) (arg : acc) lhs
206− go _ _ _ = Nothing
207−
208− inlineNonClassFunction :: (AST -> Bool) -> (AST -> AST -> AST) -> AST -> AST
209− inlineNonClassFunction p f = convert where
210− convert :: AST -> AST
211− convert (App _ (App _ op' [x]) [y]) | p op' = f x y
212− convert other = other
213−
214− inlineUnsafeIndex :: (AST -> Bool) -> (AST -> AST -> AST) -> AST -> AST
215− inlineUnsafeIndex p _ = convert where
216− convert :: AST -> AST
217− convert (App _ (App ss op' [x]) [y@NumericLiteral{}])
218− | p op' = Indexer ss y x
219− convert (App _ (App ss op' [x]) [y])
220− | p op' = App ss (Var Nothing indexFn) [x, y]
221− convert other = other
222−
223− isModFn :: (Text, PSString) -> AST -> Bool
224− isModFn (m, op) (Indexer _ (Var _ op') (Var _ m')) =
225− m == m' && decodeString op == Just op'
226− isModFn _ _ = False
227−
228− isModFnWithDict :: (Text, PSString) -> AST -> Bool
229− isModFnWithDict (m, op) (App _ (Indexer _ (Var _ op') (Var _ m')) [Var _ _]) =
230− m == m' && decodeString op == Just op'
231− isModFnWithDict _ _ = False
232−
233−-- (f <<< g $ x) = f (g x)
234−-- (f <<< g) = \x -> f (g x)
235−inlineFnComposition :: forall m. MonadSupply m => AST -> m AST
236−inlineFnComposition = everywhereTopDownM convert where
237− convert :: AST -> m AST
238− convert (App s1 (App s2 (App _ (App _ fn [dict']) [x]) [y]) [z])
239− | isFnCompose dict' fn = return $ App s1 x [App s2 y [z]]
240− | isFnComposeFlipped dict' fn = return $ App s2 y [App s1 x [z]]
241− convert app@(App ss (App _ (App _ fn [dict']) _) _)
242− | isFnCompose dict' fn || isFnComposeFlipped dict' fn = mkApps ss <$> goApps app <*> freshName'
243− convert other = return other
244−
245− mkApps :: Maybe SourceSpan -> [Either AST (Text, AST)] -> Text -> AST
246− mkApps ss fns a = App ss (Function ss Nothing [] (Block ss $ vars <> [Return Nothing comp])) []
247− where
248− vars = uncurry (VariableIntroduction ss) . fmap Just <$> rights fns
249− comp = Function ss Nothing [a] (Block ss [Return Nothing apps])
250− apps = foldr (\fn acc -> App ss (mkApp fn) [acc]) (Var ss a) fns
251−
252− mkApp :: Either AST (Text, AST) -> AST
253− mkApp = either id $ \(name, arg) -> Var (getSourceSpan arg) name
254−
255− goApps :: AST -> m [Either AST (Text, AST)]
256− goApps (App _ (App _ (App _ fn [dict']) [x]) [y])
257− | isFnCompose dict' fn = mappend <$> goApps x <*> goApps y
258− | isFnComposeFlipped dict' fn = mappend <$> goApps y <*> goApps x
259− goApps app@(App {}) = pure . Right . (,app) <$> freshName'
260− goApps other = pure [Left other]
261−
262− isFnCompose :: AST -> AST -> Bool
263− isFnCompose dict' fn = isDict semigroupoidFn dict' && isDict fnCompose fn
264−
265− isFnComposeFlipped :: AST -> AST -> Bool
266− isFnComposeFlipped dict' fn = isDict semigroupoidFn dict' && isDict fnComposeFlipped fn
267−
268− fnCompose :: forall a b. (IsString a, IsString b) => (a, b)
269− fnCompose = (C.controlSemigroupoid, C.compose)
270−
271− fnComposeFlipped :: forall a b. (IsString a, IsString b) => (a, b)
272− fnComposeFlipped = (C.controlSemigroupoid, C.composeFlipped)
273−
274−inlineUnsafeCoerce :: AST -> AST
275−inlineUnsafeCoerce = everywhereTopDown convert where
276− convert (App _ (Indexer _ (Var _ unsafeCoerceFn) (Var _ unsafeCoerce)) [ comp ])
277− | unsafeCoerceFn == C.unsafeCoerceFn && unsafeCoerce == C.unsafeCoerce
278− = comp
279− convert other = other
280−
281−inlineUnsafePartial :: AST -> AST
282−inlineUnsafePartial = everywhereTopDown convert where
283− convert (App ss fn [ comp ])
284− | isDict fnUnsafePartial fn
285− = App ss comp []
286− where
287− fnUnsafePartial :: forall a b. (IsString a, IsString b) => (a, b)
288− fnUnsafePartial = (C.partialUnsafe, C.unsafePartial)
289− convert other = other
290−
291−semiringNumber :: forall a b. (IsString a, IsString b) => (a, b)
292−semiringNumber = (C.dataSemiring, C.semiringNumber)
293−
294−semiringInt :: forall a b. (IsString a, IsString b) => (a, b)
295−semiringInt = (C.dataSemiring, C.semiringInt)
296−
297−ringNumber :: forall a b. (IsString a, IsString b) => (a, b)
298−ringNumber = (C.dataRing, C.ringNumber)
299−
300−ringInt :: forall a b. (IsString a, IsString b) => (a, b)
301−ringInt = (C.dataRing, C.ringInt)
302−
303−euclideanRingNumber :: forall a b. (IsString a, IsString b) => (a, b)
304−euclideanRingNumber = (C.dataEuclideanRing, C.euclideanRingNumber)
305−
306−-- eqNumber :: forall a b. (IsString a, IsString b) => (a, b)
307−-- eqNumber = (C.dataEq, C.eqNumber)
308−
309−eqInt :: forall a b. (IsString a, IsString b) => (a, b)
310−eqInt = (C.dataEq, C.eqInt)
311−
312−eqString :: forall a b. (IsString a, IsString b) => (a, b)
313−eqString = (C.dataEq, C.eqString)
314−
315−eqChar :: forall a b. (IsString a, IsString b) => (a, b)
316−eqChar = (C.dataEq, C.eqChar)
317−
318−eqBoolean :: forall a b. (IsString a, IsString b) => (a, b)
319−eqBoolean = (C.dataEq, C.eqBoolean)
320−
321−ordBoolean :: forall a b. (IsString a, IsString b) => (a, b)
322−ordBoolean = (C.dataOrd, C.ordBoolean)
323−
324−ordNumber :: forall a b. (IsString a, IsString b) => (a, b)
325−ordNumber = (C.dataOrd, C.ordNumber)
326−
327−ordInt :: forall a b. (IsString a, IsString b) => (a, b)
328−ordInt = (C.dataOrd, C.ordInt)
329−
330−ordString :: forall a b. (IsString a, IsString b) => (a, b)
331−ordString = (C.dataOrd, C.ordString)
332−
333−ordChar :: forall a b. (IsString a, IsString b) => (a, b)
334−ordChar = (C.dataOrd, C.ordChar)
335−
336−semigroupString :: forall a b. (IsString a, IsString b) => (a, b)
337−semigroupString = (C.dataSemigroup, C.semigroupString)
338−
339−boundedBoolean :: forall a b. (IsString a, IsString b) => (a, b)
340−boundedBoolean = (C.dataBounded, C.boundedBoolean)
341−
342−heytingAlgebraBoolean :: forall a b. (IsString a, IsString b) => (a, b)
343−heytingAlgebraBoolean = (C.dataHeytingAlgebra, C.heytingAlgebraBoolean)
344−
345−semigroupoidFn :: forall a b. (IsString a, IsString b) => (a, b)
346−semigroupoidFn = (C.controlSemigroupoid, C.semigroupoidFn)
347−
348−opAdd :: forall a b. (IsString a, IsString b) => (a, b)
349−opAdd = (C.dataSemiring, C.add)
350−
351−opMul :: forall a b. (IsString a, IsString b) => (a, b)
352−opMul = (C.dataSemiring, C.mul)
353−
354−opEq :: forall a b. (IsString a, IsString b) => (a, b)
355−opEq = (C.dataEq, C.eq)
356−
357−opNotEq :: forall a b. (IsString a, IsString b) => (a, b)
358−opNotEq = (C.dataEq, C.notEq)
359−
360−opLessThan :: forall a b. (IsString a, IsString b) => (a, b)
361−opLessThan = (C.dataOrd, C.lessThan)
362−
363−opLessThanOrEq :: forall a b. (IsString a, IsString b) => (a, b)
364−opLessThanOrEq = (C.dataOrd, C.lessThanOrEq)
365−
366−opGreaterThan :: forall a b. (IsString a, IsString b) => (a, b)
367−opGreaterThan = (C.dataOrd, C.greaterThan)
368−
369−opGreaterThanOrEq :: forall a b. (IsString a, IsString b) => (a, b)
370−opGreaterThanOrEq = (C.dataOrd, C.greaterThanOrEq)
371−
372−opAppend :: forall a b. (IsString a, IsString b) => (a, b)
373−opAppend = (C.dataSemigroup, C.append)
374−
375−opSub :: forall a b. (IsString a, IsString b) => (a, b)
376−opSub = (C.dataRing, C.sub)
377−
378−opNegate :: forall a b. (IsString a, IsString b) => (a, b)
379−opNegate = (C.dataRing, C.negate)
380−
381−opDiv :: forall a b. (IsString a, IsString b) => (a, b)
382−opDiv = (C.dataEuclideanRing, C.div)
383−
384−opConj :: forall a b. (IsString a, IsString b) => (a, b)
385−opConj = (C.dataHeytingAlgebra, C.conj)
386−
387−opDisj :: forall a b. (IsString a, IsString b) => (a, b)
388−opDisj = (C.dataHeytingAlgebra, C.disj)
389−
390−opNot :: forall a b. (IsString a, IsString b) => (a, b)
391−opNot = (C.dataHeytingAlgebra, C.not)
392−
393−unbox :: AST -> PSString -> AST
394−unbox e d = select . inlineCommonValues $ inlineCommonOperators e
395− where
396− select :: AST -> AST
397− select e' =
398− case e' of
399− Var{} -> unbox' e'
400− App{} -> unbox' e'
401− Indexer{} -> unbox' e'
402− _ -> e'
403− unbox' :: AST -> AST
404− unbox' e' = maybe e' (\t -> App Nothing (StringLiteral Nothing t) [e']) $ unboxType d
405−
406−unboxType :: PSString -> Maybe PSString
407−unboxType s = do
408− t <- decodeString s
409− t' <- unboxType' t
410− return $ mkString t'
411− where
412− unboxType' :: Text -> Maybe Text
413− unboxType' t
414− | t == C.eqInt ||
415− t == C.semiringInt ||
416− t == C.ringInt ||
417− t == C.ordInt ||
418− t == C.dataIntBits
419− = Just int
420− | t == C.semiringNumber ||
421− t == C.ringNumber ||
422− t == C.ordNumber ||
423− t == C.euclideanRingNumber
424− = Just float
425− | t == C.eqBoolean ||
426− t == C.ordBoolean ||
427− t == C.heytingAlgebraBoolean
428− = Just bool
429− | t == C.eqChar ||
430− t == C.eqString ||
431− t == C.ordChar ||
432− t == C.ordString ||
433− t == C.semigroupString
434− = Just string
435− | otherwise = Nothing
src/CodeGen/IL/Optimizer/MagicDo.hsdeleted−146
@@ -1,146 +0,0 @@
1−-- | This module implements the "Magic Do" optimization, which inlines calls to return
2−-- and bind for the Eff monad, as well as some of its actions.
3−module CodeGen.IL.Optimizer.MagicDo (magicDoEffect, magicDoEff, magicDoST, inlineST) where
4−
5−import Prelude.Compat
6−import Protolude (ordNub)
7−
8−import Data.Maybe (fromJust, isJust)
9−import Data.Text (Text)
10−
11−import Language.PureScript.CoreImp.AST
12−import Language.PureScript.CoreImp.Optimizer.Common hiding (isDict)
13−import Language.PureScript.PSString (PSString, decodeString, mkString)
14−import qualified Language.PureScript.Constants as C
15−
16−import CodeGen.IL.Common (undefinedName, unusedName)
17−import CodeGen.IL.Optimizer.Common
18−
19−-- | Inline type class dictionaries for >>= and return for the Eff monad
20−--
21−-- E.g.
22−--
23−-- Prelude[">>="](dict)(m1)(function(x) {
24−-- return ...;
25−-- })
26−--
27−-- becomes
28−--
29−-- function __do {
30−-- var x = m1();
31−-- ...
32−-- }
33−magicDoEff :: AST -> AST
34−magicDoEff = magicDo C.eff C.effDictionaries
35−
36−magicDoEffect :: AST -> AST
37−magicDoEffect = magicDo C.effect C.effectDictionaries
38−
39−magicDoST :: AST -> AST
40−magicDoST = magicDo C.st C.stDictionaries
41−
42−magicDo :: Text -> C.EffectDictionaries -> AST -> AST
43−magicDo effectModule C.EffectDictionaries{..} = everywhereTopDown convert
44− where
45− -- Desugar monomorphic calls to >>= and return for the Eff monad
46− convert :: AST -> AST
47− -- Desugar pure
48− convert (App _ (App _ pure' [val]) []) | isPure pure' = val
49− -- Desugar discard
50− convert (App _ (App _ bind [m]) [Function s1 Nothing [unused] (Block s2 il)]) | isDiscard bind && unused == unusedName =
51− Function s1 Nothing [] $ Block s2 (App s2 m [] : map applyReturns il )
52− -- Desugar bind
53− convert (App _ (App _ bind [m]) [Function s1 Nothing [arg] (Block s2 il)]) | isBind bind =
54− Function s1 Nothing [] $ Block s2 (VariableIntroduction s2 arg (Just (App s2 m [])) : map applyReturns il)
55− -- Desugar untilE
56− convert (App s1 (App _ f [arg]) []) | isEffFunc edUntil f =
57− App s1 (Function s1 Nothing [] (Block s1 [ While s1 (Unary s1 Not (App s1 arg [])) (Block s1 []), Return s1 $ ObjectLiteral s1 []])) []
58− -- Desugar whileE
59− convert (App _ (App _ (App s1 f [arg1]) [arg2]) []) | isEffFunc edWhile f =
60− App s1 (Function s1 Nothing [] (Block s1 [ While s1 (App s1 arg1 []) (Block s1 [ App s1 arg2 [] ]), Return s1 $ ObjectLiteral s1 []])) []
61− -- -- Inline __do returns
62− -- convert (Return _ (App _ (Function _ (Just ident) [] body) [])) | ident == fnName = body
63− -- Inline double applications
64− convert (App _ (App s1 (Function s2 Nothing [] (Block ss body)) []) []) =
65− App s1 (Function s2 Nothing [] (Block ss (applyReturns `fmap` body))) []
66− convert other = other
67− -- Check if an expression represents a monomorphic call to >>= for the Eff monad
68− isBind (App _ fn [dict]) | isDict (effectModule, edBindDict) dict && isBindPoly fn = True
69− isBind _ = False
70− -- Check if an expression represents a call to @discard@
71− isDiscard (App _ (App _ fn [dict1]) [dict2])
72− | isDict (C.controlBind, C.discardUnitDictionary) dict1 &&
73− isDict (effectModule, edBindDict) dict2 &&
74− isDiscardPoly fn = True
75− isDiscard _ = False
76−
77− -- Check if an expression represents a monomorphic call to pure or return for the Eff applicative
78− isPure (App _ fn [dict]) | isDict (effectModule, edApplicativeDict) dict && isPurePoly fn = True
79− isPure _ = False
80− -- Check if an expression represents the polymorphic >>= function
81− isBindPoly = isDict (C.controlBind, C.bind)
82− -- Check if an expression represents the polymorphic pure function
83− isPurePoly = isDict (C.controlApplicative, C.pure')
84− -- Check if an expression represents the polymorphic discard function
85− isDiscardPoly = isDict (C.controlBind, C.discard)
86− -- Check if an expression represents a function in the Effect module
87− isEffFunc name (Indexer _ (StringLiteral _ name') (Var _ eff)) = eff == effectModule && name == name'
88− isEffFunc _ _ = False
89−
90− applyReturns :: AST -> AST
91− applyReturns (Return ss ret) = Return ss (App ss ret [])
92− applyReturns (Block ss ils) = Block ss (map applyReturns ils)
93− applyReturns (While ss cond il) = While ss cond (applyReturns il)
94− applyReturns (For ss v lo hi il) = For ss v lo hi (applyReturns il)
95− applyReturns (ForIn ss v xs il) = ForIn ss v xs (applyReturns il)
96− applyReturns (IfElse ss cond t f) = IfElse ss cond (applyReturns t) (applyReturns `fmap` f)
97− applyReturns other = other
98−
99−-- | Inline functions in the ST module
100−inlineST :: AST -> AST
101−inlineST = everywhere convertBlock
102− where
103− -- Look for runST blocks and inline the STRefs there.
104− -- If all STRefs are used in the scope of the same runST, only using { read, write, modify }STRef then
105− -- we can be more aggressive about inlining, and actually turn STRefs into local variables.
106− convertBlock (App s1 f [arg]) | isSTFunc C.runST f =
107− let refs = ordNub . findSTRefsIn $ arg
108− usages = findAllSTUsagesIn arg
109− allUsagesAreLocalVars = all (\u -> let v = toVar u in isJust v && fromJust v `elem` refs) usages
110− localVarsDoNotEscape = all (\r -> length (r `appearingIn` arg) == length (filter (\u -> let v = toVar u in v == Just r) usages)) refs
111− in App s1 (everywhere (convert (allUsagesAreLocalVars && localVarsDoNotEscape)) arg) []
112− convertBlock other = other
113− -- Convert a block in a safe way, preserving object wrappers of references,
114− -- or in a more aggressive way, turning wrappers into local variables depending on the
115− -- agg(ressive) parameter.
116− convert agg (App s1 f [arg]) | isSTFunc C.newSTRef f =
117− Function s1 Nothing [] (Block s1 [Return s1 $ if agg then arg else ObjectLiteral s1 [(mkString C.stRefValue, arg)]])
118− convert agg (App _ (App s1 f [ref]) []) | isSTFunc C.readSTRef f =
119− if agg then ref else Indexer s1 (StringLiteral s1 C.stRefValue) ref
120− convert agg (App _ (App _ (App s1 f [arg]) [ref]) []) | isSTFunc C.writeSTRef f =
121− if agg then Assignment s1 ref arg else Assignment s1 (Indexer s1 (StringLiteral s1 C.stRefValue) ref) arg
122− convert agg (App _ (App _ (App s1 f [func]) [ref]) []) | isSTFunc C.modifySTRef f =
123− if agg then Assignment s1 ref (App s1 func [ref]) else Assignment s1 (Indexer s1 (StringLiteral s1 C.stRefValue) ref) (App s1 func [Indexer s1 (StringLiteral s1 C.stRefValue) ref])
124− convert _ other = other
125− -- Check if an expression represents a function in the ST module
126− isSTFunc name (Indexer _ (StringLiteral _ name') (Var _ st)) = st == C.st && name == name'
127− isSTFunc _ _ = False
128− -- Find all ST Refs initialized in this block
129− findSTRefsIn = everything (++) isSTRef
130− where
131− isSTRef (VariableIntroduction _ ident (Just (App _ (App _ f [_]) []))) | isSTFunc C.newSTRef f = [ident]
132− isSTRef _ = []
133− -- Find all STRefs used as arguments to readSTRef, writeSTRef, modifySTRef
134− findAllSTUsagesIn = everything (++) isSTUsage
135− where
136− isSTUsage (App _ (App _ f [ref]) []) | isSTFunc C.readSTRef f = [ref]
137− isSTUsage (App _ (App _ (App _ f [_]) [ref]) []) | isSTFunc C.writeSTRef f || isSTFunc C.modifySTRef f = [ref]
138− isSTUsage _ = []
139− -- Find all uses of a variable
140− appearingIn ref = everything (++) isVar
141− where
142− isVar e@(Var _ v) | v == ref = [e]
143− isVar _ = []
144− -- Convert a AST value to a String if it is a Var
145− toVar (Var _ v) = Just v
146− toVar _ = Nothing
src/CodeGen/IL/Optimizer/TCO.hsdeleted−141
@@ -1,141 +0,0 @@
1−module CodeGen.IL.Optimizer.TCO (tco, tcoLoop) where
2−
3−import Prelude.Compat
4−
5−import Data.Text (Text)
6−import Data.Monoid ((<>))
7−import Language.PureScript.CoreImp.AST
8−import Language.PureScript.AST.SourcePos (SourceSpan)
9−import Safe (headDef, tailSafe)
10−import CodeGen.IL.Common
11−
12−import qualified Language.PureScript.Constants as C
13−
14−tcoLoop :: Text
15−tcoLoop = "ṩtco_loop"
16−
17−tco :: AST -> AST -> AST
18−tco mn = everywhere convert where
19− tcoVar :: Text -> Text
20− tcoVar arg = "ṩtco_var_" <> arg
21−
22− copyVar :: Text -> Text
23− copyVar arg = "ṩcopy_" <> arg
24−
25− tcoDone :: Text
26− tcoDone = "ṩtco_done"
27−
28− tcoResult :: Text
29− tcoResult = "ṩtco_result"
30−
31− convert :: AST -> AST
32− convert fn@(Function ss (Just name) args _)
33− | isTailRecursive name body'
34− = replace (toLoop name outerArgs innerArgs body')
35− where
36− innerArgs = headDef [] argss
37− outerArgs = concat . reverse $ tailSafe argss
38− (argss, body', replace) = collectAllFunctionArgs [] id fn
39− convert (Assignment ss (Var _ name) fn@(Function _ Nothing _ _))
40− | isTailRecursive name body'
41− = Assignment ss (Var ss name) (replace (toLoop name outerArgs innerArgs body'))
42− where
43− innerArgs = headDef [] argss
44− outerArgs = concat . reverse $ tailSafe argss
45− (argss, body', replace) = collectAllFunctionArgs [] id fn
46− convert js = js
47−
48− collectAllFunctionArgs :: [[Text]] -> (AST -> AST) -> AST -> ([[Text]], AST, AST -> AST)
49− collectAllFunctionArgs allArgs f (Function s1 ident args (Block s2 (body@(Return _ _):_))) =
50− collectAllFunctionArgs (args : allArgs) (\b -> f (Function s1 ident (map copyVar args) (Block s2 [b]))) body
51− collectAllFunctionArgs allArgs f (Function ss ident args body@(Block _ _)) =
52− (args : allArgs, body, f . Function ss ident (map copyVar args))
53− collectAllFunctionArgs allArgs f (Return s1 (Function s2 ident args (Block s3 [body]))) =
54− collectAllFunctionArgs (args : allArgs) (\b -> f (Return s1 (Function s2 ident (map copyVar args) (Block s3 [b])))) body
55− collectAllFunctionArgs allArgs f (Return s1 (Function s2 ident args body@(Block _ _))) =
56− (args : allArgs, body, f . Return s1 . Function s2 ident (map copyVar args))
57− collectAllFunctionArgs allArgs f body = (allArgs, body, f)
58−
59− isTailRecursive :: Text -> AST -> Bool
60− isTailRecursive ident js = countSelfReferences js > 0 && allInTailPosition js where
61− countSelfReferences = everything (+) match where
62− match :: AST -> Int
63− match (Var _ ident') | ident == ident' = 1
64− match _ = 0
65−
66− allInTailPosition (Return _ expr)
67− | isSelfCall ident expr = countSelfReferences expr == 1
68− | otherwise = countSelfReferences expr == 0
69− allInTailPosition (While _ js1 body)
70− = countSelfReferences js1 == 0 && allInTailPosition body
71− allInTailPosition (For _ _ js1 js2 body)
72− = countSelfReferences js1 == 0 && countSelfReferences js2 == 0 && allInTailPosition body
73− allInTailPosition (ForIn _ _ js1 body)
74− = countSelfReferences js1 == 0 && allInTailPosition body
75− allInTailPosition (IfElse _ js1 body el)
76− = countSelfReferences js1 == 0 && allInTailPosition body && all allInTailPosition el
77− allInTailPosition (Block _ body)
78− = all allInTailPosition body
79− allInTailPosition (Throw _ js1)
80− = countSelfReferences js1 == 0
81− allInTailPosition (ReturnNoResult _)
82− = True
83− allInTailPosition (VariableIntroduction _ _ js1)
84− = all ((== 0) . countSelfReferences) js1
85− allInTailPosition (Assignment _ _ js1)
86− = countSelfReferences js1 == 0
87− allInTailPosition (Comment _ _ js1)
88− = allInTailPosition js1
89− allInTailPosition _
90− = False
91−
92− toLoop :: Text -> [Text] -> [Text] -> AST -> AST
93− toLoop ident outerArgs innerArgs js =
94− Block rootSS $
95− concatMap (\arg -> [ VariableIntroduction rootSS (tcoVar arg) . Just $
96− Var rootSS (copyVar arg) ]) (outerArgs ++ innerArgs) ++
97− [ Assignment rootSS (Var rootSS $ "var " <> tcoDone) $ BooleanLiteral Nothing False
98− , VariableIntroduction rootSS tcoResult Nothing
99− , Assignment rootSS (Var rootSS $ "var " <> tcoLoop) (Function rootSS (Just tcoLoop) (outerArgs ++ innerArgs) (Block rootSS [loopify js]))
100− , While rootSS (Unary Nothing Not (Var rootSS tcoDone))
101− (Block rootSS
102− [(Assignment rootSS (Var rootSS tcoResult) (App rootSS (Var rootSS tcoLoop) ((map (Var rootSS . tcoVar) outerArgs) ++ (map (Var rootSS . copyVar) innerArgs))))])
103− , Return rootSS (Var rootSS tcoResult)
104− ]
105− where
106− rootSS = Nothing
107−
108− loopify :: AST -> AST
109− loopify (Return ss ret)
110− | isSelfCall ident ret =
111− let
112− allArgumentValues = concat $ collectArgs [] ret
113− in
114− Block ss $
115− zipWith (\val arg ->
116− Assignment ss (Var ss (tcoVar arg)) val) allArgumentValues outerArgs
117− ++ zipWith (\val arg ->
118− Assignment ss (Var ss (copyVar arg)) val) (drop (length outerArgs) allArgumentValues) innerArgs
119− ++ [ ReturnNoResult ss ]
120− | otherwise = Block ss [ markDone ss, Return ss ret ]
121− loopify (ReturnNoResult ss) = Block ss [ markDone ss, ReturnNoResult ss ]
122− loopify (While ss cond body) = While ss cond (loopify body)
123− loopify (For ss i js1 js2 body) = For ss i js1 js2 (loopify body)
124− loopify (ForIn ss i js1 body) = ForIn ss i js1 (loopify body)
125− loopify (IfElse ss cond body el) = IfElse ss cond (loopify body) (fmap loopify el)
126− loopify (Block ss body) = Block ss (map loopify body)
127− loopify other = other
128−
129− markDone :: Maybe SourceSpan -> AST
130− markDone ss = Assignment ss (Var ss tcoDone) (BooleanLiteral ss True)
131−
132− collectArgs :: [[AST]] -> AST -> [[AST]]
133− collectArgs acc (App _ fn args') = collectArgs (args' : acc) fn
134− collectArgs acc _ = acc
135−
136− isSelfCall :: Text -> AST -> Bool
137− isSelfCall ident (App _ (Var _ ident') _) = ident == ident'
138− isSelfCall ident (App _ (Indexer _ (Var _ ident') (Var _ mn')) _) = mn' == "" && ident == ident'
139− isSelfCall ident (App _ (Indexer _ (Var _ ident') mn') _) = mn' == mn && ident == ident'
140− isSelfCall ident (App _ fn _) = isSelfCall ident fn
141− isSelfCall _ _ = False
src/CodeGen/IL/Printer.hsdeleted−527
@@ -1,527 +0,0 @@
1−-- | Pretty printer for the AST
2−module CodeGen.IL.Printer
3− ( prettyPrintIL
4− , prettyPrintIL1
5− , prettyPrintILWithSourceMaps
6− , interfaceSource
7− , implHeaderSource
8− , implFooterSource
9− , isLiteral
10− , modLabel
11− , modPrefix
12− , ffiLoader
13− ) where
14−
15−import Prelude.Compat
16−
17−import Control.Arrow ((<+>))
18−import Control.Monad (forM, mzero)
19−import Control.Monad.State (StateT, evalStateT)
20−import Control.PatternArrows
21−import Data.List (filter, (\\))
22−import qualified Control.Arrow as A
23−
24−import Data.Maybe (fromMaybe)
25−import Data.Monoid ((<>))
26−import Data.Text (Text)
27−import qualified Data.Text as T
28−
29−import Language.PureScript.AST (SourceSpan(..))
30−import Language.PureScript.CoreImp.AST
31−import Language.PureScript.Comments
32−import Language.PureScript.Crash
33−import Language.PureScript.Names (Ident, runIdent)
34−import Language.PureScript.Pretty.Common
35−import Language.PureScript.PSString (PSString, decodeString, mkString)
36−
37−import CodeGen.IL.Common
38−import CodeGen.IL.Optimizer.TCO (tcoLoop)
39−
40−import qualified Language.PureScript.Constants as C
41−
42−-- TODO (Christoph): Get rid of T.unpack / pack
43−
44−literals :: (Emit gen) => Pattern PrinterState AST gen
45−literals = mkPattern' match'
46− where
47− match' :: (Emit gen) => AST -> StateT PrinterState Maybe gen
48− match' il = (addMapping' (getSourceSpan il) <>) <$> match il
49−
50− match :: (Emit gen) => AST -> StateT PrinterState Maybe gen
51− match (NumericLiteral _ n) = return $ emit $ T.pack $ either show show n
52− match (StringLiteral _ s) = return $ emit $ stringLiteral s
53− match (BooleanLiteral _ True) = return $ emit "true"
54− match (BooleanLiteral _ False) = return $ emit "false"
55− match (ArrayLiteral _ xs) = mconcat <$> sequence
56− [ return . emit $ arrayType <> "{"
57− , intercalate (emit ", ") <$> forM xs prettyPrintIL'
58− , return $ emit "}"
59− ]
60− -- match (ObjectLiteral _ []) = return $ emit "std::initializer_list<std::pair<const string, boxed>>{}"
61− match (ObjectLiteral _ ps) = mconcat <$> sequence
62− [ return . emit $ dictType <> "{"
63− , withIndent $ do
64− ils <- forM ps $ \(key, value) -> do
65− value' <- prettyPrintIL' value
66− return $ objectPropertyToString key <> value'
67− return $ intercalate (emit " ") $ map (<> emit ",") ils
68− , return $ emit "}"
69− ]
70− where
71− objectPropertyToString :: (Emit gen) => PSString -> gen
72− objectPropertyToString s = emit $ stringLiteral s <> ": "
73− match (Block _ sts) = mconcat <$> sequence
74− [ return $ emit "{\n"
75− , withIndent $ prettyStatements sts
76− , return $ emit "\n"
77− , currentIndent
78− , return $ emit "}"
79− ]
80− match (Var _ ident) | ident == C.undefined = return $ emit undefinedName
81− match (Var _ ident) = return $ emit ident
82− match (VariableIntroduction _ ident value) = mconcat <$> sequence
83− [ return . emit $ varDecl <> " " <> ident <> " " <> anyType
84− , maybe (return mempty) (fmap (emit " = " <>) . prettyPrintIL') value
85− ]
86− match (Assignment _ target value) = mconcat <$> sequence
87− [ prettyPrintIL' target
88− , return $ emit " = "
89− , prettyPrintIL' value
90− ]
91− match (App _ val []) = mconcat <$> sequence
92− [ return $ emit "Run("
93− , prettyPrintIL' val
94− , return $ emit ")"
95− ]
96− match (App _ (StringLiteral _ u) [arg])
97− | Just ty <- decodeString u = mconcat <$> sequence
98− [ prettyPrintIL' arg
99− , return $ emit ".("
100− , return $ emit ty
101− , return $ emit ")"
102− ]
103− match (App _ (Var _ fn) [arg]) | fn == arrayLengthFn = mconcat <$> sequence
104− [ return $ emit fn
105− , return $ emit "("
106− , prettyPrintIL' arg
107− , return $ emit ")"
108− ]
109− match (App _ (Var _ fn) args) | fn == indexFn = mconcat <$> sequence
110− [ return $ emit fn
111− , return $ emit "("
112− , intercalate (emit ", ") <$> forM args prettyPrintIL'
113− , return $ emit ")"
114− ]
115− match (App _ (Var _ fn) args) | fn == tcoLoop = mconcat <$> sequence
116− [ return $ emit fn
117− , return $ emit "("
118− , intercalate (emit ", ") <$> forM args prettyPrintIL'
119− , return $ emit ")"
120− ]
121− match (App _ (App Nothing (StringLiteral Nothing fnx) [fn@Function{}]) args)
122− | Just ftype <- decodeString fnx
123− , "Fn" `T.isPrefixOf` ftype = mconcat <$> sequence
124− [ prettyPrintIL' fn
125− , return $ emit "("
126− , intercalate (emit ", ") <$> forM args prettyPrintIL'
127− , return $ emit ")"
128− ]
129− match (App _ (App Nothing (StringLiteral Nothing fnx) [fn]) args)
130− | Just ftype <- decodeString fnx
131− , "Fn" `T.isPrefixOf` ftype = mconcat <$> sequence
132− [ prettyPrintIL' fn
133− , return $ emit ".("
134− , return $ emit ftype
135− , return $ emit ")("
136− , intercalate (emit ", ") <$> forM args prettyPrintIL'
137− , return $ emit ")"
138− ]
139− match app@(App{})
140− | (val, args) <- unApp app []
141− , length args > 1
142− = mconcat <$> sequence
143− [ return $ emit "Apply("
144− , prettyPrintIL' val
145− , return $ emit ", "
146− , intercalate (emit ", ") <$> forM args prettyPrintIL'
147− , return $ emit ")"
148− ]
149− match (App _ val args) = mconcat <$> sequence
150− [ return $ emit "Apply("
151− , prettyPrintIL' val
152− , return $ emit ", "
153− , intercalate (emit ", ") <$> forM args prettyPrintIL'
154− , return $ emit ")"
155− ]
156− match (Function _ (Just name) [] (Block _ [Return _ ret]))
157− | isComplexLiteral ret = mconcat <$> sequence
158− [ return $ emit "\n"
159− , return . emit $ varDecl <> " " <> initName name <> " Once\n"
160− , prettyPrintIL' $ VariableIntroduction Nothing (valueName name) Nothing
161− , return $ emit "\n\n"
162− , return $ emit "func "
163− , return . emit $ withPrefix name
164− , return . emit $ "() " <> anyType <> " "
165− , return $ emit "{\n"
166− , withIndent $ do
167− indentString <- currentIndent
168− return $ indentString <> (emit $ initName name <> ".Do(func() {\n") <>
169− indentString <> indentString <> (emit $ valueName name <> " = ")
170− , withIndent $ do
171− case ret of
172− Function _ Nothing args body -> mconcat <$> sequence
173− [ return $ emit "func("
174− , return . emit $ intercalate ", " (renderArg anyType <$> args)
175− , return . emit $ ") " <> anyType <> " "
176− , prettyPrintIL' body
177− ]
178− _ -> do
179− prettyPrintIL' ret
180− , return $ emit "\n"
181− , withIndent $ do
182− indentString <- currentIndent
183− return $ indentString <> (emit $ "})\n" <> "return " <> valueName name <>"\n")
184− , return $ emit "}\n\n"
185− ]
186− match (Function _ (Just name) [] ret) = mconcat <$> sequence
187− [ return $ emit "func "
188− , return . emit $ withPrefix name
189− , return . emit $ "() " <> anyType <> " "
190− , prettyPrintIL' ret
191− ]
192− match (Function _ _ args ret) = mconcat <$> sequence
193− [ return $ emit "func("
194− , return . emit $ intercalate ", " (renderArg anyType <$> args)
195− , return . emit $ ") " <> anyType <> " "
196− , prettyPrintIL' ret
197− ]
198− match (Indexer _ (Var _ name) (Var _ "")) = mconcat <$> sequence
199− [ prettyPrintIL' (Var Nothing $ withPrefix name)
200− , return $ emit "()"
201− ]
202− match (Indexer _ (Var _ name) val) = mconcat <$> sequence
203− [ prettyPrintIL' val
204− , return $ emit "."
205− , prettyPrintIL' (Var Nothing $ withPrefix name)
206− , return $ emit "()"
207− ]
208− match (Indexer _ prop@StringLiteral{} val@ObjectLiteral{}) = mconcat <$> sequence
209− [ prettyPrintIL' val
210− , return $ emit "["
211− , prettyPrintIL' prop
212− , return $ emit "]"
213− ]
214− match (Indexer _ prop@StringLiteral{} val) = mconcat <$> sequence
215− [ prettyPrintIL' val
216− , return $ emit ".("
217− , return $ emit dictType
218− , return $ emit ")["
219− , prettyPrintIL' prop
220− , return $ emit "]"
221− ]
222− match (Indexer _ index val@ArrayLiteral{}) = mconcat <$> sequence
223− [ prettyPrintIL' val
224− , return $ emit "["
225− , prettyPrintIL' index
226− , return $ emit "]"
227− ]
228− match (Indexer _ index val) = mconcat <$> sequence
229− [ prettyPrintIL' val
230− , return $ emit ".("
231− , return $ emit arrayType
232− , return $ emit ")["
233− , prettyPrintIL' index
234− , return $ emit "]"
235− ]
236− match (InstanceOf _ val ty) = mconcat <$> sequence
237− [ return $ emit "Is("
238− , prettyPrintIL' val
239− , return $ emit ", "
240− , prettyPrintIL' ty
241− , return $ emit ")"
242− ]
243− match (While _ cond sts) = mconcat <$> sequence
244− [ return $ emit "for "
245− , prettyPrintIL' cond
246− , return $ emit " "
247− , prettyPrintIL' sts
248− ]
249− match (For _ ident start end sts) = mconcat <$> sequence
250− [ return $ emit $ "for var " <> ident <> " = "
251− , prettyPrintIL' start
252− , return $ emit $ "; " <> ident <> " < "
253− , prettyPrintIL' end
254− , return $ emit $ "; " <> ident <> "++ "
255− , prettyPrintIL' sts
256− ]
257− match (ForIn _ ident obj sts) = mconcat <$> sequence
258− [ return $ emit $ "for var " <> ident <> " in "
259− , prettyPrintIL' obj
260− , return $ emit " "
261− , prettyPrintIL' sts
262− ]
263− match (IfElse _ (Binary _ EqualTo cond@Binary{} (BooleanLiteral Nothing True)) thens elses) = mconcat <$> sequence
264− [ return $ emit "if "
265− , prettyPrintIL' cond
266− , return $ emit " "
267− , prettyPrintIL' thens
268− , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintIL') elses
269− ]
270− match (IfElse _ (Binary _ EqualTo cond@Binary{} (BooleanLiteral Nothing False)) thens elses) = mconcat <$> sequence
271− [ return $ emit "if !("
272− , prettyPrintIL' cond
273− , return $ emit ") "
274− , prettyPrintIL' thens
275− , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintIL') elses
276− ]
277− match (IfElse _ cond thens elses) = mconcat <$> sequence
278− [ return $ emit "if "
279− , prettyPrintIL' cond
280− , return $ emit " "
281− , prettyPrintIL' thens
282− , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintIL') elses
283− ]
284− match (Return _ value) = mconcat <$> sequence
285− [ return $ emit "return "
286− , prettyPrintIL' value
287− ]
288− match (ReturnNoResult _) = return . emit $ "return " <> undefinedName
289− -- match (Throw _ _) = return mempty
290− match (Throw _ value) = mconcat <$> sequence
291− [ return $ emit "panic("
292− , prettyPrintIL' value
293− , return $ emit ")"
294− ]
295− match (Comment _ com il) = mconcat <$> sequence
296− [ return $ emit "\n"
297− , mconcat <$> forM com comment
298− , prettyPrintIL' il
299− ]
300− match _ = mzero
301−
302− comment :: (Emit gen) => Comment -> StateT PrinterState Maybe gen
303− comment (LineComment com) = fmap mconcat $ sequence $
304− [ currentIndent
305− , return $ emit "//" <> emit com <> emit "\n"
306− ]
307− comment (BlockComment com) = fmap mconcat $ sequence $
308− [ currentIndent
309− , return $ emit "/**\n"
310− ] ++
311− map asLine (T.lines com) ++
312− [ currentIndent
313− , return $ emit " */\n"
314− , currentIndent
315− ]
316− where
317− asLine :: (Emit gen) => Text -> StateT PrinterState Maybe gen
318− asLine s = do
319− i <- currentIndent
320− return $ i <> emit " * " <> (emit . removeComments) s <> emit "\n"
321−
322− removeComments :: Text -> Text
323− removeComments t =
324− case T.stripPrefix "*/" t of
325− Just rest -> removeComments rest
326− Nothing -> case T.uncons t of
327− Just (x, xs) -> x `T.cons` removeComments xs
328− Nothing -> ""
329−
330−unary' :: (Emit gen) => UnaryOperator -> (AST -> Text) -> Operator PrinterState AST gen
331−unary' op mkStr = Wrap match (<>)
332− where
333− match :: (Emit gen) => Pattern PrinterState AST (gen, AST)
334− match = mkPattern match'
335− where
336− match' (Unary _ op' val) | op' == op = Just (emit $ mkStr val, val)
337− match' _ = Nothing
338−
339−unary :: (Emit gen) => UnaryOperator -> Text -> Operator PrinterState AST gen
340−unary op str = unary' op (const str)
341−
342−negateOperator :: (Emit gen) => Operator PrinterState AST gen
343−negateOperator = unary' Negate (\v -> if isNegate v then "- " else "-")
344− where
345− isNegate (Unary _ Negate _) = True
346− isNegate _ = False
347−
348−binary :: (Emit gen) => BinaryOperator -> Text -> Operator PrinterState AST gen
349−binary op str = AssocL match (\v1 v2 -> v1 <> emit (" " <> str <> " ") <> v2)
350− where
351− match :: Pattern PrinterState AST (AST, AST)
352− match = mkPattern match'
353− where
354− match' (Binary _ op' v1 v2) | op' == op = Just (v1, v2)
355− match' _ = Nothing
356−
357−isLiteral :: AST -> Bool
358−isLiteral Function{} = True
359−isLiteral NumericLiteral{} = True
360−isLiteral StringLiteral{} = True
361−isLiteral BooleanLiteral{} = True
362−isLiteral ObjectLiteral{} = True
363−isLiteral ArrayLiteral{} = True
364−isLiteral _ = False
365−
366−isComplexLiteral :: AST -> Bool
367−-- isComplexLiteral Function{} = True
368−isComplexLiteral ObjectLiteral{} = True
369−isComplexLiteral ArrayLiteral{} = True
370−isComplexLiteral _ = False
371−
372−unApp :: AST -> [AST] -> (AST, [AST])
373−unApp (App _ val [arg]) args = unApp val (arg : args)
374−unApp other args = (other, args)
375−
376−prettyStatements :: (Emit gen) => [AST] -> StateT PrinterState Maybe gen
377−prettyStatements sts = do
378− ils <- forM sts prettyPrintIL'
379− indentString <- currentIndent
380− return $ intercalate (emit "\n") $ map (indentString <>) ils
381−
382−-- | Generate a pretty-printed string representing a collection of C++ expressions at the same indentation level
383−prettyPrintILWithSourceMaps :: [AST] -> (Text, [SMap])
384−prettyPrintILWithSourceMaps il =
385− let StrPos (_, s, mp) = (fromMaybe (internalError "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyStatements) il
386− in (s, mp)
387−
388−prettyPrintIL :: [AST] -> Text
389−prettyPrintIL = maybe (internalError "Incomplete pattern") runPlainString . flip evalStateT (PrinterState 0) . prettyStatements
390−
391−-- | Generate an indented, pretty-printed string representing a C++ expression
392−prettyPrintIL' :: (Emit gen) => AST -> StateT PrinterState Maybe gen
393−prettyPrintIL' = A.runKleisli $ runPattern matchValue
394− where
395− matchValue :: (Emit gen) => Pattern PrinterState AST gen
396− matchValue = buildPrettyPrinter operators (literals <+> fmap parensPos matchValue)
397− operators :: (Emit gen) => OperatorTable PrinterState AST gen
398− operators =
399− OperatorTable [ [ unary New "?" ]
400− , [ unary Not "!"
401− , unary BitwiseNot "~"
402− , unary Positive "+"
403− , negateOperator ]
404− , [ binary Multiply "*"
405− , binary Divide "/"
406− , binary Modulus "%" ]
407− , [ binary Add "+"
408− , binary Subtract "-" ]
409− , [ binary ShiftLeft "<<"
410− , binary ShiftRight ">>" ]
411− , [ binary LessThan "<"
412− , binary LessThanOrEqualTo "<="
413− , binary GreaterThan ">"
414− , binary GreaterThanOrEqualTo ">=" ]
415− , [ binary EqualTo "=="
416− , binary NotEqualTo "!=" ]
417− , [ binary BitwiseAnd "&" ]
418− , [ binary BitwiseXor "^" ]
419− , [ binary BitwiseOr "|" ]
420− , [ binary And "&&" ]
421− , [ binary Or "||" ]
422− ]
423−
424−prettyPrintIL1 :: AST -> Text
425−prettyPrintIL1 = maybe (internalError "Incomplete pattern") runPlainString . flip evalStateT (PrinterState 0) . prettyPrintIL'
426−
427−stringLiteral :: PSString -> Text
428−stringLiteral pss | Just s <- decodeString pss = stringLiteral' s
429− where
430− stringLiteral' :: Text -> Text
431− stringLiteral' s = "\"" <> T.concatMap encodeChar s <> "\""
432− encodeChar :: Char -> Text
433− encodeChar '\0' = "\\x00"
434− encodeChar '\b' = "\\b"
435− encodeChar '\t' = "\\t"
436− encodeChar '\n' = "\\n"
437− encodeChar '\v' = "\\v"
438− encodeChar '\f' = "\\f"
439− encodeChar '\r' = "\\r"
440− encodeChar '"' = "\\\""
441− encodeChar '\\' = "\\\\"
442− encodeChar c = T.singleton $ c
443−stringLiteral _ = "\"\\uFFFD\""
444−
445−interfaceSource :: Text -> [(Text,Bool)] -> [Ident] -> Text
446−interfaceSource _ _ _ = ""
447−
448−implHeaderSource :: Text -> [Text] -> Text -> Text
449−implHeaderSource mn imports otherPrefix =
450− "// Code generated by psgo. DO NOT EDIT.\n\n" <>
451− "package " <> (if mn == "Main" || mn == "Test_Main" then "main" else mn) <> "\n\n" <>
452− "import . \"" <> runtime <> "\"\n" <>
453− (if mn == "Main" || mn == "Test_Main"
454− then "import _ \"" <> otherPrefix <> "/" <> ffiLoader <> "\"\n"
455− else "\n") <>
456− "import (\n" <>
457− (T.concat $ formatImport <$> imports) <> ")\n\n" <>
458− "type _ = Any\n\n"
459− where
460− formatImport :: Text -> Text
461− formatImport s =
462− "\t\"" <> otherPrefix <> "/" <> modPrefix <> "/" <> moduleRenamer s <> "\"\n"
463− moduleRenamer :: Text -> Text
464− moduleRenamer s
465− | (s', sfx) <- T.breakOn moduleRenamerMarker s,
466− not $ T.null sfx = s'
467− moduleRenamer s = s
468−
469−implFooterSource :: Text -> [Ident] -> Text
470−implFooterSource mn foreigns =
471− "\n\n\n" <>
472− (if null foreigns
473− then ""
474− else ("// Foreign values\n\n" <>
475− "var " <> foreignDict <> " = "<> foreignMod <> "(\"" <> mn <> "\")\n\n" <>
476− (T.concat $ (\foreign' ->
477− let name = moduleIdentToIL foreign' in
478− varDecl <> " " <> initName name <> " Once\n" <>
479− varDecl <> " " <> valueName name <> " " <> anyType <> "\n\n" <>
480− "func " <>
481− withPrefix name <>
482− "() Any { \n" <>
483− " " <> initName name <> ".Do(func() {\n" <>
484− " " <> valueName name <> " = " <>
485− "Get(" <> foreignDict <> ", " <>
486− (stringLiteral . mkString $ runIdent foreign') <> ")\n" <>
487− " })\n" <>
488− " return " <> valueName name <> "\n" <>
489− "}\n\n") <$> foreigns))) <>
490− if mn == "Main" || mn == "Test.Main" then mainSource else "\n"
491− where
492− mainSource :: Text
493− mainSource = "\
494− \func main() {\n\
495− \ Run(Ꞌmain())\n\
496− \}\n\n\
497− \"
498−
499−varDecl :: Text
500−varDecl = "var"
501−
502−renderArg :: Text -> Text -> Text
503−renderArg decl arg = arg <> " " <> decl
504−
505−foreignMod :: Text
506−foreignMod = "Foreign"
507−
508−foreignDict :: Text
509−foreignDict = "foreign"
510−
511−modLabel :: Text
512−modLabel = "purescript-native"
513−
514−modPrefix :: Text
515−modPrefix = modLabel <> "/output"
516−
517−runtime :: Text
518−runtime = "github.com/" <> modLabel <> "/go-runtime"
519−
520−ffiLoader :: Text
521−ffiLoader = modLabel <> "/ffi-loader"
522−
523−initName :: Text -> Text
524−initName s = "ᛌ" <> s <> "_once"
525−
526−valueName :: Text -> Text
527−valueName s = "ᛧ" <> s
src/Data/Generics/Extras.hsnew file+63
@@ -0,0 +1,63 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Data.Generics.Extras
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+-- Additional SYB combinators
13+--
14+-----------------------------------------------------------------------------
15+
16+{-# LANGUAGE Rank2Types #-}
17+
18+module Data.Generics.Extras where
19+
20+import Data.Data
21+import Data.Maybe (fromMaybe)
22+
23+-- |
24+-- Apply a top-down monadic transformation everywhere
25+--
26+everywhereM' :: (Monad m, Data d) => (forall d1. (Data d1) => d1 -> m d1) -> d -> m d
27+everywhereM' f x = do
28+ y <- f x
29+ gmapM (everywhereM' f) y
30+
31+-- |
32+-- Apply a top-down transformation, mutating a state when descending from parents to children
33+--
34+-- For example, if we want to relabel bound variables with a different data constructor, we can do so:
35+--
36+-- > data Expr = Var String
37+-- > | Lam String Test
38+-- > | App Test Test
39+-- > | LocalVar String deriving (Show, Data, Typeable)
40+-- >
41+-- > test = App (Lam "a" (App (Var "a") (Var "b"))) (Var "a")
42+-- >
43+-- > varsToLocals :: Expr -> Expr
44+-- > varsToLocals = everywhereWithContext' [] (mkS go)
45+-- > where
46+-- > go locals (Var v) | v `elem` locals = (locals, LocalVar v)
47+-- > go locals lam@(Lam local _) = (local : locals, lam)
48+-- > go locals other = (locals, other)
49+--
50+everywhereWithContext' :: (Data d) => s -> (forall d1. (Data d1) => s -> d1 -> (s, d1)) -> d -> d
51+everywhereWithContext' s0 f x =
52+ let (s, y) = f s0 x in
53+ gmapT (everywhereWithContext' s f) y
54+
55+-- |
56+-- Make a stateful transformation function
57+--
58+mkS :: (Data a, Data b) => (s -> a -> (s, a)) -> s -> b -> (s, b)
59+mkS f s b = fromMaybe (s, b) $ do
60+ a <- cast b
61+ let (s', a') = f s a
62+ b' <- cast a'
63+ return (s', b')
src/Language/PureScript.hsnew file+78
@@ -0,0 +1,78 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript
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+-- The main compiler module
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript (module P, compile) where
17+
18+import Language.PureScript.Values as P
19+import Language.PureScript.Types as P
20+import Language.PureScript.Kinds as P
21+import Language.PureScript.Declarations as P
22+import Language.PureScript.Names as P
23+import Language.PureScript.Parser as P
24+import Language.PureScript.CodeGen as P
25+import Language.PureScript.CodeGen.Common as P
26+import Language.PureScript.TypeChecker as P
27+import Language.PureScript.Pretty as P
28+import Language.PureScript.Sugar as P
29+import Language.PureScript.Options as P
30+import Language.PureScript.ModuleDependencies as P
31+import Language.PureScript.DeadCodeElimination as P
32+
33+import Data.List (intercalate)
34+import Data.Maybe (mapMaybe)
35+import Control.Monad.State.Lazy
36+import Control.Applicative ((<$>))
37+import qualified Data.Map as M
38+
39+-- |
40+-- Compile a collection of modules
41+--
42+-- The compilation pipeline proceeds as follows:
43+--
44+-- * Sort the modules based on module dependencies, checking for cyclic dependencies.
45+--
46+-- * Perform a set of desugaring passes.
47+--
48+-- * Type check, and elaborate values to include type annotations and type class dictionaries.
49+--
50+-- * Regroup values to take into account new value dependencies introduced by elaboration.
51+--
52+-- * Eliminate dead code.
53+--
54+-- * Generate Javascript, and perform optimization passes.
55+--
56+-- * Pretty-print the generated Javascript
57+--
58+compile :: Options -> [Module] -> Either String (String, String, Environment)
59+compile opts ms = do
60+ sorted <- sortModules ms
61+ desugared <- desugar sorted
62+ (elaborated, env) <- runCheck $ forM desugared $ \(Module moduleName' decls) -> do
63+ modify (\s -> s { checkCurrentModule = Just moduleName' })
64+ Module moduleName' <$> typeCheckAll mainModuleIdent moduleName' decls
65+ regrouped <- createBindingGroupsModule . collapseBindingGroupsModule $ elaborated
66+ let entryPoints = moduleNameFromString `map` optionsModules opts
67+ let elim = if null entryPoints then regrouped else eliminateDeadCode env entryPoints regrouped
68+ let js = mapMaybe (flip (moduleToJs opts) env) elim
69+ let exts = intercalate "\n" . map (`moduleToPs` env) $ elim
70+ js' <- case mainModuleIdent of
71+ Just mmi -> do
72+ when ((mmi, Ident "main") `M.notMember` names env) $
73+ Left $ show mmi ++ ".main is undefined"
74+ return $ js ++ [JSApp (JSAccessor "main" (JSAccessor (moduleNameToJs mmi) (JSVar "_ps"))) []]
75+ _ -> return js
76+ return (prettyPrintJS [wrapExportsContainer opts js'], exts, env)
77+ where
78+ mainModuleIdent = moduleNameFromString <$> optionsMain opts
src/Language/PureScript/CodeGen.hsnew file+26
@@ -0,0 +1,26 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.CodeGen
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+-- A collection of modules related to code generation:
13+--
14+-- [@Language.PureScript.CodeGen.JS@] Code generator for Javascript
15+--
16+-- [@Language.PureScript.CodeGen.Externs@] Code generator for extern (foreign import) files
17+--
18+-- [@Language.PureScript.CodeGen.Optimize@] Optimization passes for generated Javascript
19+--
20+-----------------------------------------------------------------------------
21+
22+module Language.PureScript.CodeGen (module C) where
23+
24+import Language.PureScript.CodeGen.JS as C
25+import Language.PureScript.CodeGen.Externs as C
26+import Language.PureScript.CodeGen.Optimize as C
src/Language/PureScript/CodeGen/Common.hsnew file+134
@@ -0,0 +1,134 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.CodeGen.Common
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+-- Common code generation utility functions
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.CodeGen.Common where
17+
18+import Data.Char
19+import Data.List (intercalate)
20+import Language.PureScript.Names
21+
22+-- |
23+-- Convert an Ident into a valid Javascript identifier:
24+--
25+-- * Alphanumeric characters are kept unmodified.
26+--
27+-- * Reserved javascript identifiers are prefixed with '$$'.
28+--
29+-- * Symbols are prefixed with '$' followed by a symbol name or their ordinal value.
30+--
31+identToJs :: Ident -> String
32+identToJs (Ident name) | nameIsJsReserved name = "$$" ++ name
33+identToJs (Ident name) = concatMap identCharToString name
34+identToJs (Op op) = concatMap identCharToString op
35+identToJs (Escaped name) = name
36+
37+-- |
38+-- Attempts to find a human-readable name for a symbol, if none has been specified returns the
39+-- ordinal value.
40+--
41+identCharToString :: Char -> String
42+identCharToString c | isAlphaNum c = [c]
43+identCharToString '_' = "_"
44+identCharToString '.' = "$dot"
45+identCharToString '$' = "$dollar"
46+identCharToString '~' = "$tilde"
47+identCharToString '=' = "$eq"
48+identCharToString '<' = "$less"
49+identCharToString '>' = "$greater"
50+identCharToString '!' = "$bang"
51+identCharToString '#' = "$hash"
52+identCharToString '%' = "$percent"
53+identCharToString '^' = "$up"
54+identCharToString '&' = "$amp"
55+identCharToString '|' = "$bar"
56+identCharToString '*' = "$times"
57+identCharToString '/' = "$div"
58+identCharToString '+' = "$plus"
59+identCharToString '-' = "$minus"
60+identCharToString ':' = "$colon"
61+identCharToString '\\' = "$bslash"
62+identCharToString '?' = "$qmark"
63+identCharToString '@' = "$at"
64+identCharToString '\'' = "$prime"
65+identCharToString c = '$' : show (ord c)
66+
67+-- |
68+-- Checks whether an identifier name is reserved in Javascript.
69+--
70+nameIsJsReserved :: String -> Bool
71+nameIsJsReserved name =
72+ name `elem` [ "abstract"
73+ , "arguments"
74+ , "boolean"
75+ , "break"
76+ , "byte"
77+ , "case"
78+ , "catch"
79+ , "char"
80+ , "class"
81+ , "const"
82+ , "continue"
83+ , "debugger"
84+ , "default"
85+ , "delete"
86+ , "do"
87+ , "double"
88+ , "else"
89+ , "enum"
90+ , "eval"
91+ , "export"
92+ , "extends"
93+ , "final"
94+ , "finally"
95+ , "float"
96+ , "for"
97+ , "function"
98+ , "goto"
99+ , "if"
100+ , "implements"
101+ , "import"
102+ , "in"
103+ , "instanceof"
104+ , "int"
105+ , "interface"
106+ , "let"
107+ , "long"
108+ , "native"
109+ , "new"
110+ , "package"
111+ , "private"
112+ , "protected"
113+ , "public"
114+ , "return"
115+ , "short"
116+ , "static"
117+ , "super"
118+ , "switch"
119+ , "synchronized"
120+ , "this"
121+ , "throw"
122+ , "throws"
123+ , "transient"
124+ , "try"
125+ , "typeof"
126+ , "var"
127+ , "void"
128+ , "volatile"
129+ , "while"
130+ , "with"
131+ , "yield" ]
132+
133+moduleNameToJs :: ModuleName -> String
134+moduleNameToJs (ModuleName pns) = intercalate "_" (runProperName `map` pns)
src/Language/PureScript/CodeGen/Externs.hsnew file+51
@@ -0,0 +1,51 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.CodeGen.Externs
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+-- This module generates code for \"externs\" files, i.e. files containing only foreign import declarations.
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.CodeGen.Externs (
17+ moduleToPs
18+) where
19+
20+import Data.Maybe (maybeToList, mapMaybe)
21+import qualified Data.Map as M
22+import Language.PureScript.Declarations
23+import Language.PureScript.TypeChecker.Monad
24+import Language.PureScript.Pretty
25+import Language.PureScript.Names
26+import Data.List (intercalate)
27+
28+-- |
29+-- Generate foreign imports for all declarations in a module
30+--
31+moduleToPs :: Module -> Environment -> String
32+moduleToPs (Module mn decls) env =
33+ "module " ++ runModuleName mn ++ " where\n" ++
34+ (intercalate "\n" . map (" " ++) . concatMap (declToPs mn env) $ decls)
35+
36+declToPs :: ModuleName -> Environment -> Declaration -> [String]
37+declToPs path env (ValueDeclaration name _ _ _) = maybeToList $ do
38+ (ty, _) <- M.lookup (path, name) $ names env
39+ return $ "foreign import " ++ show name ++ " :: " ++ prettyPrintType ty
40+declToPs path env (BindingGroupDeclaration vals) =
41+ flip mapMaybe vals $ \(name, _) -> do
42+ (ty, _) <- M.lookup (path, name) $ names env
43+ return $ "foreign import " ++ show name ++ " :: " ++ prettyPrintType ty
44+declToPs path env (DataDeclaration name _ _) = maybeToList $ do
45+ kind <- M.lookup (Qualified (Just path) name) $ types env
46+ return $ "foreign import data " ++ show name ++ " :: " ++ prettyPrintKind kind
47+declToPs _ _ (ExternDataDeclaration name kind) =
48+ return $ "foreign import data " ++ show name ++ " :: " ++ prettyPrintKind kind
49+declToPs _ _ (TypeSynonymDeclaration name args ty) =
50+ return $ "type " ++ show name ++ " " ++ unwords args ++ " = " ++ prettyPrintType ty
51+declToPs _ _ _ = []
src/Language/PureScript/CodeGen/JS.hsnew file+329
@@ -0,0 +1,329 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.CodeGen.JS
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+-- This module generates code in the simplified Javascript intermediate representation from Purescript code
13+--
14+-----------------------------------------------------------------------------
15+
16+{-# LANGUAGE DoAndIfThenElse #-}
17+
18+module Language.PureScript.CodeGen.JS (
19+ module AST,
20+ declToJs,
21+ moduleToJs,
22+ wrapExportsContainer
23+) where
24+
25+import Data.Maybe (fromMaybe, mapMaybe)
26+import Data.Function (on)
27+import Data.Data (Data)
28+import Data.Generics (mkQ, everything)
29+
30+import Control.Arrow (second)
31+import Control.Monad (replicateM, forM)
32+
33+import qualified Data.Map as M
34+
35+import Language.PureScript.TypeChecker (Environment(..), NameKind(..))
36+import Language.PureScript.Values
37+import Language.PureScript.Names
38+import Language.PureScript.Scope
39+import Language.PureScript.Declarations
40+import Language.PureScript.CodeGen.Monad
41+import Language.PureScript.Options
42+import Language.PureScript.CodeGen.JS.AST as AST
43+import Language.PureScript.Types
44+import Language.PureScript.CodeGen.Optimize
45+import Language.PureScript.CodeGen.Common
46+
47+-- |
48+-- Generate code in the simplified Javascript intermediate representation for all declarations in a
49+-- module.
50+--
51+moduleToJs :: Options -> Module -> Environment -> Maybe JS
52+moduleToJs opts (Module name decls) env =
53+ case jsDecls of
54+ [] -> Nothing
55+ _ -> Just $ JSAssignment (JSAccessor (moduleNameToJs name) (JSVar "_ps")) $
56+ JSApp (JSFunction Nothing ["module"] (JSBlock $ jsDecls ++ [JSReturn $ JSVar "module"]))
57+ [JSBinary Or (JSAccessor (moduleNameToJs name) (JSVar "_ps")) (JSObjectLiteral [])]
58+ where
59+ jsDecls = concat $ mapMaybe (\decl -> fmap (map $ optimize opts) $ declToJs opts name decl env) decls
60+
61+-- |
62+-- Generate code in the simplified Javascript intermediate representation for a declaration
63+--
64+declToJs :: Options -> ModuleName -> Declaration -> Environment -> Maybe [JS]
65+declToJs opts mp (ValueDeclaration ident _ _ val) e =
66+ Just [ JSVariableIntroduction (identToJs ident) (Just (valueToJs opts mp e val))
67+ , setExportProperty ident (var ident) ]
68+declToJs opts mp (BindingGroupDeclaration vals) e =
69+ Just $ concatMap (\(ident, val) ->
70+ [ JSVariableIntroduction (identToJs ident) (Just (valueToJs opts mp e val))
71+ , setExportProperty ident (var ident) ]
72+ ) vals
73+declToJs _ mp (DataDeclaration _ _ ctors) _ =
74+ Just $ flip concatMap ctors $ \(pn@(ProperName ctor), tys) ->
75+ [ JSVariableIntroduction ctor (Just (go pn 0 tys []))
76+ , setExportProperty (Escaped ctor) (JSVar ctor) ]
77+ where
78+ go pn _ [] values =
79+ JSObjectLiteral [ ("ctor", JSStringLiteral (show (Qualified (Just mp) pn))), ("values", JSArrayLiteral $ reverse values) ]
80+ go pn index (_ : tys') values =
81+ JSFunction Nothing ["value" ++ show index]
82+ (JSBlock [JSReturn (go pn (index + 1) tys' (JSVar ("value" ++ show index) : values))])
83+declToJs opts mp (DataBindingGroupDeclaration ds) e =
84+ Just $ concat $ mapMaybe (flip (declToJs opts mp) e) ds
85+declToJs _ _ (ExternDeclaration _ ident (Just js) _) _ =
86+ Just [js, setExportProperty ident (var ident)]
87+declToJs _ _ _ _ = Nothing
88+
89+-- |
90+-- Generate code in the simplified Javascript intermediate representation for exporting a
91+-- declaration from a module.
92+--
93+setExportProperty :: Ident -> JS -> JS
94+setExportProperty ident = JSAssignment (accessor ident (JSVar "module"))
95+
96+-- |
97+-- Generate code in the simplified Javascript intermediate representation for a variable based on a
98+-- PureScript identifier.
99+--
100+var :: Ident -> JS
101+var = JSVar . identToJs
102+
103+-- |
104+-- Generate code in the simplified Javascript intermediate representation for an accessor based on
105+-- a PureScript identifier. If the name is not valid in Javascript (symbol based, reserved name) an
106+-- indexer is returned.
107+--
108+accessor :: Ident -> JS -> JS
109+accessor (Ident name) | nameIsJsReserved name = JSIndexer (JSStringLiteral name)
110+accessor (Op op) = JSIndexer (JSStringLiteral op)
111+accessor ident = JSAccessor (identToJs ident)
112+
113+-- |
114+-- Generate code in the simplified Javascript intermediate representation for a value or expression.
115+--
116+valueToJs :: Options -> ModuleName -> Environment -> Value -> JS
117+valueToJs _ _ _ (NumericLiteral n) = JSNumericLiteral n
118+valueToJs _ _ _ (StringLiteral s) = JSStringLiteral s
119+valueToJs _ _ _ (BooleanLiteral b) = JSBooleanLiteral b
120+valueToJs opts m e (ArrayLiteral xs) = JSArrayLiteral (map (valueToJs opts m e) xs)
121+valueToJs opts m e (ObjectLiteral ps) = JSObjectLiteral (map (second (valueToJs opts m e)) ps)
122+valueToJs opts m e (ObjectUpdate o ps) = JSApp (JSAccessor "extend" (JSVar "Object")) [ valueToJs opts m e o, JSObjectLiteral (map (second (valueToJs opts m e)) ps)]
123+valueToJs _ m _ (Constructor name) = qualifiedToJS m (Ident . runProperName) name
124+valueToJs opts m e (Case values binders) = bindersToJs opts m e binders (map (valueToJs opts m e) values)
125+valueToJs opts m e (IfThenElse cond th el) = JSConditional (valueToJs opts m e cond) (valueToJs opts m e th) (valueToJs opts m e el)
126+valueToJs opts m e (Accessor prop val) = JSAccessor prop (valueToJs opts m e val)
127+valueToJs opts m e (App val arg) = JSApp (valueToJs opts m e val) [valueToJs opts m e arg]
128+valueToJs opts m e (Abs (Left arg) val) = JSFunction Nothing [identToJs arg] (JSBlock [JSReturn (valueToJs opts m (bindName m arg e) val)])
129+valueToJs opts m e (TypedValue _ (Abs (Left arg) val) ty) | optionsPerformRuntimeTypeChecks opts = let arg' = identToJs arg in JSFunction Nothing [arg'] (JSBlock $ runtimeTypeChecks arg' ty ++ [JSReturn (valueToJs opts m e val)])
130+valueToJs _ m e (Var ident) = varToJs m e ident
131+valueToJs opts m e (TypedValue _ val _) = valueToJs opts m e val
132+valueToJs _ _ _ (TypeClassDictionary _ _) = error "Type class dictionary was not replaced"
133+valueToJs _ _ _ _ = error "Invalid argument to valueToJs"
134+
135+-- |
136+-- Temporarily extends the environment with a single local variable name
137+--
138+bindName :: ModuleName -> Ident -> Environment -> Environment
139+bindName m ident = bindNames m [ident]
140+
141+-- |
142+-- Temporarily extends the environment to include local variable names introduced by lambda
143+-- abstractions or case statements
144+--
145+bindNames :: ModuleName -> [Ident] -> Environment -> Environment
146+bindNames m idents env = env { names = M.fromList [ ((m, ident), (noType, LocalVariable)) | ident <- idents ] `M.union` names env }
147+ where
148+ noType = error "Temporary lambda variable type was read"
149+
150+
151+-- |
152+-- Generate code in the simplified Javascript intermediate representation for runtime type checks.
153+--
154+runtimeTypeChecks :: String -> Type -> [JS]
155+runtimeTypeChecks arg ty =
156+ let
157+ argTy = getFunctionArgumentType ty
158+ in
159+ maybe [] (argumentCheck (JSVar arg)) argTy
160+ where
161+ getFunctionArgumentType :: Type -> Maybe Type
162+ getFunctionArgumentType (TypeApp (TypeApp t funArg) _) | t == tyFunction = Just funArg
163+ getFunctionArgumentType (ForAll _ ty' _) = getFunctionArgumentType ty'
164+ getFunctionArgumentType _ = Nothing
165+ argumentCheck :: JS -> Type -> [JS]
166+ argumentCheck val t | t == tyNumber = [typeCheck val "number"]
167+ argumentCheck val t | t == tyString = [typeCheck val "string"]
168+ argumentCheck val t | t == tyBoolean = [typeCheck val "boolean"]
169+ argumentCheck val (TypeApp t _) | t == tyArray = [arrayCheck val]
170+ argumentCheck val (Object row) =
171+ let
172+ (pairs, _) = rowToList row
173+ in
174+ typeCheck val "object" : concatMap (\(prop, ty') -> argumentCheck (JSAccessor prop val) ty') pairs
175+ argumentCheck val (TypeApp (TypeApp t _) _) | t == tyFunction = [typeCheck val "function"]
176+ argumentCheck val (ForAll _ ty' _) = argumentCheck val ty'
177+ argumentCheck _ _ = []
178+ typeCheck :: JS -> String -> JS
179+ typeCheck js ty' = JSIfElse (JSBinary NotEqualTo (JSTypeOf js) (JSStringLiteral ty')) (JSBlock [JSThrow (JSStringLiteral $ ty' ++ " expected")]) Nothing
180+ arrayCheck :: JS -> JS
181+ arrayCheck js = JSIfElse (JSUnary Not (JSApp (JSAccessor "isArray" (JSVar "Array")) [js])) (JSBlock [JSThrow (JSStringLiteral "Array expected")]) Nothing
182+
183+-- |
184+-- Generate code in the simplified Javascript intermediate representation for a reference to a
185+-- variable.
186+--
187+varToJs :: ModuleName -> Environment -> Qualified Ident -> JS
188+varToJs m e qual@(Qualified _ ident) = go qual
189+ where
190+ go qual' = case M.lookup (qualify m qual') (names e) of
191+ Just (_, ty) | isExtern ty -> var ident
192+ Just (_, Alias aliasModule aliasIdent) -> go (Qualified (Just aliasModule) aliasIdent)
193+ _ -> case qual' of
194+ Qualified Nothing _ -> var ident
195+ _ -> qualifiedToJS m id qual'
196+ isExtern (Extern ForeignImport) = True
197+ isExtern (Alias m' ident') = case M.lookup (m', ident') (names e) of
198+ Just (_, ty') -> isExtern ty'
199+ Nothing -> error "Undefined alias in varToJs"
200+ isExtern _ = False
201+
202+-- |
203+-- Generate code in the simplified Javascript intermediate representation for a reference to a
204+-- variable that may have a qualified name.
205+--
206+qualifiedToJS :: ModuleName -> (a -> Ident) -> Qualified a -> JS
207+qualifiedToJS m f (Qualified (Just m') a) | m /= m' = accessor (f a) (JSAccessor (moduleNameToJs m') $ JSVar "_ps")
208+qualifiedToJS _ f (Qualified _ a) = JSVar $ identToJs (f a)
209+
210+-- |
211+-- Generate code in the simplified Javascript intermediate representation for pattern match binders
212+-- and guards.
213+--
214+bindersToJs :: Options -> ModuleName -> Environment -> [([Binder], Maybe Guard, Value)] -> [JS] -> JS
215+bindersToJs opts m e binders vals = runGen (map identToJs (unusedNames (binders, vals))) $ do
216+ valNames <- replicateM (length vals) fresh
217+ jss <- forM binders $ \(bs, grd, result) -> go valNames [JSReturn (valueToJs opts m (bindNames m (binderNames bs) e) result)] bs grd
218+ return $ JSApp (JSFunction Nothing valNames (JSBlock (concat jss ++ [JSThrow (JSStringLiteral "Failed pattern match")])))
219+ vals
220+ where
221+ go :: [String] -> [JS] -> [Binder] -> Maybe Guard -> Gen [JS]
222+ go _ done [] Nothing = return done
223+ go _ done [] (Just cond) = return [JSIfElse (valueToJs opts m e cond) (JSBlock done) Nothing]
224+ go (v:vs) done' (b:bs) grd = do
225+ done'' <- go vs done' bs grd
226+ binderToJs m e v done'' b
227+ go _ _ _ _ = error "Invalid arguments to bindersToJs"
228+
229+-- |
230+-- Collect all names introduced in binders in an expression
231+--
232+binderNames :: (Data d) => d -> [Ident]
233+binderNames = everything (++) (mkQ [] go)
234+ where
235+ go (VarBinder ident) = [ident]
236+ go _ = []
237+
238+-- |
239+-- Generate code in the simplified Javascript intermediate representation for a pattern match
240+-- binder.
241+--
242+binderToJs :: ModuleName -> Environment -> String -> [JS] -> Binder -> Gen [JS]
243+binderToJs _ _ _ done NullBinder = return done
244+binderToJs _ _ varName done (StringBinder str) =
245+ return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSStringLiteral str)) (JSBlock done) Nothing]
246+binderToJs _ _ varName done (NumberBinder num) =
247+ return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSNumericLiteral num)) (JSBlock done) Nothing]
248+binderToJs _ _ varName done (BooleanBinder True) =
249+ return [JSIfElse (JSVar varName) (JSBlock done) Nothing]
250+binderToJs _ _ varName done (BooleanBinder False) =
251+ return [JSIfElse (JSUnary Not (JSVar varName)) (JSBlock done) Nothing]
252+binderToJs _ _ varName done (VarBinder ident) =
253+ return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : done)
254+binderToJs m e varName done (ConstructorBinder ctor bs) = do
255+ js <- go 0 done bs
256+ if isOnlyConstructor m e ctor
257+ then
258+ return js
259+ else
260+ return [JSIfElse (JSBinary EqualTo (JSAccessor "ctor" (JSVar varName)) (JSStringLiteral (show ctor)))
261+ (JSBlock js)
262+ Nothing]
263+ where
264+ go :: Integer -> [JS] -> [Binder] -> Gen [JS]
265+ go _ done' [] = return done'
266+ go index done' (binder:bs') = do
267+ argVar <- fresh
268+ done'' <- go (index + 1) done' bs'
269+ js <- binderToJs m e argVar done'' binder
270+ return (JSVariableIntroduction argVar (Just (JSIndexer (JSNumericLiteral (Left index)) (JSAccessor "values" (JSVar varName)))) : js)
271+binderToJs m e varName done (ObjectBinder bs) = go done bs
272+ where
273+ go :: [JS] -> [(String, Binder)] -> Gen [JS]
274+ go done' [] = return done'
275+ go done' ((prop, binder):bs') = do
276+ propVar <- fresh
277+ done'' <- go done' bs'
278+ js <- binderToJs m e propVar done'' binder
279+ return (JSVariableIntroduction propVar (Just (JSAccessor prop (JSVar varName))) : js)
280+binderToJs m e varName done (ArrayBinder bs) = do
281+ js <- go done 0 bs
282+ return [JSIfElse (JSBinary EqualTo (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left (fromIntegral $ length bs)))) (JSBlock js) Nothing]
283+ where
284+ go :: [JS] -> Integer -> [Binder] -> Gen [JS]
285+ go done' _ [] = return done'
286+ go done' index (binder:bs') = do
287+ elVar <- fresh
288+ done'' <- go done' (index + 1) bs'
289+ js <- binderToJs m e elVar done'' binder
290+ return (JSVariableIntroduction elVar (Just (JSIndexer (JSNumericLiteral (Left index)) (JSVar varName))) : js)
291+binderToJs m e varName done (ConsBinder headBinder tailBinder) = do
292+ headVar <- fresh
293+ tailVar <- fresh
294+ js1 <- binderToJs m e headVar done headBinder
295+ js2 <- binderToJs m e tailVar js1 tailBinder
296+ return [JSIfElse (JSBinary GreaterThan (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left 0))) (JSBlock
297+ ( JSVariableIntroduction headVar (Just (JSIndexer (JSNumericLiteral (Left 0)) (JSVar varName))) :
298+ JSVariableIntroduction tailVar (Just (JSApp (JSAccessor "slice" (JSVar varName)) [JSNumericLiteral (Left 1)])) :
299+ js2
300+ )) Nothing]
301+binderToJs m e varName done (NamedBinder ident binder) = do
302+ js <- binderToJs m e varName done binder
303+ return (JSVariableIntroduction (identToJs ident) (Just (JSVar varName)) : js)
304+
305+-- |
306+-- Checks whether a data constructor is the only constructor for that type, used to simplify the
307+-- check when generating code for binders.
308+--
309+isOnlyConstructor :: ModuleName -> Environment -> Qualified ProperName -> Bool
310+isOnlyConstructor m e ctor =
311+ let ty = fromMaybe (error "Data constructor not found") $ ctor `M.lookup` dataConstructors e
312+ in numConstructors ty == 1
313+ where
314+ numConstructors ty = length $ filter (((==) `on` typeConstructor) ty) $ M.elems $ dataConstructors e
315+ typeConstructor (TypeConstructor qual) = qualify m qual
316+ typeConstructor (ForAll _ ty _) = typeConstructor ty
317+ typeConstructor (TypeApp (TypeApp t _) ty) | t == tyFunction = typeConstructor ty
318+ typeConstructor (TypeApp ty _) = typeConstructor ty
319+ typeConstructor fn = error $ "Invalid arguments to typeConstructor: " ++ show fn
320+
321+wrapExportsContainer :: Options -> [JS] -> JS
322+wrapExportsContainer opts modules = JSApp (JSFunction Nothing ["_ps"] $ JSBlock $ JSStringLiteral "use strict" : modules) [exportSelector]
323+ where
324+ exportSelector = JSConditional (JSBinary And (JSBinary NotEqualTo (JSTypeOf $ JSVar "module") (JSStringLiteral "undefined")) (JSAccessor "exports" (JSVar "module")))
325+ (JSAccessor "exports" (JSVar "module"))
326+ (JSConditional (JSBinary NotEqualTo (JSTypeOf $ JSVar "window") (JSStringLiteral "undefined"))
327+ (JSAssignment (JSAccessor browserNamespace (JSVar "window")) (JSBinary Or (JSAccessor browserNamespace (JSVar "window")) (JSObjectLiteral [])))
328+ (JSApp (JSFunction Nothing [] $ JSBlock [JSThrow $ JSStringLiteral "PureScript doesn't know how to export modules in the current environment"]) []))
329+ browserNamespace = optionsBrowserNamespace opts
src/Language/PureScript/CodeGen/JS/AST.hsnew file+233
@@ -0,0 +1,233 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.CodeGen.JS.AST
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+-- Data types for the intermediate simplified-Javascript AST
13+--
14+-----------------------------------------------------------------------------
15+
16+{-# LANGUAGE DeriveDataTypeable #-}
17+
18+module Language.PureScript.CodeGen.JS.AST where
19+
20+import Data.Data
21+
22+
23+
24+-- |
25+-- Built-in unary operators
26+--
27+data UnaryOperator
28+ -- |
29+ -- Numeric negation
30+ --
31+ = Negate
32+ -- |
33+ -- Boolean negation
34+ --
35+ | Not
36+ -- |
37+ -- Bitwise negation
38+ --
39+ | BitwiseNot
40+ -- |
41+ -- Numeric unary \'plus\'
42+ --
43+ | Positive deriving (Show, Eq, Data, Typeable)
44+
45+-- |
46+-- Built-in binary operators
47+--
48+data BinaryOperator
49+ -- |
50+ -- Numeric addition
51+ --
52+ = Add
53+ -- |
54+ -- Numeric subtraction
55+ --
56+ | Subtract
57+ -- |
58+ -- Numeric multiplication
59+ --
60+ | Multiply
61+ -- |
62+ -- Numeric division
63+ --
64+ | Divide
65+ -- |
66+ -- Remainder
67+ --
68+ | Modulus
69+ -- |
70+ -- Generic equality test
71+ --
72+ | EqualTo
73+ -- |
74+ -- Generic inequality test
75+ --
76+ | NotEqualTo
77+ -- |
78+ -- Numeric less-than
79+ --
80+ | LessThan
81+ -- |
82+ -- Numeric less-than-or-equal
83+ --
84+ | LessThanOrEqualTo
85+ -- |
86+ -- Numeric greater-than
87+ --
88+ | GreaterThan
89+ -- |
90+ -- Numeric greater-than-or-equal
91+ --
92+ | GreaterThanOrEqualTo
93+ -- |
94+ -- Boolean and
95+ --
96+ | And
97+ -- |
98+ -- Boolean or
99+ --
100+ | Or
101+ -- |
102+ -- Bitwise and
103+ --
104+ | BitwiseAnd
105+ -- |
106+ -- Bitwise or
107+ --
108+ | BitwiseOr
109+ -- |
110+ -- Bitwise xor
111+ --
112+ | BitwiseXor
113+ -- |
114+ -- Bitwise left shift
115+ --
116+ | ShiftLeft
117+ -- |
118+ -- Bitwise right shift
119+ --
120+ | ShiftRight
121+ -- |
122+ -- Bitwise right shift with zero-fill
123+ --
124+ | ZeroFillShiftRight deriving (Show, Eq, Data, Typeable)
125+
126+-- |
127+-- Data type for simplified Javascript expressions
128+--
129+data JS
130+ -- |
131+ -- A numeric literal
132+ --
133+ = JSNumericLiteral (Either Integer Double)
134+ -- |
135+ -- A string literal
136+ --
137+ | JSStringLiteral String
138+ -- |
139+ -- A boolean literal
140+ --
141+ | JSBooleanLiteral Bool
142+ -- |
143+ -- A unary operator application
144+ --
145+ | JSUnary UnaryOperator JS
146+ -- |
147+ -- A binary operator application
148+ --
149+ | JSBinary BinaryOperator JS JS
150+ -- |
151+ -- An array literal
152+ --
153+ | JSArrayLiteral [JS]
154+ -- |
155+ -- An array indexer expression
156+ --
157+ | JSIndexer JS JS
158+ -- |
159+ -- An object literal
160+ --
161+ | JSObjectLiteral [(String, JS)]
162+ -- |
163+ -- An object property accessor expression
164+ --
165+ | JSAccessor String JS
166+ -- |
167+ -- A function introduction (optional name, arguments, body)
168+ --
169+ | JSFunction (Maybe String) [String] JS
170+ -- |
171+ -- Function application
172+ --
173+ | JSApp JS [JS]
174+ -- |
175+ -- Variable
176+ --
177+ | JSVar String
178+ -- |
179+ -- Conditional expression
180+ --
181+ | JSConditional JS JS JS
182+ -- |
183+ -- A block of expressions in braces
184+ --
185+ | JSBlock [JS]
186+ -- |
187+ -- A variable introduction and optional initialization
188+ --
189+ | JSVariableIntroduction String (Maybe JS)
190+ -- |
191+ -- A variable assignment
192+ --
193+ | JSAssignment JS JS
194+ -- |
195+ -- While loop
196+ --
197+ | JSWhile JS JS
198+ -- |
199+ -- For loop
200+ --
201+ | JSFor String JS JS JS
202+ -- |
203+ -- If-then-else statement
204+ --
205+ | JSIfElse JS JS (Maybe JS)
206+ -- |
207+ -- Return statement
208+ --
209+ | JSReturn JS
210+ -- |
211+ -- Throw statement
212+ --
213+ | JSThrow JS
214+ -- |
215+ -- Type-Of operator
216+ --
217+ | JSTypeOf JS
218+ -- |
219+ -- Labelled statement
220+ --
221+ | JSLabel String JS
222+ -- |
223+ -- Break statement
224+ --
225+ | JSBreak String
226+ -- |
227+ -- Continue statement
228+ --
229+ | JSContinue String
230+ -- |
231+ -- Raw Javascript (generated when parsing fails for an inline foreign import declaration)
232+ --
233+ | JSRaw String deriving (Show, Eq, Data, Typeable)
src/Language/PureScript/CodeGen/Monad.hsnew file+43
@@ -0,0 +1,43 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.CodeGen.Monad
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+-- Code generation monad
13+--
14+-- This monad provides a supply of fresh names which can be used to create variables.
15+--
16+-----------------------------------------------------------------------------
17+
18+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
19+
20+module Language.PureScript.CodeGen.Monad where
21+
22+import Control.Monad.State
23+import Control.Applicative
24+
25+-- |
26+-- Code generation monad data type
27+--
28+newtype Gen a = Gen { unGen :: State [String] a } deriving (Functor, Applicative, Monad, MonadState [String])
29+
30+-- |
31+-- Run a computation in the code generation monad
32+--
33+runGen :: [String] -> Gen a -> a
34+runGen names = flip evalState names . unGen
35+
36+-- |
37+-- Generate a fresh name
38+--
39+fresh :: Gen String
40+fresh = do
41+ (s:ss) <- get
42+ put ss
43+ return s
src/Language/PureScript/CodeGen/Optimize.hsnew file+472
@@ -0,0 +1,472 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Optimize
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+-- This module optimizes code in the simplified-Javascript intermediate representation.
13+--
14+-- The following optimizations are supported:
15+--
16+-- * Collapsing nested blocks
17+--
18+-- * Tail call elimination
19+--
20+-- * Inlining of (>>=) and ret for the Eff monad
21+--
22+-- * Removal of unused variables
23+--
24+-- * Removal of unnecessary thunks
25+--
26+-- * Eta conversion
27+--
28+-- * Inlining variables
29+--
30+-- * Inline Prelude.($), Prelude.(#), Prelude.(++), Prelude.(!!)
31+--
32+-- * Inlining primitive Javascript operators
33+--
34+-----------------------------------------------------------------------------
35+
36+module Language.PureScript.CodeGen.Optimize (
37+ optimize
38+) where
39+
40+import Data.Data
41+import Data.List (nub)
42+import Data.Maybe (fromJust, isJust, fromMaybe)
43+import Data.Generics
44+
45+import Language.PureScript.Names
46+import Language.PureScript.CodeGen.JS.AST
47+import Language.PureScript.Options
48+import Language.PureScript.CodeGen.Common (identToJs)
49+import Language.PureScript.Sugar.TypeClasses
50+ (mkDictionaryValueName)
51+import Language.PureScript.Types
52+
53+-- |
54+-- Apply a series of optimizer passes to simplified Javascript code
55+--
56+optimize :: Options -> JS -> JS
57+optimize opts | optionsNoOptimizations opts = id
58+ | otherwise = untilFixedPoint $ applyAll
59+ [ collapseNestedBlocks
60+ , tco opts
61+ , magicDo opts
62+ , removeUnusedVariables
63+ , unThunk
64+ , etaConvert
65+ , inlineVariables
66+ , inlineOperator "$" $ \f x -> JSApp f [x]
67+ , inlineOperator "#" $ \x f -> JSApp f [x]
68+ , inlineOperator "!!" $ flip JSIndexer
69+ , inlineOperator "++" $ JSBinary Add
70+ , inlineCommonOperators ]
71+
72+applyAll :: [a -> a] -> a -> a
73+applyAll = foldl1 (.)
74+
75+untilFixedPoint :: (Eq a) => (a -> a) -> a -> a
76+untilFixedPoint f = go
77+ where
78+ go a = let a' = f a in
79+ if a' == a then a' else go a'
80+
81+replaceIdent :: (Data d) => String -> JS -> d -> d
82+replaceIdent var1 js = everywhere (mkT replace)
83+ where
84+ replace (JSVar var2) | var1 == var2 = js
85+ replace other = other
86+
87+replaceIdents :: (Data d) => [(String, JS)] -> d -> d
88+replaceIdents vars = everywhere (mkT replace)
89+ where
90+ replace v@(JSVar var) = fromMaybe v $ lookup var vars
91+ replace other = other
92+
93+isReassigned :: (Data d) => String -> d -> Bool
94+isReassigned var1 = everything (||) (mkQ False check)
95+ where
96+ check :: JS -> Bool
97+ check (JSFunction _ args _) | var1 `elem` args = True
98+ check (JSVariableIntroduction arg _) | var1 == arg = True
99+ check (JSAssignment (JSVar arg) _) | var1 == arg = True
100+ check _ = False
101+
102+isRebound :: (Data d) => JS -> d -> Bool
103+isRebound js d = any (`isReassigned` d) (everything (++) (mkQ [] variablesOf) js)
104+ where
105+ variablesOf (JSVar var) = [var]
106+ variablesOf _ = []
107+
108+isUsed :: (Data d) => String -> d -> Bool
109+isUsed var1 = everything (||) (mkQ False check)
110+ where
111+ check :: JS -> Bool
112+ check (JSVar var2) | var1 == var2 = True
113+ check (JSAssignment target _) | var1 == targetVariable target = True
114+ check _ = False
115+
116+targetVariable :: JS -> String
117+targetVariable (JSVar var) = var
118+targetVariable (JSAccessor _ tgt) = targetVariable tgt
119+targetVariable (JSIndexer _ tgt) = targetVariable tgt
120+targetVariable _ = error "Invalid argument to targetVariable"
121+
122+isUpdated :: (Data d) => String -> d -> Bool
123+isUpdated var1 = everything (||) (mkQ False check)
124+ where
125+ check :: JS -> Bool
126+ check (JSAssignment target _) | var1 == targetVariable target = True
127+ check _ = False
128+
129+shouldInline :: JS -> Bool
130+shouldInline (JSVar _) = True
131+shouldInline (JSNumericLiteral _) = True
132+shouldInline (JSStringLiteral _) = True
133+shouldInline (JSBooleanLiteral _) = True
134+shouldInline (JSAccessor _ val) = shouldInline val
135+shouldInline (JSIndexer index val) = shouldInline index && shouldInline val
136+shouldInline _ = False
137+
138+removeFromBlock :: ([JS] -> [JS]) -> JS -> JS
139+removeFromBlock go (JSBlock sts) = JSBlock (go sts)
140+removeFromBlock _ js = js
141+
142+inlineVariables :: JS -> JS
143+inlineVariables = everywhere (mkT $ removeFromBlock go)
144+ where
145+ go :: [JS] -> [JS]
146+ go [] = []
147+ go (JSVariableIntroduction var (Just js) : sts)
148+ | shouldInline js && not (isReassigned var sts) && not (isRebound js sts) && not (isUpdated var sts) =
149+ go (replaceIdent var js sts)
150+ go (s:sts) = s : go sts
151+
152+removeUnusedVariables :: JS -> JS
153+removeUnusedVariables = everywhere (mkT $ removeFromBlock go)
154+ where
155+ go :: [JS] -> [JS]
156+ go [] = []
157+ go (JSVariableIntroduction var _ : sts) | not (isUsed var sts) = go sts
158+ go (s:sts) = s : go sts
159+
160+etaConvert :: JS -> JS
161+etaConvert = everywhere (mkT convert)
162+ where
163+ convert :: JS -> JS
164+ convert (JSBlock [JSReturn (JSApp (JSFunction Nothing idents block@(JSBlock body)) args)])
165+ | all shouldInline args &&
166+ not (any (`isRebound` block) (map JSVar idents)) &&
167+ not (any (`isRebound` block) args)
168+ = JSBlock (replaceIdents (zip idents args) body)
169+ convert js = js
170+
171+unThunk :: JS -> JS
172+unThunk = everywhere (mkT convert)
173+ where
174+ convert :: JS -> JS
175+ convert (JSBlock [JSReturn (JSApp (JSFunction Nothing [] (JSBlock body)) [])]) = JSBlock body
176+ convert js = js
177+
178+tco :: Options -> JS -> JS
179+tco opts | optionsTco opts = tco'
180+ | otherwise = id
181+
182+tco' :: JS -> JS
183+tco' = everywhere (mkT convert)
184+ where
185+ tcoLabel :: String
186+ tcoLabel = "tco"
187+ tcoVar :: String -> String
188+ tcoVar arg = "__tco_" ++ arg
189+ copyVar :: String -> String
190+ copyVar arg = "__copy_" ++ arg
191+ convert :: JS -> JS
192+ convert js@(JSVariableIntroduction name (Just fn@JSFunction {})) =
193+ let
194+ (argss, body', replace) = collectAllFunctionArgs [] id fn
195+ in case () of
196+ _ | isTailCall name body' ->
197+ let
198+ allArgs = reverse $ concat argss
199+ in
200+ JSVariableIntroduction name (Just (replace (toLoop name allArgs body')))
201+ | otherwise -> js
202+ convert js = js
203+ collectAllFunctionArgs :: [[String]] -> (JS -> JS) -> JS -> ([[String]], JS, JS -> JS)
204+ collectAllFunctionArgs allArgs f (JSFunction ident args (JSBlock (body@(JSReturn _):_))) =
205+ collectAllFunctionArgs (args : allArgs) (\b -> f (JSFunction ident (map copyVar args) (JSBlock [b]))) body
206+ collectAllFunctionArgs allArgs f (JSFunction ident args body@(JSBlock _)) =
207+ (args : allArgs, body, f . JSFunction ident (map copyVar args))
208+ collectAllFunctionArgs allArgs f (JSReturn (JSFunction ident args (JSBlock [body]))) =
209+ collectAllFunctionArgs (args : allArgs) (\b -> f (JSReturn (JSFunction ident (map copyVar args) (JSBlock [b])))) body
210+ collectAllFunctionArgs allArgs f (JSReturn (JSFunction ident args body@(JSBlock _))) =
211+ (args : allArgs, body, f . JSReturn . JSFunction ident (map copyVar args))
212+ collectAllFunctionArgs allArgs f body = (allArgs, body, f)
213+ isTailCall :: String -> JS -> Bool
214+ isTailCall ident js =
215+ let
216+ numSelfCalls = everything (+) (mkQ 0 countSelfCalls) js
217+ numSelfCallsInTailPosition = everything (+) (mkQ 0 countSelfCallsInTailPosition) js
218+ numSelfCallsUnderFunctions = everything (+) (mkQ 0 countSelfCallsUnderFunctions) js
219+ in
220+ numSelfCalls > 0
221+ && numSelfCalls == numSelfCallsInTailPosition
222+ && numSelfCallsUnderFunctions == 0
223+ where
224+ countSelfCalls :: JS -> Int
225+ countSelfCalls (JSApp (JSVar ident') _) | ident == ident' = 1
226+ countSelfCalls _ = 0
227+ countSelfCallsInTailPosition :: JS -> Int
228+ countSelfCallsInTailPosition (JSReturn ret) | isSelfCall ident ret = 1
229+ countSelfCallsInTailPosition _ = 0
230+ countSelfCallsUnderFunctions (JSFunction _ _ js') = everything (+) (mkQ 0 countSelfCalls) js'
231+ countSelfCallsUnderFunctions _ = 0
232+ toLoop :: String -> [String] -> JS -> JS
233+ toLoop ident allArgs js = JSBlock $
234+ map (\arg -> JSVariableIntroduction arg (Just (JSVar (copyVar arg)))) allArgs ++
235+ [ JSLabel tcoLabel $ JSWhile (JSBooleanLiteral True) (JSBlock [ everywhere (mkT loopify) js ]) ]
236+ where
237+ loopify :: JS -> JS
238+ loopify (JSReturn ret) | isSelfCall ident ret =
239+ let
240+ allArgumentValues = concat $ collectSelfCallArgs [] ret
241+ in
242+ JSBlock $ zipWith (\val arg ->
243+ JSVariableIntroduction (tcoVar arg) (Just val)) allArgumentValues allArgs
244+ ++ map (\arg ->
245+ JSAssignment (JSVar arg) (JSVar (tcoVar arg))) allArgs
246+ ++ [ JSContinue tcoLabel ]
247+ loopify other = other
248+ collectSelfCallArgs :: [[JS]] -> JS -> [[JS]]
249+ collectSelfCallArgs allArgumentValues (JSApp fn args') = collectSelfCallArgs (args' : allArgumentValues) fn
250+ collectSelfCallArgs allArgumentValues _ = allArgumentValues
251+ isSelfCall :: String -> JS -> Bool
252+ isSelfCall ident (JSApp (JSVar ident') _) | ident == ident' = True
253+ isSelfCall ident (JSApp fn _) = isSelfCall ident fn
254+ isSelfCall _ _ = False
255+
256+magicDo :: Options -> JS -> JS
257+magicDo opts | optionsMagicDo opts = inlineST . magicDo'
258+ | otherwise = id
259+
260+-- |
261+-- Inline type class dictionaries for >>= and return for the Eff monad
262+--
263+-- E.g.
264+--
265+-- Prelude[">>="](dict)(m1)(function(x) {
266+-- return ...;
267+-- })
268+--
269+-- becomes
270+--
271+-- function __do {
272+-- var x = m1();
273+-- ...
274+-- }
275+--
276+magicDo' :: JS -> JS
277+magicDo' = everywhere (mkT undo) . everywhere' (mkT convert)
278+ where
279+ -- The name of the function block which is added to denote a do block
280+ fnName = "__do"
281+ -- Desugar monomorphic calls to >>= and return for the Eff monad
282+ convert :: JS -> JS
283+ -- Desugar return
284+ convert (JSApp (JSApp ret [val]) []) | isReturn ret = val
285+ -- Desugae >>
286+ convert (JSApp (JSApp bind [m]) [JSFunction Nothing ["_"] (JSBlock [JSReturn ret])]) | isBind bind =
287+ JSFunction (Just fnName) [] $ JSBlock [ JSApp m [], JSReturn (JSApp ret []) ]
288+ -- Desugar >>=
289+ convert (JSApp (JSApp bind [m]) [JSFunction Nothing [arg] (JSBlock [JSReturn ret])]) | isBind bind =
290+ JSFunction (Just fnName) [] $ JSBlock [ JSVariableIntroduction arg (Just (JSApp m [])), JSReturn (JSApp ret []) ]
291+ -- Desugar untilE
292+ convert (JSApp (JSApp f [arg]) []) | isEffFunc "untilE" f =
293+ JSApp (JSFunction Nothing [] (JSBlock [ JSWhile (JSUnary Not (JSApp arg [])) (JSBlock []), JSReturn (JSObjectLiteral []) ])) []
294+ -- Desugar whileE
295+ convert (JSApp (JSApp (JSApp f [arg1]) [arg2]) []) | isEffFunc "whileE" f =
296+ JSApp (JSFunction Nothing [] (JSBlock [ JSWhile (JSApp arg1 []) (JSBlock [ JSApp arg2 [] ]), JSReturn (JSObjectLiteral []) ])) []
297+ convert other = other
298+ -- Check if an expression represents a monomorphic call to >>= for the Eff monad
299+ isBind (JSApp bindPoly [effDict]) | isBindPoly bindPoly && isEffDict effDict = True
300+ isBind _ = False
301+ -- Check if an expression represents a monomorphic call to return for the Eff monad
302+ isReturn (JSApp retPoly [effDict]) | isRetPoly retPoly && isEffDict effDict = True
303+ isReturn _ = False
304+ -- Check if an expression represents the polymorphic >>= function
305+ isBindPoly (JSAccessor prop (JSAccessor "Prelude" (JSVar "_ps"))) | prop == identToJs (Op ">>=") = True
306+ isBindPoly (JSIndexer (JSStringLiteral ">>=") (JSAccessor "Prelude" (JSVar "_ps"))) = True
307+ isBindPoly _ = False
308+ -- Check if an expression represents the polymorphic return function
309+ isRetPoly (JSAccessor "$return" (JSAccessor "Prelude" (JSVar "_ps"))) = True
310+ isRetPoly (JSIndexer (JSStringLiteral "return") (JSAccessor "Prelude" (JSVar "_ps"))) = True
311+ isRetPoly _ = False
312+ -- Check if an expression represents a function in the Ef module
313+ isEffFunc name (JSAccessor name' (JSAccessor "Control_Monad_Eff" (JSVar "_ps"))) | name == name' = True
314+ isEffFunc _ _ = False
315+ -- Module names
316+ prelude = ModuleName [ProperName "Prelude"]
317+ effModule = ModuleName [ProperName "Control", ProperName "Monad", ProperName "Eff"]
318+ -- The name of the type class dictionary for the Monad Eff instance
319+ Right (Ident effDictName) = mkDictionaryValueName
320+ effModule
321+ (Qualified (Just prelude) (ProperName "Monad"))
322+ [TypeConstructor (Qualified (Just effModule) (ProperName "Eff"))]
323+ -- Check if an expression represents the Monad Eff dictionary
324+ isEffDict (JSApp (JSVar ident) [JSObjectLiteral []]) | ident == effDictName = True
325+ isEffDict (JSApp (JSAccessor prop (JSAccessor "Control_Monad_Eff" (JSVar "_ps"))) [JSObjectLiteral []]) | prop == effDictName = True
326+ isEffDict _ = False
327+ -- Remove __do function applications which remain after desugaring
328+ undo :: JS -> JS
329+ undo (JSReturn (JSApp (JSFunction (Just ident) [] body) [])) | ident == fnName = body
330+ undo other = other
331+
332+-- |
333+-- Inline functions in the ST module
334+--
335+inlineST :: JS -> JS
336+inlineST = everywhere (mkT convertBlock)
337+ where
338+ -- Look for runST blocks and inline the STRefs there.
339+ -- If all STRefs are used in the scope of the same runST, only using { read, write, modify }STRef then
340+ -- we can be more aggressive about inlining, and actually turn STRefs into local variables.
341+ convertBlock (JSApp f [arg]) | isSTFunc "runST" f || isSTFunc "runSTArray" f =
342+ let refs = nub . findSTRefsIn $ arg
343+ usages = findAllSTUsagesIn arg
344+ allUsagesAreLocalVars = all (\u -> let v = toVar u in isJust v && fromJust v `elem` refs) usages
345+ localVarsDoNotEscape = all (\r -> length (r `appearingIn` arg) == length (filter (\u -> let v = toVar u in v == Just r) usages)) refs
346+ in everywhere (mkT $ convert (allUsagesAreLocalVars && localVarsDoNotEscape)) arg
347+ convertBlock other = other
348+ -- Convert a block in a safe way, preserving object wrappers of references,
349+ -- or in a more aggressive way, turning wrappers into local variables depending on the
350+ -- agg(ressive) parameter.
351+ convert agg (JSApp (JSApp f [arg]) []) | isSTFunc "newSTRef" f =
352+ if agg then arg else JSObjectLiteral [("value", arg)]
353+ convert agg (JSApp (JSApp f [ref]) []) | isSTFunc "readSTRef" f =
354+ if agg then ref else JSAccessor "value" ref
355+ convert agg (JSApp (JSApp (JSApp f [ref]) [arg]) []) | isSTFunc "writeSTRef" f =
356+ if agg then JSAssignment ref arg else JSAssignment (JSAccessor "value" ref) arg
357+ convert agg (JSApp (JSApp (JSApp f [ref]) [func]) []) | isSTFunc "modifySTRef" f =
358+ if agg then JSAssignment ref (JSApp func [ref]) else JSAssignment (JSAccessor "value" ref) (JSApp func [JSAccessor "value" ref])
359+ convert _ (JSApp (JSApp (JSApp f [arr]) [i]) []) | isSTFunc "peekSTArray" f =
360+ JSIndexer i arr
361+ convert _ (JSApp (JSApp (JSApp (JSApp f [arr]) [i]) [val]) []) | isSTFunc "pokeSTArray" f =
362+ JSAssignment (JSIndexer i arr) val
363+ convert _ other = other
364+ -- Check if an expression represents a function in the ST module
365+ isSTFunc name (JSAccessor name' (JSAccessor "Control_Monad_ST" (JSVar "_ps"))) | name == name' = True
366+ isSTFunc _ _ = False
367+ -- Find all ST Refs initialized in this block
368+ findSTRefsIn = everything (++) (mkQ [] isSTRef)
369+ where
370+ isSTRef (JSVariableIntroduction ident (Just (JSApp (JSApp f [_]) []))) | isSTFunc "newSTRef" f = [ident]
371+ isSTRef _ = []
372+ -- Find all STRefs used as arguments to readSTRef, writeSTRef, modifySTRef
373+ findAllSTUsagesIn = everything (++) (mkQ [] isSTUsage)
374+ where
375+ isSTUsage (JSApp (JSApp f [ref]) []) | isSTFunc "readSTRef" f = [ref]
376+ isSTUsage (JSApp (JSApp (JSApp f [ref]) [_]) []) | isSTFunc "writeSTRef" f || isSTFunc "modifySTRef" f = [ref]
377+ isSTUsage _ = []
378+ -- Find all uses of a variable
379+ appearingIn ref = everything (++) (mkQ [] isVar)
380+ where
381+ isVar e@(JSVar v) | v == ref = [e]
382+ isVar _ = []
383+ -- Convert a JS value to a String if it is a JSVar
384+ toVar (JSVar v) = Just v
385+ toVar _ = Nothing
386+
387+collapseNestedBlocks :: JS -> JS
388+collapseNestedBlocks = everywhere (mkT collapse)
389+ where
390+ collapse :: JS -> JS
391+ collapse (JSBlock sts) = JSBlock (concatMap go sts)
392+ collapse js = js
393+ go :: JS -> [JS]
394+ go (JSBlock sts) = sts
395+ go s = [s]
396+
397+inlineOperator :: String -> (JS -> JS -> JS) -> JS -> JS
398+inlineOperator op f = everywhere (mkT convert)
399+ where
400+ convert :: JS -> JS
401+ convert (JSApp (JSApp op' [x]) [y]) | isOp op' = f x y
402+ convert other = other
403+ isOp (JSAccessor longForm (JSAccessor "Prelude" (JSVar "_ps"))) | longForm == identToJs (Op op) = True
404+ isOp (JSIndexer (JSStringLiteral op') (JSAccessor "Prelude" (JSVar "_ps"))) | op == op' = True
405+ isOp _ = False
406+
407+inlineCommonOperators :: JS -> JS
408+inlineCommonOperators = applyAll
409+ [ binary "+" "Num" tyNumber Add
410+ , binary "-" "Num" tyNumber Subtract
411+ , binary "*" "Num" tyNumber Multiply
412+ , binary "/" "Num" tyNumber Divide
413+ , binary "%" "Num" tyNumber Modulus
414+ , unary "negate" "Num" tyNumber Negate
415+
416+ , binary "<" "Ord" tyNumber LessThan
417+ , binary ">" "Ord" tyNumber GreaterThan
418+ , binary "<=" "Ord" tyNumber LessThanOrEqualTo
419+ , binary ">=" "Ord" tyNumber GreaterThanOrEqualTo
420+
421+ , binary "==" "Eq" tyNumber EqualTo
422+ , binary "/=" "Eq" tyNumber NotEqualTo
423+ , binary "==" "Eq" tyString EqualTo
424+ , binary "/=" "Eq" tyString NotEqualTo
425+ , binary "==" "Eq" tyBoolean EqualTo
426+ , binary "/=" "Eq" tyBoolean NotEqualTo
427+
428+ , binaryFunction "shl" "Bits" tyNumber ShiftLeft
429+ , binaryFunction "shr" "Bits" tyNumber ShiftRight
430+ , binaryFunction "zshr" "Bits" tyNumber ZeroFillShiftRight
431+ , binary "&" "Bits" tyNumber BitwiseAnd
432+ , binary "|" "Bits" tyNumber BitwiseOr
433+ , binary "^" "Bits" tyNumber BitwiseXor
434+ , unary "complement" "Bits" tyNumber BitwiseNot
435+
436+ , binary "&&" "BoolLike" tyBoolean And
437+ , binary "||" "BoolLike" tyBoolean Or
438+ , unary "not" "BoolLike" tyBoolean Not
439+ ]
440+ where
441+ binary :: String -> String -> Type -> BinaryOperator -> JS -> JS
442+ binary opString className classTy op = everywhere (mkT convert)
443+ where
444+ convert :: JS -> JS
445+ convert (JSApp (JSApp (JSApp fn [dict]) [x]) [y]) | isOp fn && isOpDict className classTy dict = JSBinary op x y
446+ convert other = other
447+ isOp (JSAccessor longForm (JSAccessor "Prelude" (JSVar _))) | longForm == identToJs (Op opString) = True
448+ isOp (JSIndexer (JSStringLiteral op') (JSAccessor "Prelude" (JSVar "_ps"))) | opString == op' = True
449+ isOp _ = False
450+ binaryFunction :: String -> String -> Type -> BinaryOperator -> JS -> JS
451+ binaryFunction fnName className classTy op = everywhere (mkT convert)
452+ where
453+ convert :: JS -> JS
454+ convert (JSApp (JSApp (JSApp fn [dict]) [x]) [y]) | isOp fn && isOpDict className classTy dict = JSBinary op x y
455+ convert other = other
456+ isOp (JSAccessor fnName' (JSAccessor "Prelude" (JSVar "_ps"))) | fnName == fnName' = True
457+ isOp _ = False
458+ unary :: String -> String -> Type -> UnaryOperator -> JS -> JS
459+ unary fnName className classTy op = everywhere (mkT convert)
460+ where
461+ convert :: JS -> JS
462+ convert (JSApp (JSApp fn [dict]) [x]) | isOp fn && isOpDict className classTy dict = JSUnary op x
463+ convert other = other
464+ isOp (JSAccessor fnName' (JSAccessor "Prelude" (JSVar "_ps"))) | fnName' == fnName = True
465+ isOp _ = False
466+ isOpDict className ty (JSApp (JSAccessor prop (JSAccessor "Prelude" (JSVar "_ps"))) [JSObjectLiteral []]) | prop == dictName = True
467+ where
468+ Right (Ident dictName) = mkDictionaryValueName
469+ (ModuleName [ProperName "Prim"])
470+ (Qualified (Just (ModuleName [ProperName "Prelude"])) (ProperName className))
471+ [ty]
472+ isOpDict _ _ _ = False
src/Language/PureScript/DeadCodeElimination.hsnew file+77
@@ -0,0 +1,77 @@
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+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module Language.PureScript.DeadCodeElimination (
16+ eliminateDeadCode
17+) where
18+
19+import Data.Data
20+import Data.List
21+import Data.Graph
22+import Data.Generics
23+import Data.Maybe (mapMaybe)
24+
25+import Language.PureScript.Names
26+import Language.PureScript.Values
27+import Language.PureScript.Declarations
28+import Language.PureScript.TypeChecker.Monad
29+
30+-- |
31+-- Eliminate all declarations which are not a transitive dependency of the entry point module
32+--
33+eliminateDeadCode :: Environment -> [ModuleName] -> [Module] -> [Module]
34+eliminateDeadCode env entryPoints ms =
35+ let declarations = concatMap (declarationsByModule env) ms
36+ (graph, _, vertexFor) = graphFromEdges $ map (\(key, deps) -> (key, key, deps)) declarations
37+ entryPointVertices = mapMaybe (vertexFor . fst) . filter (\((mn, _), _) -> mn `elem` entryPoints) $ declarations
38+ in flip map ms $ \(Module moduleName ds) -> Module moduleName (filter (isUsed moduleName graph vertexFor entryPointVertices) ds)
39+
40+type Key = (ModuleName, Either Ident ProperName)
41+
42+declarationsByModule :: Environment -> Module -> [(Key, [Key])]
43+declarationsByModule env (Module moduleName ds) = concatMap go ds
44+ where
45+ go :: Declaration -> [(Key, [Key])]
46+ go d@(ValueDeclaration name _ _ _) = [((moduleName, Left name), dependencies env moduleName d)]
47+ go (DataDeclaration _ _ dctors) = map (\(name, _) -> ((moduleName, Right name), [])) dctors
48+ go (ExternDeclaration _ name _ _) = [((moduleName, Left name), [])]
49+ go d@(BindingGroupDeclaration names') = map (\(name, _) -> ((moduleName, Left name), dependencies env moduleName d)) names'
50+ go (DataBindingGroupDeclaration ds') = concatMap go ds'
51+ go _ = []
52+
53+dependencies :: (Data d) => Environment -> ModuleName -> d -> [Key]
54+dependencies env moduleName = nub . everything (++) (mkQ [] values)
55+ where
56+ values :: Value -> [Key]
57+ values (Var ident) = let (mn, name) = canonicalize moduleName env ident in [(mn, Left name)]
58+ values (Constructor (Qualified (Just mn) name)) = [(mn, Right name)]
59+ values (Constructor (Qualified Nothing _)) = error "Found unqualified data constructor"
60+ values _ = []
61+
62+isUsed :: ModuleName -> Graph -> (Key -> Maybe Vertex) -> [Vertex] -> Declaration -> Bool
63+isUsed moduleName graph vertexFor entryPointVertices (ValueDeclaration name _ _ _) =
64+ let Just v' = vertexFor (moduleName, Left name)
65+ in any (\v -> path graph v v') entryPointVertices
66+isUsed moduleName graph vertexFor entryPointVertices (DataDeclaration _ _ dctors) =
67+ any (\(pn, _) -> let Just v' = vertexFor (moduleName, Right pn)
68+ in any (\v -> path graph v v') entryPointVertices) dctors
69+isUsed moduleName graph vertexFor entryPointVertices (ExternDeclaration _ name _ _) =
70+ let Just v' = vertexFor (moduleName, Left name)
71+ in any (\v -> path graph v v') entryPointVertices
72+isUsed moduleName graph vertexFor entryPointVertices (BindingGroupDeclaration ds) =
73+ any (\(name, _) -> let Just v' = vertexFor (moduleName, Left name)
74+ in any (\v -> path graph v v') entryPointVertices) ds
75+isUsed moduleName graph vertexFor entryPointVertices (DataBindingGroupDeclaration ds) =
76+ any (isUsed moduleName graph vertexFor entryPointVertices) ds
77+isUsed _ _ _ _ _ = True
src/Language/PureScript/Declarations.hsnew file+208
@@ -0,0 +1,208 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Declarations
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- | Data types for modules and declarations
12+--
13+-----------------------------------------------------------------------------
14+
15+{-# LANGUAGE DeriveDataTypeable #-}
16+
17+module Language.PureScript.Declarations where
18+
19+import Language.PureScript.Values
20+import Language.PureScript.Types
21+import Language.PureScript.Names
22+import Language.PureScript.Kinds
23+import Language.PureScript.CodeGen.JS.AST
24+
25+import qualified Data.Data as D
26+
27+-- |
28+-- A precedence level for an infix operator
29+--
30+type Precedence = Integer
31+
32+-- |
33+-- Associativity for infix operators
34+--
35+data Associativity = Infixl | Infixr deriving (Show, D.Data, D.Typeable)
36+
37+-- |
38+-- Fixity data for infix operators
39+--
40+data Fixity = Fixity Associativity Precedence deriving (Show, D.Data, D.Typeable)
41+
42+-- |
43+-- A module declaration, consisting of a module name and a list of declarations
44+--
45+data Module = Module ModuleName [Declaration] deriving (Show, D.Data, D.Typeable)
46+
47+-- |
48+-- The type of a foreign import
49+--
50+data ForeignImportType
51+ -- |
52+ -- A regular foreign import
53+ --
54+ = ForeignImport
55+ -- |
56+ -- A foreign import which contains inline Javascript as a string literal
57+ --
58+ | InlineJavascript
59+ -- |
60+ -- A type class dictionary import, generated during desugaring of type class declarations
61+ --
62+ | TypeClassDictionaryImport
63+ -- |
64+ -- A type class dictionary member accessor import, generated during desugaring of type class declarations
65+ --
66+ | TypeClassAccessorImport deriving (Show, Eq, D.Data, D.Typeable)
67+
68+-- |
69+-- An item in a list of explicit imports
70+--
71+data ImportType
72+ -- |
73+ -- A type constructor import
74+ --
75+ = TypeImport ProperName
76+ -- |
77+ -- A declaration import
78+ --
79+ | NameImport Ident
80+ deriving (Show, D.Data, D.Typeable)
81+
82+-- |
83+-- The data type of declarations
84+--
85+data Declaration
86+ -- |
87+ -- A data type declaration (name, arguments, data constructors)
88+ --
89+ = DataDeclaration ProperName [String] [(ProperName, [Type])]
90+ -- |
91+ -- A minimal mutually recursive set of data type declarations
92+ --
93+ | DataBindingGroupDeclaration [Declaration]
94+ -- |
95+ -- A type synonym declaration (name, arguments, type)
96+ --
97+ | TypeSynonymDeclaration ProperName [String] Type
98+ -- |
99+ -- A type declaration for a value (name, ty)
100+ --
101+ | TypeDeclaration Ident Type
102+ -- |
103+ -- A value declaration (name, top-level binders, optional guard, value)
104+ --
105+ | ValueDeclaration Ident [Binder] (Maybe Guard) Value
106+ -- |
107+ -- A minimal mutually recursive set of value declarations
108+ --
109+ | BindingGroupDeclaration [(Ident, Value)]
110+ -- |
111+ -- A foreign import declaration (type, name, optional inline Javascript, type)
112+ --
113+ | ExternDeclaration ForeignImportType Ident (Maybe JS) Type
114+ -- |
115+ -- A data type foreign import (name, kind)
116+ --
117+ | ExternDataDeclaration ProperName Kind
118+ -- |
119+ -- A fixity declaration (fixity data, operator name)
120+ --
121+ | FixityDeclaration Fixity String
122+ -- |
123+ -- A module import (module name, optional set of identifiers to import)
124+ --
125+ | ImportDeclaration ModuleName (Maybe [ImportType])
126+ -- |
127+ -- A type class declaration (name, argument, member declarations)
128+ --
129+ | TypeClassDeclaration ProperName [String] [Declaration]
130+ -- |
131+ -- A type instance declaration (dependencies, class name, instance type, member declarations)
132+ --
133+ | TypeInstanceDeclaration [(Qualified ProperName, [Type])] (Qualified ProperName) [Type] [Declaration]
134+ deriving (Show, D.Data, D.Typeable)
135+
136+-- |
137+-- Test if a declaration is a value declaration
138+--
139+isValueDecl :: Declaration -> Bool
140+isValueDecl ValueDeclaration{} = True
141+isValueDecl _ = False
142+
143+-- |
144+-- Test if a declaration is a data type or type synonym declaration
145+--
146+isDataDecl :: Declaration -> Bool
147+isDataDecl DataDeclaration{} = True
148+isDataDecl TypeSynonymDeclaration{} = True
149+isDataDecl _ = False
150+
151+-- |
152+-- Test if a declaration is a module import
153+--
154+isImportDecl :: Declaration -> Bool
155+isImportDecl ImportDeclaration{} = True
156+isImportDecl _ = False
157+
158+-- |
159+-- Test if a declaration is a data type foreign import
160+--
161+isExternDataDecl :: Declaration -> Bool
162+isExternDataDecl ExternDataDeclaration{} = True
163+isExternDataDecl _ = False
164+
165+-- |
166+-- Test if a declaration is a fixity declaration
167+--
168+isFixityDecl :: Declaration -> Bool
169+isFixityDecl FixityDeclaration{} = True
170+isFixityDecl _ = False
171+
172+-- |
173+-- Test if a declaration is a foreign import
174+--
175+isExternDecl :: Declaration -> Bool
176+isExternDecl ExternDeclaration{} = True
177+isExternDecl _ = False
178+
179+-- |
180+-- Test if a declaration is a type class or instance declaration
181+--
182+isTypeClassDeclaration :: Declaration -> Bool
183+isTypeClassDeclaration TypeClassDeclaration{} = True
184+isTypeClassDeclaration TypeInstanceDeclaration{} = True
185+isTypeClassDeclaration _ = False
186+
187+-- |
188+-- Extracts names from a list of explicit imports.
189+--
190+nameImports :: [ImportType] -> [Ident]
191+nameImports ((NameImport ident):xs) = ident : nameImports xs
192+nameImports (_ : xs) = nameImports xs
193+nameImports _ = []
194+
195+-- |
196+-- Extracts types from a list of explicit imports.
197+--
198+typeImports :: [ImportType] -> [ProperName]
199+typeImports (TypeImport ident : xs) = ident : typeImports xs
200+typeImports (_ : xs) = typeImports xs
201+typeImports _ = []
202+
203+-- |
204+-- Extracts classes from a list of explicit imports.
205+-- note: class imports are indistinguishable from types at the moment
206+--
207+classImports :: [ImportType] -> [ProperName]
208+classImports = typeImports
src/Language/PureScript/Kinds.hsnew file+46
@@ -0,0 +1,46 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Kinds
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 DeriveDataTypeable #-}
16+
17+module Language.PureScript.Kinds where
18+
19+import Data.Data
20+
21+import Control.Monad.Unify (Unknown)
22+
23+-- |
24+-- The data type of kinds
25+--
26+data Kind
27+ -- |
28+ -- Unification variable of type Kind
29+ --
30+ = KUnknown Unknown
31+ -- |
32+ -- The kind of types
33+ --
34+ | Star
35+ -- |
36+ -- The kind of effects
37+ --
38+ | Bang
39+ -- |
40+ -- Kinds for labelled, unordered rows without duplicates
41+ --
42+ | Row Kind
43+ -- |
44+ -- Function kinds
45+ --
46+ | FunKind Kind Kind deriving (Show, Eq, Data, Typeable)
src/Language/PureScript/ModuleDependencies.hsnew file+62
@@ -0,0 +1,62 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.ModuleDependencies
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- | Provides the ability to sort modules based on module dependencies
12+--
13+-----------------------------------------------------------------------------
14+
15+module Language.PureScript.ModuleDependencies (
16+ sortModules
17+) where
18+
19+import Data.Data
20+import Data.Graph
21+import Data.Generics
22+import Data.List (nub)
23+
24+import Language.PureScript.Declarations
25+import Language.PureScript.Names
26+
27+-- |
28+-- Sort a collection of modules based on module dependencies.
29+--
30+-- Reports an error if the module graph contains a cycle.
31+--
32+sortModules :: [Module] -> Either String [Module]
33+sortModules ms = do
34+ let verts = map (\m -> (m, getModuleName m, usedModules m)) ms
35+ mapM toModule $ stronglyConnComp verts
36+
37+-- |
38+-- Calculate a list of used modules based on explicit imports and qualified names
39+--
40+usedModules :: (Data d) => d -> [ModuleName]
41+usedModules = nub . everything (++) (mkQ [] qualifiedIdents `extQ` qualifiedProperNames `extQ` imports)
42+ where
43+ qualifiedIdents :: Qualified Ident -> [ModuleName]
44+ qualifiedIdents (Qualified (Just mn) _) = [mn]
45+ qualifiedIdents _ = []
46+ qualifiedProperNames :: Qualified ProperName -> [ModuleName]
47+ qualifiedProperNames (Qualified (Just mn) _) = [mn]
48+ qualifiedProperNames _ = []
49+ imports :: Declaration -> [ModuleName]
50+ imports (ImportDeclaration mn _) = [mn]
51+ imports _ = []
52+
53+getModuleName :: Module -> ModuleName
54+getModuleName (Module mn _) = mn
55+
56+-- |
57+-- Convert a strongly connected component of the module graph to a module
58+--
59+toModule :: SCC Module -> Either String Module
60+toModule (AcyclicSCC m) = return m
61+toModule (CyclicSCC [m]) = return m
62+toModule (CyclicSCC _) = Left "Cycle in module dependencies"
src/Language/PureScript/Names.hsnew file+98
@@ -0,0 +1,98 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Names
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+-- Data types for names
13+--
14+-----------------------------------------------------------------------------
15+
16+{-# LANGUAGE DeriveDataTypeable #-}
17+
18+module Language.PureScript.Names where
19+
20+import Data.List
21+import Data.Data
22+import Data.Function (on)
23+
24+-- |
25+-- Names for value identifiers
26+--
27+data Ident
28+ -- |
29+ -- An alphanumeric identifier
30+ --
31+ = Ident String
32+ -- |
33+ -- A symbolic name for an infix operator
34+ --
35+ | Op String
36+ -- |
37+ -- An escaped name
38+ --
39+ | Escaped String deriving (Data, Typeable)
40+
41+instance Show Ident where
42+ show (Ident s) = s
43+ show (Op op) = '(':op ++ ")"
44+ show (Escaped s) = s
45+
46+instance Eq Ident where
47+ Ident s1 == Ident s2 = s1 == s2
48+ Op s1 == Op s2 = s1 == s2
49+ Escaped s1 == Escaped s2 = s1 == s2
50+ Ident s1 == Escaped s2 = s1 == s2
51+ Escaped s1 == Ident s2 = s1 == s2
52+ _ == _ = False
53+
54+instance Ord Ident where
55+ compare = compare `on` show
56+
57+-- |
58+-- Proper names, i.e. capitalized names for e.g. module names, type//data constructors.
59+--
60+newtype ProperName = ProperName { runProperName :: String } deriving (Eq, Ord, Data, Typeable)
61+
62+instance Show ProperName where
63+ show = runProperName
64+
65+-- |
66+-- Module names
67+--
68+data ModuleName = ModuleName [ProperName] deriving (Eq, Ord, Data, Typeable)
69+
70+runModuleName :: ModuleName -> String
71+runModuleName (ModuleName pns) = intercalate "." (runProperName `map` pns)
72+
73+moduleNameFromString :: String -> ModuleName
74+moduleNameFromString = ModuleName . splitProperNames
75+ where
76+ splitProperNames s = case dropWhile (== '.') s of
77+ "" -> []
78+ s' -> ProperName w : splitProperNames s''
79+ where (w, s'') = break (== '.') s'
80+
81+instance Show ModuleName where
82+ show = runModuleName
83+
84+-- |
85+-- A qualified name, i.e. a name with an optional module name
86+--
87+data Qualified a = Qualified (Maybe ModuleName) a deriving (Eq, Ord, Data, Typeable)
88+
89+instance (Show a) => Show (Qualified a) where
90+ show (Qualified Nothing a) = show a
91+ show (Qualified (Just name) a) = show name ++ "." ++ show a
92+
93+-- |
94+-- Provide a default module name, if a name is unqualified
95+--
96+qualify :: ModuleName -> Qualified a -> (ModuleName, a)
97+qualify m (Qualified Nothing a) = (m, a)
98+qualify _ (Qualified (Just m) a) = (m, a)
src/Language/PureScript/Options.hsnew file+58
@@ -0,0 +1,58 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Options
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+-- The data type of compiler options
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Options where
17+
18+-- |
19+-- The data type of compiler options
20+--
21+data Options = Options {
22+ -- |
23+ -- Perform tail-call elimination
24+ --
25+ optionsTco :: Bool
26+ -- |
27+ -- Perform type checks at runtime
28+ --
29+ , optionsPerformRuntimeTypeChecks :: Bool
30+ -- |
31+ -- Inline calls to ret and bind for the Eff monad
32+ --
33+ , optionsMagicDo :: Bool
34+ -- |
35+ -- When specified, checks the type of `main` in the module, and generate a call to run main
36+ -- after the module definitions.
37+ --
38+ , optionsMain :: Maybe String
39+ -- |
40+ -- Skip all optimizations
41+ --
42+ , optionsNoOptimizations :: Bool
43+ -- |
44+ -- Specify the namespace that PureScript modules will be exported to when running in the
45+ -- browser.
46+ --
47+ , optionsBrowserNamespace :: String
48+ -- |
49+ -- The modules to keep while enabling dead code elimination
50+ --
51+ , optionsModules :: [String]
52+ } deriving Show
53+
54+-- |
55+-- Default compiler options
56+--
57+defaultOptions :: Options
58+defaultOptions = Options False False False Nothing False "PS" []
src/Language/PureScript/Parser.hsnew file+35
@@ -0,0 +1,35 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Parser
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+-- A collection of parsers for core data types:
13+--
14+-- [@Language.PureScript.Parser.Kinds@] Parser for kinds
15+--
16+-- [@Language.PureScript.Parser.Values@] Parser for values
17+--
18+-- [@Language.PureScript.Parser.Types@] Parser for types
19+--
20+-- [@Language.PureScript.Parser.Declaration@] Parsers for declarations and modules
21+--
22+-- [@Language.PureScript.Parser.State@] Parser state, including indentation
23+--
24+-- [@Language.PureScript.Parser.Common@] Common parsing utility functions
25+--
26+-----------------------------------------------------------------------------
27+
28+module Language.PureScript.Parser (module P) where
29+
30+import Language.PureScript.Parser.Common as P
31+import Language.PureScript.Parser.Types as P
32+import Language.PureScript.Parser.Values as P
33+import Language.PureScript.Parser.State as P
34+import Language.PureScript.Parser.Kinds as P
35+import Language.PureScript.Parser.Declarations as P
src/Language/PureScript/Parser/Common.hsnew file+370
@@ -0,0 +1,370 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Parser.Common
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+-- Constants, and utility functions to be used when parsing
13+--
14+-----------------------------------------------------------------------------
15+
16+{-# LANGUAGE FlexibleContexts #-}
17+
18+module Language.PureScript.Parser.Common where
19+
20+import Data.Functor.Identity
21+import Control.Applicative
22+import Control.Monad
23+import Language.PureScript.Parser.State
24+import qualified Text.Parsec as P
25+import qualified Text.Parsec.Token as PT
26+
27+import Language.PureScript.Names
28+
29+-- |
30+-- A list of purescript reserved identifiers
31+--
32+reservedPsNames :: [String]
33+reservedPsNames = [ "data"
34+ , "type"
35+ , "foreign"
36+ , "import"
37+ , "infixl"
38+ , "infixr"
39+ , "class"
40+ , "instance"
41+ , "module"
42+ , "case"
43+ , "of"
44+ , "if"
45+ , "then"
46+ , "else"
47+ , "do"
48+ , "let"
49+ , "true"
50+ , "false"
51+ , "in"
52+ , "where"
53+ ]
54+
55+-- |
56+-- A list of reserved identifiers for types
57+--
58+reservedTypeNames :: [String]
59+reservedTypeNames = [ "forall"
60+ , "where" ]
61+
62+-- |
63+-- A list of reserved operators
64+--
65+reservedOpNames :: [String]
66+reservedOpNames = [ "=>", "->", "=", ".", "\\" ]
67+
68+-- |
69+-- Valid first characters for an identifier
70+--
71+identStart :: P.Parsec String u Char
72+identStart = P.lower <|> P.oneOf "_"
73+
74+-- |
75+-- Valid identifier characters
76+--
77+identLetter :: P.Parsec String u Char
78+identLetter = P.alphaNum <|> P.oneOf "_'"
79+
80+-- |
81+-- Valid first characters for an operator
82+--
83+opStart :: P.Parsec String u Char
84+opStart = P.oneOf ":!#$%&*+./<=>?@\\^|-~"
85+
86+-- |
87+-- Valid operators characters
88+--
89+opLetter :: P.Parsec String u Char
90+opLetter = P.oneOf ":!#$%&*+./<=>?@\\^|-~"
91+
92+-- |
93+-- The PureScript language definition
94+--
95+langDef :: PT.GenLanguageDef String u Identity
96+langDef = PT.LanguageDef
97+ { PT.reservedNames = reservedPsNames
98+ , PT.reservedOpNames = reservedOpNames
99+ , PT.commentStart = "{-"
100+ , PT.commentEnd = "-}"
101+ , PT.commentLine = "--"
102+ , PT.nestedComments = True
103+ , PT.identStart = identStart
104+ , PT.identLetter = identLetter
105+ , PT.opStart = opStart
106+ , PT.opLetter = opLetter
107+ , PT.caseSensitive = True
108+ }
109+
110+-- |
111+-- A token parser based on the language definition
112+--
113+tokenParser :: PT.GenTokenParser String u Identity
114+tokenParser = PT.makeTokenParser langDef
115+
116+-- |
117+-- Parse a token
118+--
119+lexeme :: P.Parsec String u a -> P.Parsec String u a
120+lexeme = PT.lexeme tokenParser
121+
122+-- |
123+-- Parse an identifier
124+--
125+identifier :: P.Parsec String u String
126+identifier = PT.identifier tokenParser
127+
128+-- |
129+-- Parse a reserved word
130+--
131+reserved :: String -> P.Parsec String u ()
132+reserved = PT.reserved tokenParser
133+
134+-- |
135+-- Parse a reserved operator
136+--
137+reservedOp :: String -> P.Parsec String u ()
138+reservedOp = PT.reservedOp tokenParser
139+
140+-- |
141+-- Parse an operator
142+--
143+operator :: P.Parsec String u String
144+operator = PT.operator tokenParser
145+
146+-- |
147+-- Parse a string literal
148+--
149+stringLiteral :: P.Parsec String u String
150+stringLiteral = PT.stringLiteral tokenParser
151+
152+-- |
153+-- Parse whitespace
154+--
155+whiteSpace :: P.Parsec String u ()
156+whiteSpace = PT.whiteSpace tokenParser
157+
158+-- |
159+-- Semicolon
160+--
161+semi :: P.Parsec String u String
162+semi = PT.semi tokenParser
163+
164+-- |
165+-- Colon
166+--
167+colon :: P.Parsec String u String
168+colon = PT.colon tokenParser
169+
170+-- |
171+-- Period
172+--
173+dot :: P.Parsec String u String
174+dot = PT.dot tokenParser
175+
176+-- |
177+-- Comma
178+--
179+comma :: P.Parsec String u String
180+comma = PT.comma tokenParser
181+
182+-- |
183+-- Backtick
184+--
185+tick :: P.Parsec String u Char
186+tick = lexeme $ P.char '`'
187+
188+-- |
189+-- Pipe character
190+--
191+pipe :: P.Parsec String u Char
192+pipe = lexeme $ P.char '|'
193+
194+-- |
195+-- Natural number
196+--
197+natural :: P.Parsec String u Integer
198+natural = PT.natural tokenParser
199+
200+-- |
201+-- Parse a proper name
202+--
203+properName :: P.Parsec String u ProperName
204+properName = lexeme $ ProperName <$> P.try ((:) <$> P.upper <*> many P.alphaNum P.<?> "name")
205+
206+-- |
207+-- Parse a module name
208+--
209+moduleName :: P.Parsec String ParseState ModuleName
210+moduleName = ModuleName <$> P.try (sepBy properName dot)
211+
212+-- |
213+-- Parse a qualified name, i.e. M.name or just name
214+--
215+parseQualified :: P.Parsec String ParseState a -> P.Parsec String ParseState (Qualified a)
216+parseQualified parser = part []
217+ where
218+ part path = (do name <- P.try (properName <* delimiter)
219+ part (updatePath path name))
220+ <|> (Qualified (qual path) <$> P.try parser)
221+ delimiter = indented *> dot <* P.notFollowedBy dot
222+ updatePath path name = path ++ [name]
223+ qual path = if null path then Nothing else Just $ ModuleName path
224+
225+-- |
226+-- Parse an integer or floating point value
227+--
228+integerOrFloat :: P.Parsec String u (Either Integer Double)
229+integerOrFloat = (Right <$> P.try (PT.float tokenParser) <|>
230+ Left <$> P.try (PT.natural tokenParser)) P.<?> "number"
231+
232+-- |
233+-- Parse an identifier or parenthesized operator
234+--
235+parseIdent :: P.Parsec String ParseState Ident
236+parseIdent = (Ident <$> identifier) <|> (Op <$> parens operator)
237+
238+-- |
239+-- Parse a token inside square brackets
240+--
241+squares :: P.Parsec String ParseState a -> P.Parsec String ParseState a
242+squares = P.between (lexeme $ P.char '[') (lexeme $ indented *> P.char ']') . (indented *>)
243+
244+-- |
245+-- Parse a token inside parentheses
246+--
247+parens :: P.Parsec String ParseState a -> P.Parsec String ParseState a
248+parens = P.between (lexeme $ P.char '(') (lexeme $ indented *> P.char ')') . (indented *>)
249+
250+-- |
251+-- Parse a token inside braces
252+--
253+braces :: P.Parsec String ParseState a -> P.Parsec String ParseState a
254+braces = P.between (lexeme $ P.char '{') (lexeme $ indented *> P.char '}') . (indented *>)
255+
256+-- |
257+-- Parse a token inside angle brackets
258+--
259+angles :: P.Parsec String ParseState a -> P.Parsec String ParseState a
260+angles = P.between (lexeme $ P.char '<') (lexeme $ indented *> P.char '>') . (indented *>)
261+
262+-- |
263+-- Parse zero or more values separated by a separator token
264+--
265+sepBy :: P.Parsec String ParseState a -> P.Parsec String ParseState sep -> P.Parsec String ParseState [a]
266+sepBy p s = P.sepBy (indented *> p) (indented *> s)
267+
268+-- |
269+-- Parse one or more values separated by a separator token
270+--
271+sepBy1 :: P.Parsec String ParseState a -> P.Parsec String ParseState sep -> P.Parsec String ParseState [a]
272+sepBy1 p s = P.sepBy1 (indented *> p) (indented *> s)
273+
274+-- |
275+-- Parse zero or more values separated by semicolons
276+--
277+semiSep :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
278+semiSep = flip sepBy semi
279+
280+-- |
281+-- Parse one or more values separated by semicolons
282+--
283+semiSep1 :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
284+semiSep1 = flip sepBy1 semi
285+
286+-- |
287+-- Parse zero or more values separated by commas
288+--
289+commaSep :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
290+commaSep = flip sepBy comma
291+
292+-- |
293+-- Parse one or more values separated by commas
294+--
295+commaSep1 :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
296+commaSep1 = flip sepBy1 comma
297+
298+-- |
299+-- Run the first parser, then match the second if possible, applying the specified function on a successful match
300+--
301+augment :: P.Stream s m t => P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a
302+augment p q f = flip (maybe id $ flip f) <$> p <*> P.optionMaybe q
303+
304+-- |
305+-- Run the first parser, then match the second zero or more times, applying the specified function for each match
306+--
307+fold :: P.Stream s m t => P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a
308+fold first more combine = do
309+ a <- first
310+ bs <- P.many more
311+ return $ foldl combine a bs
312+
313+-- |
314+-- Build a parser from a smaller parser and a list of parsers for postfix operators
315+--
316+buildPostfixParser :: P.Stream s m t => [a -> P.ParsecT s u m a] -> P.ParsecT s u m a -> P.ParsecT s u m a
317+buildPostfixParser fs first = do
318+ a <- first
319+ go a
320+ where
321+ go a = do
322+ maybeA <- P.optionMaybe $ P.choice (map ($ a) fs)
323+ case maybeA of
324+ Nothing -> return a
325+ Just a' -> go a'
326+
327+-- |
328+-- Parse an identifier in backticks or an operator
329+--
330+parseIdentInfix :: P.Parsec String ParseState (Qualified Ident)
331+parseIdentInfix = P.between tick tick (parseQualified (Ident <$> identifier)) <|> Qualified Nothing <$> (Op <$> operator)
332+
333+-- |
334+-- Mark the current indentation level
335+--
336+mark :: P.Parsec String ParseState a -> P.Parsec String ParseState a
337+mark p = do
338+ current <- indentationLevel <$> P.getState
339+ pos <- P.sourceColumn <$> P.getPosition
340+ P.modifyState $ \st -> st { indentationLevel = pos }
341+ a <- p
342+ P.modifyState $ \st -> st { indentationLevel = current }
343+ return a
344+
345+-- |
346+-- Check that the current identation level matches a predicate
347+--
348+checkIndentation :: (P.Column -> P.Column -> Bool) -> P.Parsec String ParseState ()
349+checkIndentation rel = do
350+ col <- P.sourceColumn <$> P.getPosition
351+ current <- indentationLevel <$> P.getState
352+ guard (col `rel` current)
353+
354+-- |
355+-- Check that the current indentation level is past the current mark
356+--
357+indented :: P.Parsec String ParseState ()
358+indented = checkIndentation (>) P.<?> "indentation"
359+
360+-- |
361+-- Check that the current indentation level is at the same indentation as the current mark
362+--
363+same :: P.Parsec String ParseState ()
364+same = checkIndentation (==) P.<?> "no indentation"
365+
366+-- |
367+-- Run a parser which supports indentation
368+--
369+runIndentParser :: FilePath -> P.Parsec String ParseState a -> String -> Either P.ParseError a
370+runIndentParser filePath p = P.runParser p (ParseState 0) filePath
src/Language/PureScript/Parser/Declarations.hsnew file+150
@@ -0,0 +1,150 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Parser.Declarations
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+-- Parsers for module definitions and declarations
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Parser.Declarations (
17+ parseDeclaration,
18+ parseModule,
19+ parseModules
20+) where
21+
22+import Data.Maybe (isJust, fromMaybe)
23+import Control.Applicative
24+import qualified Text.Parsec as P
25+
26+import Language.PureScript.Parser.State
27+import Language.PureScript.Parser.Common
28+import Language.PureScript.Declarations
29+import Language.PureScript.Parser.Values
30+import Language.PureScript.Parser.Types
31+import Language.PureScript.Parser.Kinds
32+import Language.PureScript.CodeGen.JS.AST
33+
34+parseDataDeclaration :: P.Parsec String ParseState Declaration
35+parseDataDeclaration = do
36+ reserved "data"
37+ name <- indented *> properName
38+ tyArgs <- many (indented *> identifier)
39+ ctors <- P.option [] $ do
40+ _ <- lexeme $ indented *> P.char '='
41+ sepBy1 ((,) <$> properName <*> P.many (indented *> parseTypeAtom)) pipe
42+ return $ DataDeclaration name tyArgs ctors
43+
44+parseTypeDeclaration :: P.Parsec String ParseState Declaration
45+parseTypeDeclaration =
46+ TypeDeclaration <$> P.try (parseIdent <* lexeme (indented *> P.string "::"))
47+ <*> parsePolyType
48+
49+parseTypeSynonymDeclaration :: P.Parsec String ParseState Declaration
50+parseTypeSynonymDeclaration =
51+ TypeSynonymDeclaration <$> (P.try (reserved "type") *> indented *> properName)
52+ <*> many (indented *> identifier)
53+ <*> (lexeme (indented *> P.char '=') *> parsePolyType)
54+
55+parseValueDeclaration :: P.Parsec String ParseState Declaration
56+parseValueDeclaration =
57+ ValueDeclaration <$> parseIdent
58+ <*> P.many parseBinderNoParens
59+ <*> P.optionMaybe parseGuard
60+ <*> (lexeme (indented *> P.char '=') *> parseValue)
61+
62+parseExternDeclaration :: P.Parsec String ParseState Declaration
63+parseExternDeclaration = P.try (reserved "foreign") *> indented *> reserved "import" *> indented *>
64+ (ExternDataDeclaration <$> (P.try (reserved "data") *> indented *> properName)
65+ <*> (lexeme (indented *> P.string "::") *> parseKind)
66+ <|> do ident <- parseIdent
67+ js <- P.optionMaybe (JSRaw <$> stringLiteral)
68+ ty <- lexeme (indented *> P.string "::") *> parsePolyType
69+ return $ ExternDeclaration (if isJust js then InlineJavascript else ForeignImport) ident js ty)
70+
71+parseAssociativity :: P.Parsec String ParseState Associativity
72+parseAssociativity =
73+ (P.try (reserved "infixl") >> return Infixl) <|>
74+ (P.try (reserved "infixr") >> return Infixr)
75+
76+parseFixity :: P.Parsec String ParseState Fixity
77+parseFixity = Fixity <$> parseAssociativity <*> (indented *> natural)
78+
79+parseFixityDeclaration :: P.Parsec String ParseState Declaration
80+parseFixityDeclaration = do
81+ fixity <- parseFixity
82+ indented
83+ name <- operator
84+ return $ FixityDeclaration fixity name
85+
86+parseImportDeclaration :: P.Parsec String ParseState Declaration
87+parseImportDeclaration = do
88+ reserved "import"
89+ indented
90+ moduleName' <- moduleName
91+ idents <- P.optionMaybe $ parens $ commaSep1 (NameImport <$> parseIdent <|> TypeImport <$> properName)
92+ return $ ImportDeclaration moduleName' idents
93+
94+parseTypeClassDeclaration :: P.Parsec String ParseState Declaration
95+parseTypeClassDeclaration = do
96+ reserved "class"
97+ className <- indented *> properName
98+ idents <- P.many (indented *> identifier)
99+ members <- P.option [] . P.try $ do
100+ indented *> reserved "where"
101+ mark (P.many (same *> parseTypeDeclaration))
102+ return $ TypeClassDeclaration className idents members
103+
104+parseTypeInstanceDeclaration :: P.Parsec String ParseState Declaration
105+parseTypeInstanceDeclaration = do
106+ reserved "instance"
107+ deps <- P.optionMaybe $ do
108+ deps <- parens (commaSep1 ((,) <$> parseQualified properName <*> P.many parseTypeAtom))
109+ indented
110+ reservedOp "=>"
111+ return deps
112+ className <- indented *> parseQualified properName
113+ ty <- P.many (indented *> parseTypeAtom)
114+ members <- P.option [] . P.try $ do
115+ indented *> reserved "where"
116+ mark (P.many (same *> parseValueDeclaration))
117+ return $ TypeInstanceDeclaration (fromMaybe [] deps) className ty members
118+
119+-- |
120+-- Parse a single declaration
121+--
122+parseDeclaration :: P.Parsec String ParseState Declaration
123+parseDeclaration = P.choice
124+ [ parseDataDeclaration
125+ , parseTypeDeclaration
126+ , parseTypeSynonymDeclaration
127+ , parseValueDeclaration
128+ , parseExternDeclaration
129+ , parseFixityDeclaration
130+ , parseImportDeclaration
131+ , parseTypeClassDeclaration
132+ , parseTypeInstanceDeclaration ] P.<?> "declaration"
133+
134+-- |
135+-- Parse a module header and a collection of declarations
136+--
137+parseModule :: P.Parsec String ParseState Module
138+parseModule = do
139+ reserved "module"
140+ indented
141+ name <- moduleName
142+ _ <- lexeme $ P.string "where"
143+ decls <- mark (P.many (same *> parseDeclaration))
144+ return $ Module name decls
145+
146+-- |
147+-- Parse a collection of modules
148+--
149+parseModules :: P.Parsec String ParseState [Module]
150+parseModules = whiteSpace *> mark (P.many (same *> parseModule)) <* P.eof
src/Language/PureScript/Parser/Kinds.hsnew file+45
@@ -0,0 +1,45 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Parser.Kinds
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+-- A parser for kinds
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Parser.Kinds (
17+ parseKind
18+) where
19+
20+import Language.PureScript.Kinds
21+import Language.PureScript.Parser.State
22+import Language.PureScript.Parser.Common
23+import Control.Applicative
24+import qualified Text.Parsec as P
25+import qualified Text.Parsec.Expr as P
26+
27+parseStar :: P.Parsec String ParseState Kind
28+parseStar = const Star <$> lexeme (P.char '*')
29+
30+parseBang :: P.Parsec String ParseState Kind
31+parseBang = const Bang <$> lexeme (P.char '!')
32+
33+parseTypeAtom :: P.Parsec String ParseState Kind
34+parseTypeAtom = indented *> P.choice (map P.try
35+ [ parseStar
36+ , parseBang
37+ , parens parseKind ])
38+-- |
39+-- Parse a kind
40+--
41+parseKind :: P.Parsec String ParseState Kind
42+parseKind = P.buildExpressionParser operators parseTypeAtom P.<?> "kind"
43+ where
44+ operators = [ [ P.Prefix (lexeme (P.char '#') >> return Row) ]
45+ , [ P.Infix (lexeme (P.try (P.string "->")) >> return FunKind) P.AssocRight ] ]
src/Language/PureScript/Parser/State.hsnew file+30
@@ -0,0 +1,30 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Parser.State
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+-- State for the parser monad
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Parser.State where
17+
18+import qualified Text.Parsec as P
19+
20+-- |
21+-- State for the parser monad
22+--
23+data ParseState = ParseState {
24+ -- |
25+ -- The most recently marked indentation level
26+ --
27+ indentationLevel :: P.Column
28+ } deriving Show
29+
30+
src/Language/PureScript/Parser/Types.hsnew file+125
@@ -0,0 +1,125 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Parser.Types
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+-- Parsers for types
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Parser.Types (
17+ parseType,
18+ parsePolyType,
19+ parseTypeAtom
20+) where
21+
22+import Language.PureScript.Types
23+import Language.PureScript.Parser.State
24+import Language.PureScript.Parser.Common
25+import Control.Applicative
26+import qualified Text.Parsec as P
27+import qualified Text.Parsec.Expr as P
28+import Control.Monad (when, unless)
29+
30+parseNumber :: P.Parsec String ParseState Type
31+parseNumber = const tyNumber <$> reserved "Number"
32+
33+parseString :: P.Parsec String ParseState Type
34+parseString = const tyString <$> reserved "String"
35+
36+parseBoolean :: P.Parsec String ParseState Type
37+parseBoolean = const tyBoolean <$> reserved "Boolean"
38+
39+parseArray :: P.Parsec String ParseState Type
40+parseArray = squares $ return tyArray
41+
42+parseArrayOf :: P.Parsec String ParseState Type
43+parseArrayOf = squares $ TypeApp tyArray <$> parseType
44+
45+parseFunction :: P.Parsec String ParseState Type
46+parseFunction = parens $ P.try (lexeme (P.string "->")) >> return tyFunction
47+
48+parseObject :: P.Parsec String ParseState Type
49+parseObject = braces $ Object <$> parseRow False
50+
51+parseTypeVariable :: P.Parsec String ParseState Type
52+parseTypeVariable = do
53+ ident <- identifier
54+ when (ident `elem` reservedTypeNames) $ P.unexpected ident
55+ return $ TypeVar ident
56+
57+parseTypeConstructor :: P.Parsec String ParseState Type
58+parseTypeConstructor = TypeConstructor <$> parseQualified properName
59+
60+parseForAll :: P.Parsec String ParseState Type
61+parseForAll = mkForAll <$> (P.try (reserved "forall") *> P.many1 (indented *> identifier) <* indented <* dot)
62+ <*> parseConstrainedType
63+
64+-- |
65+-- Parse a type as it appears in e.g. a data constructor
66+--
67+parseTypeAtom :: P.Parsec String ParseState Type
68+parseTypeAtom = indented *> P.choice (map P.try
69+ [ parseNumber
70+ , parseString
71+ , parseBoolean
72+ , parseArray
73+ , parseArrayOf
74+ , parseFunction
75+ , parseObject
76+ , parseTypeVariable
77+ , parseTypeConstructor
78+ , parseForAll
79+ , parens (parseRow True)
80+ , parens parsePolyType ])
81+
82+parseConstrainedType :: P.Parsec String ParseState Type
83+parseConstrainedType = do
84+ constraints <- P.optionMaybe . P.try $ do
85+ constraints <- parens . commaSep1 $ do
86+ className <- parseQualified properName
87+ indented
88+ ty <- P.many parseTypeAtom
89+ return (className, ty)
90+ _ <- lexeme $ P.string "=>"
91+ return constraints
92+ indented
93+ ty <- parseType
94+ return $ maybe ty (flip ConstrainedType ty) constraints
95+
96+parseAnyType :: P.Parsec String ParseState Type
97+parseAnyType = P.buildExpressionParser operators parseTypeAtom P.<?> "type"
98+ where
99+ operators = [ [ P.Infix (return TypeApp) P.AssocLeft ]
100+ , [ P.Infix (P.try (lexeme (P.string "->")) >> return function) P.AssocRight ] ]
101+
102+-- |
103+-- Parse a monotype
104+--
105+parseType :: P.Parsec String ParseState Type
106+parseType = do
107+ ty <- parseAnyType
108+ unless (isMonoType ty) $ P.unexpected "polymorphic type"
109+ return ty
110+
111+-- |
112+-- Parse a polytype
113+--
114+parsePolyType :: P.Parsec String ParseState Type
115+parsePolyType = parseAnyType
116+
117+parseNameAndType :: P.Parsec String ParseState t -> P.Parsec String ParseState (String, t)
118+parseNameAndType p = (,) <$> (indented *> identifier <* indented <* lexeme (P.string "::")) <*> p
119+
120+parseRowEnding :: P.Parsec String ParseState Type
121+parseRowEnding = P.option REmpty (TypeVar <$> (lexeme (indented *> P.char '|') *> indented *> identifier))
122+
123+parseRow :: Bool -> P.Parsec String ParseState Type
124+parseRow nonEmpty = (curry rowFromList <$> many' (parseNameAndType parsePolyType) <*> parseRowEnding) P.<?> "row"
125+ where many' = if nonEmpty then commaSep1 else commaSep
src/Language/PureScript/Parser/Values.hsnew file+245
@@ -0,0 +1,245 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Parser.Values
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+-- Parsers for values, statements, binders and guards
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Parser.Values (
17+ parseValue,
18+ parseGuard,
19+ parseBinder,
20+ parseBinderNoParens,
21+) where
22+
23+import Control.Applicative
24+
25+import Language.PureScript.Values
26+import Language.PureScript.Parser.State
27+import Language.PureScript.Parser.Types
28+
29+import Text.Parsec.Expr
30+
31+import qualified Language.PureScript.Parser.Common as C
32+import qualified Text.Parsec as P
33+
34+booleanLiteral :: P.Parsec String ParseState Bool
35+booleanLiteral = (C.reserved "true" >> return True) P.<|> (C.reserved "false" >> return False)
36+
37+parseNumericLiteral :: P.Parsec String ParseState Value
38+parseNumericLiteral = NumericLiteral <$> C.integerOrFloat
39+
40+parseStringLiteral :: P.Parsec String ParseState Value
41+parseStringLiteral = StringLiteral <$> C.stringLiteral
42+
43+parseBooleanLiteral :: P.Parsec String ParseState Value
44+parseBooleanLiteral = BooleanLiteral <$> booleanLiteral
45+
46+parseArrayLiteral :: P.Parsec String ParseState Value
47+parseArrayLiteral = ArrayLiteral <$> C.squares (C.commaSep parseValue)
48+
49+parseObjectLiteral :: P.Parsec String ParseState Value
50+parseObjectLiteral = ObjectLiteral <$> C.braces (C.commaSep parseIdentifierAndValue)
51+
52+parseIdentifierAndValue :: P.Parsec String ParseState (String, Value)
53+parseIdentifierAndValue = (,) <$> (C.indented *> C.identifier <* C.indented <* C.colon)
54+ <*> (C.indented *> parseValue)
55+
56+parseAbs :: P.Parsec String ParseState Value
57+parseAbs = do
58+ C.reservedOp "\\"
59+ args <- P.many1 (C.indented *> (Abs <$> (Left <$> P.try C.parseIdent <|> Right <$> parseBinderNoParens)))
60+ C.indented *> C.reservedOp "->"
61+ value <- parseValue
62+ return $ toFunction args value
63+ where
64+ toFunction :: [Value -> Value] -> Value -> Value
65+ toFunction args value = foldr ($) value args
66+
67+parseVar :: P.Parsec String ParseState Value
68+parseVar = Var <$> C.parseQualified C.parseIdent
69+
70+parseConstructor :: P.Parsec String ParseState Value
71+parseConstructor = Constructor <$> C.parseQualified C.properName
72+
73+parseCase :: P.Parsec String ParseState Value
74+parseCase = Case <$> P.between (P.try (C.reserved "case")) (C.indented *> C.reserved "of") (return <$> parseValue)
75+ <*> (C.indented *> C.mark (P.many (C.same *> C.mark parseCaseAlternative)))
76+
77+parseCaseAlternative :: P.Parsec String ParseState ([Binder], Maybe Guard, Value)
78+parseCaseAlternative = (,,) <$> (return <$> parseBinder)
79+ <*> P.optionMaybe parseGuard
80+ <*> (C.indented *> C.reservedOp "->" *> parseValue)
81+ P.<?> "case alternative"
82+
83+parseIfThenElse :: P.Parsec String ParseState Value
84+parseIfThenElse = IfThenElse <$> (P.try (C.reserved "if") *> C.indented *> parseValue)
85+ <*> (C.indented *> C.reserved "then" *> C.indented *> parseValue)
86+ <*> (C.indented *> C.reserved "else" *> C.indented *> parseValue)
87+
88+parseLet :: P.Parsec String ParseState Value
89+parseLet = do
90+ C.reserved "let"
91+ C.indented
92+ binder <- parseBinder
93+ C.indented
94+ C.reservedOp "="
95+ C.indented
96+ value <- parseValue
97+ C.indented
98+ C.reserved "in"
99+ result <- parseValue
100+ return $ Let binder value result
101+
102+parseValueAtom :: P.Parsec String ParseState Value
103+parseValueAtom = P.choice
104+ [ P.try parseNumericLiteral
105+ , P.try parseStringLiteral
106+ , P.try parseBooleanLiteral
107+ , parseArrayLiteral
108+ , P.try parseObjectLiteral
109+ , parseAbs
110+ , P.try parseConstructor
111+ , P.try parseVar
112+ , parseCase
113+ , parseIfThenElse
114+ , parseDo
115+ , parseLet
116+ , Parens <$> C.parens parseValue ]
117+
118+parsePropertyUpdate :: P.Parsec String ParseState (String, Value)
119+parsePropertyUpdate = do
120+ name <- C.lexeme C.identifier
121+ _ <- C.lexeme $ C.indented *> P.char '='
122+ value <- C.indented *> parseValue
123+ return (name, value)
124+
125+parseAccessor :: Value -> P.Parsec String ParseState Value
126+parseAccessor (Constructor _) = P.unexpected "constructor"
127+parseAccessor obj = P.try $ Accessor <$> (C.indented *> C.dot *> P.notFollowedBy C.opLetter *> C.indented *> C.identifier) <*> pure obj
128+
129+parseDo :: P.Parsec String ParseState Value
130+parseDo = do
131+ C.reserved "do"
132+ C.indented
133+ Do <$> C.mark (P.many (C.same *> C.mark parseDoNotationElement))
134+
135+parseDoNotationLet :: P.Parsec String ParseState DoNotationElement
136+parseDoNotationLet = DoNotationLet <$> (C.reserved "let" *> C.indented *> parseBinder)
137+ <*> (C.indented *> C.reservedOp "=" *> parseValue)
138+
139+parseDoNotationBind :: P.Parsec String ParseState DoNotationElement
140+parseDoNotationBind = DoNotationBind <$> parseBinder <*> (C.indented *> C.reservedOp "<-" *> parseValue)
141+
142+parseDoNotationElement :: P.Parsec String ParseState DoNotationElement
143+parseDoNotationElement = P.choice
144+ [ P.try parseDoNotationBind
145+ , parseDoNotationLet
146+ , P.try (DoNotationValue <$> parseValue) ]
147+
148+-- |
149+-- Parse a value
150+--
151+parseValue :: P.Parsec String ParseState Value
152+parseValue =
153+ (buildExpressionParser operators
154+ . C.buildPostfixParser postfixTable2
155+ $ indexersAndAccessors) P.<?> "expression"
156+ where
157+ indexersAndAccessors = C.buildPostfixParser postfixTable1 parseValueAtom
158+ postfixTable1 = [ parseAccessor
159+ , \v -> P.try $ flip ObjectUpdate <$> (C.indented *> C.braces (C.commaSep1 (C.indented *> parsePropertyUpdate))) <*> pure v ]
160+ postfixTable2 = [ \v -> P.try (flip App <$> (C.indented *> indexersAndAccessors)) <*> pure v
161+ , \v -> flip (TypedValue True) <$> (P.try (C.lexeme (C.indented *> P.string "::")) *> parsePolyType) <*> pure v
162+ ]
163+ operators = [ [ Infix (C.lexeme (P.try (C.indented *> C.parseIdentInfix P.<?> "operator") >>= \ident ->
164+ return (BinaryNoParens ident))) AssocRight ]
165+ ]
166+
167+parseStringBinder :: P.Parsec String ParseState Binder
168+parseStringBinder = StringBinder <$> C.stringLiteral
169+
170+parseBooleanBinder :: P.Parsec String ParseState Binder
171+parseBooleanBinder = BooleanBinder <$> booleanLiteral
172+
173+parseNumberBinder :: P.Parsec String ParseState Binder
174+parseNumberBinder = NumberBinder <$> C.integerOrFloat
175+
176+parseVarBinder :: P.Parsec String ParseState Binder
177+parseVarBinder = VarBinder <$> C.parseIdent
178+
179+parseNullaryConstructorBinder :: P.Parsec String ParseState Binder
180+parseNullaryConstructorBinder = ConstructorBinder <$> C.lexeme (C.parseQualified C.properName) <*> pure []
181+
182+parseConstructorBinder :: P.Parsec String ParseState Binder
183+parseConstructorBinder = ConstructorBinder <$> C.lexeme (C.parseQualified C.properName) <*> many (C.indented *> parseBinderNoParens)
184+
185+parseObjectBinder :: P.Parsec String ParseState Binder
186+parseObjectBinder = ObjectBinder <$> C.braces (C.commaSep (C.indented *> parseIdentifierAndBinder))
187+
188+parseArrayBinder :: P.Parsec String ParseState Binder
189+parseArrayBinder = C.squares $ ArrayBinder <$> C.commaSep (C.indented *> parseBinder)
190+
191+parseNamedBinder :: P.Parsec String ParseState Binder
192+parseNamedBinder = NamedBinder <$> (C.parseIdent <* C.indented <* C.lexeme (P.char '@'))
193+ <*> (C.indented *> parseBinder)
194+
195+parseNullBinder :: P.Parsec String ParseState Binder
196+parseNullBinder = C.lexeme (P.char '_') *> P.notFollowedBy C.identLetter *> return NullBinder
197+
198+parseIdentifierAndBinder :: P.Parsec String ParseState (String, Binder)
199+parseIdentifierAndBinder = do
200+ name <- C.lexeme C.identifier
201+ _ <- C.lexeme $ C.indented *> P.char '='
202+ binder <- C.indented *> parseBinder
203+ return (name, binder)
204+
205+-- |
206+-- Parse a binder
207+--
208+parseBinder :: P.Parsec String ParseState Binder
209+parseBinder = buildExpressionParser operators parseBinderAtom P.<?> "expression"
210+ where
211+ operators = [ [ Infix ( C.lexeme (P.try $ C.indented *> C.reservedOp ":") >> return ConsBinder) AssocRight ] ]
212+ parseBinderAtom :: P.Parsec String ParseState Binder
213+ parseBinderAtom = P.choice (map P.try
214+ [ parseNullBinder
215+ , parseStringBinder
216+ , parseBooleanBinder
217+ , parseNumberBinder
218+ , parseNamedBinder
219+ , parseVarBinder
220+ , parseConstructorBinder
221+ , parseObjectBinder
222+ , parseArrayBinder
223+ , C.parens parseBinder ]) P.<?> "binder"
224+
225+-- |
226+-- Parse a binder as it would appear in a top level declaration
227+--
228+parseBinderNoParens :: P.Parsec String ParseState Binder
229+parseBinderNoParens = P.choice (map P.try
230+ [ parseNullBinder
231+ , parseStringBinder
232+ , parseBooleanBinder
233+ , parseNumberBinder
234+ , parseNamedBinder
235+ , parseVarBinder
236+ , parseNullaryConstructorBinder
237+ , parseObjectBinder
238+ , parseArrayBinder
239+ , C.parens parseBinder ]) P.<?> "binder"
240+-- |
241+-- Parse a guard
242+--
243+parseGuard :: P.Parsec String ParseState Guard
244+parseGuard = C.indented *> C.pipe *> C.indented *> parseValue
245+
src/Language/PureScript/Pretty.hsnew file+32
@@ -0,0 +1,32 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Pretty
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+-- A collection of pretty printers for core data types:
13+--
14+-- [@Language.PureScript.Pretty.Kinds@] Pretty printer for kinds
15+--
16+-- [@Language.PureScript.Pretty.Values@] Pretty printer for values
17+--
18+-- [@Language.PureScript.Pretty.Types@] Pretty printer for types
19+--
20+-- [@Language.PureScript.Pretty.JS@] Pretty printer for values, used for code generation
21+--
22+-----------------------------------------------------------------------------
23+
24+module Language.PureScript.Pretty (module P) where
25+
26+import Language.PureScript.Pretty.Kinds as P
27+import Language.PureScript.Pretty.Values as P
28+import Language.PureScript.Pretty.Types as P
29+import Language.PureScript.Pretty.JS as P
30+
31+
32+
src/Language/PureScript/Pretty/Common.hsnew file+22
@@ -0,0 +1,22 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Pretty.Common
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+-- Common pretty-printing utility functions
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Pretty.Common where
17+
18+-- |
19+-- Wrap a string in parentheses
20+--
21+parens :: String -> String
22+parens s = ('(':s) ++ ")"
src/Language/PureScript/Pretty/JS.hsnew file+253
@@ -0,0 +1,253 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Pretty.JS
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+-- Pretty printer for the Javascript AST
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Pretty.JS (
17+ prettyPrintJS
18+) where
19+
20+import Language.PureScript.Pretty.Common
21+import Language.PureScript.CodeGen.JS.AST
22+
23+import Data.List
24+import Data.Maybe (fromMaybe)
25+import qualified Control.Arrow as A
26+import Control.Arrow ((<+>))
27+import Control.PatternArrows
28+import Control.Applicative
29+import Control.Monad.State
30+
31+newtype PrinterState = PrinterState { indent :: Int } deriving (Show, Eq, Ord)
32+
33+-- |
34+-- Number of characters per identation level
35+--
36+blockIndent :: Int
37+blockIndent = 4
38+
39+-- |
40+-- Pretty print with a new indentation level
41+--
42+withIndent :: StateT PrinterState Maybe String -> StateT PrinterState Maybe String
43+withIndent action = do
44+ modify $ \st -> st { indent = indent st + blockIndent }
45+ result <- action
46+ modify $ \st -> st { indent = indent st - blockIndent }
47+ return result
48+
49+-- |
50+-- Get the current indentation level
51+--
52+currentIndent :: StateT PrinterState Maybe String
53+currentIndent = do
54+ current <- get
55+ return $ replicate (indent current) ' '
56+
57+literals :: Pattern PrinterState JS String
58+literals = mkPattern' match
59+ where
60+ match :: JS -> StateT PrinterState Maybe String
61+ match (JSNumericLiteral n) = return $ either show show n
62+ match (JSStringLiteral s) = return $ show s
63+ match (JSBooleanLiteral True) = return "true"
64+ match (JSBooleanLiteral False) = return "false"
65+ match (JSArrayLiteral xs) = fmap concat $ sequence
66+ [ return "[ "
67+ , fmap (intercalate ", ") $ forM xs prettyPrintJS'
68+ , return " ]"
69+ ]
70+ match (JSObjectLiteral []) = return "{}"
71+ match (JSObjectLiteral ps) = fmap concat $ sequence
72+ [ return "{\n"
73+ , withIndent $ do
74+ jss <- forM ps $ \(key, value) -> fmap ((key ++ ": ") ++) . prettyPrintJS' $ value
75+ indentString <- currentIndent
76+ return $ intercalate ", \n" $ map (indentString ++) jss
77+ , return "\n"
78+ , currentIndent
79+ , return "}"
80+ ]
81+ match (JSBlock sts) = fmap concat $ sequence
82+ [ return "{\n"
83+ , withIndent $ prettyStatements sts
84+ , return "\n"
85+ , currentIndent
86+ , return "}"
87+ ]
88+ match (JSVar ident) = return ident
89+ match (JSVariableIntroduction ident value) = fmap concat $ sequence
90+ [ return "var "
91+ , return ident
92+ , maybe (return "") (fmap (" = " ++) . prettyPrintJS') value
93+ ]
94+ match (JSAssignment target value) = fmap concat $ sequence
95+ [ prettyPrintJS' target
96+ , return " = "
97+ , prettyPrintJS' value
98+ ]
99+ match (JSWhile cond sts) = fmap concat $ sequence
100+ [ return "while ("
101+ , prettyPrintJS' cond
102+ , return ") "
103+ , prettyPrintJS' sts
104+ ]
105+ match (JSFor ident start end sts) = fmap concat $ sequence
106+ [ return $ "for (var " ++ ident ++ " = "
107+ , prettyPrintJS' start
108+ , return $ "; " ++ ident ++ " < "
109+ , prettyPrintJS' end
110+ , return $ "; " ++ ident ++ "++) "
111+ , prettyPrintJS' sts
112+ ]
113+ match (JSIfElse cond thens elses) = fmap concat $ sequence
114+ [ return "if ("
115+ , prettyPrintJS' cond
116+ , return ") "
117+ , prettyPrintJS' thens
118+ , maybe (return "") (fmap (" else " ++) . prettyPrintJS') elses
119+ ]
120+ match (JSReturn value) = fmap concat $ sequence
121+ [ return "return "
122+ , prettyPrintJS' value
123+ ]
124+ match (JSThrow value) = fmap concat $ sequence
125+ [ return "throw "
126+ , prettyPrintJS' value
127+ ]
128+ match (JSBreak lbl) = return $ "break " ++ lbl
129+ match (JSContinue lbl) = return $ "continue " ++ lbl
130+ match (JSLabel lbl js) = fmap concat $ sequence
131+ [ return $ lbl ++ ": "
132+ , prettyPrintJS' js
133+ ]
134+ match (JSRaw js) = return js
135+ match _ = mzero
136+
137+conditional :: Pattern PrinterState JS ((JS, JS), JS)
138+conditional = mkPattern match
139+ where
140+ match (JSConditional cond th el) = Just ((th, el), cond)
141+ match _ = Nothing
142+
143+accessor :: Pattern PrinterState JS (String, JS)
144+accessor = mkPattern match
145+ where
146+ match (JSAccessor prop val) = Just (prop, val)
147+ match _ = Nothing
148+
149+indexer :: Pattern PrinterState JS (String, JS)
150+indexer = mkPattern' match
151+ where
152+ match (JSIndexer index val) = (,) <$> prettyPrintJS' index <*> pure val
153+ match _ = mzero
154+
155+lam :: Pattern PrinterState JS ((Maybe String, [String]), JS)
156+lam = mkPattern match
157+ where
158+ match (JSFunction name args ret) = Just ((name, args), ret)
159+ match _ = Nothing
160+
161+app :: Pattern PrinterState JS (String, JS)
162+app = mkPattern' match
163+ where
164+ match (JSApp val args) = do
165+ jss <- mapM prettyPrintJS' args
166+ return (intercalate ", " jss, val)
167+ match _ = mzero
168+
169+typeOf :: Pattern PrinterState JS ((), JS)
170+typeOf = mkPattern match
171+ where
172+ match (JSTypeOf val) = Just ((), val)
173+ match _ = Nothing
174+
175+unary :: UnaryOperator -> String -> Operator PrinterState JS String
176+unary op str = Wrap match (++)
177+ where
178+ match :: Pattern PrinterState JS (String, JS)
179+ match = mkPattern match'
180+ where
181+ match' (JSUnary op' val) | op' == op = Just (str, val)
182+ match' _ = Nothing
183+
184+binary :: BinaryOperator -> String -> Operator PrinterState JS String
185+binary op str = AssocR match (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)
186+ where
187+ match :: Pattern PrinterState JS (JS, JS)
188+ match = mkPattern match'
189+ where
190+ match' (JSBinary op' v1 v2) | op' == op = Just (v1, v2)
191+ match' _ = Nothing
192+
193+prettyStatements :: [JS] -> StateT PrinterState Maybe String
194+prettyStatements sts = do
195+ jss <- forM sts prettyPrintJS'
196+ indentString <- currentIndent
197+ return $ intercalate "\n" $ map ((++ ";") . (indentString ++)) jss
198+
199+-- |
200+-- Generate a pretty-printed string representing a Javascript expression
201+--
202+prettyPrintJS1 :: JS -> String
203+prettyPrintJS1 = fromMaybe (error "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyPrintJS'
204+
205+-- |
206+-- Generate a pretty-printed string representing a collection of Javascript expressions at the same indentation level
207+--
208+prettyPrintJS :: [JS] -> String
209+prettyPrintJS = fromMaybe (error "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyStatements
210+
211+-- |
212+-- Generate an indented, pretty-printed string representing a Javascript expression
213+--
214+prettyPrintJS' :: JS -> StateT PrinterState Maybe String
215+prettyPrintJS' = A.runKleisli $ runPattern matchValue
216+ where
217+ matchValue :: Pattern PrinterState JS String
218+ matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)
219+ operators :: OperatorTable PrinterState JS String
220+ operators =
221+ OperatorTable [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ]
222+ , [ Wrap indexer $ \index val -> val ++ "[" ++ index ++ "]" ]
223+ , [ Wrap app $ \args val -> val ++ "(" ++ args ++ ")" ]
224+ , [ Wrap lam $ \(name, args) ret -> "function "
225+ ++ fromMaybe "" name
226+ ++ "(" ++ intercalate ", " args ++ ") "
227+ ++ ret ]
228+ , [ Wrap conditional $ \(th, el) cond -> cond ++ " ? " ++ prettyPrintJS1 th ++ " : " ++ prettyPrintJS1 el ]
229+ , [ binary LessThan "<" ]
230+ , [ binary LessThanOrEqualTo "<=" ]
231+ , [ binary GreaterThan ">" ]
232+ , [ binary GreaterThanOrEqualTo ">=" ]
233+ , [ Wrap typeOf $ \_ s -> "typeof " ++ s ]
234+ , [ unary Not "!" ]
235+ , [ unary BitwiseNot "~" ]
236+ , [ unary Negate "-" ]
237+ , [ unary Positive "+" ]
238+ , [ binary Multiply "*" ]
239+ , [ binary Divide "/" ]
240+ , [ binary Modulus "%" ]
241+ , [ binary Add "+" ]
242+ , [ binary Subtract "-" ]
243+ , [ binary ShiftLeft "<<" ]
244+ , [ binary ShiftRight ">>" ]
245+ , [ binary ZeroFillShiftRight ">>>" ]
246+ , [ binary EqualTo "===" ]
247+ , [ binary NotEqualTo "!==" ]
248+ , [ binary BitwiseAnd "&" ]
249+ , [ binary BitwiseXor "^" ]
250+ , [ binary BitwiseOr "|" ]
251+ , [ binary And "&&" ]
252+ , [ binary Or "||" ]
253+ ]
src/Language/PureScript/Pretty/Kinds.hsnew file+60
@@ -0,0 +1,60 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Pretty.Kinds
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+-- Pretty printer for kinds
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Pretty.Kinds (
17+ prettyPrintKind
18+) where
19+
20+import Data.Maybe (fromMaybe)
21+
22+import Control.Arrow (ArrowPlus(..))
23+import Control.PatternArrows
24+import Control.Monad.Unify
25+
26+import Language.PureScript.Kinds
27+import Language.PureScript.Pretty.Common
28+
29+typeLiterals :: Pattern () Kind String
30+typeLiterals = mkPattern match
31+ where
32+ match Star = Just "*"
33+ match Bang = Just "!"
34+ match (KUnknown (Unknown u)) = Just $ 'u' : show u
35+ match _ = Nothing
36+
37+matchRow :: Pattern () Kind ((), Kind)
38+matchRow = mkPattern match
39+ where
40+ match (Row k) = Just ((), k)
41+ match _ = Nothing
42+
43+funKind :: Pattern () Kind (Kind, Kind)
44+funKind = mkPattern match
45+ where
46+ match (FunKind arg ret) = Just (arg, ret)
47+ match _ = Nothing
48+
49+-- |
50+-- Generate a pretty-printed string representing a Kind
51+--
52+prettyPrintKind :: Kind -> String
53+prettyPrintKind = fromMaybe (error "Incomplete pattern") . pattern matchKind ()
54+ where
55+ matchKind :: Pattern () Kind String
56+ matchKind = buildPrettyPrinter operators (typeLiterals <+> fmap parens matchKind)
57+ operators :: OperatorTable () Kind String
58+ operators =
59+ OperatorTable [ [ Wrap matchRow $ \_ k -> "# " ++ k]
60+ , [ AssocR funKind $ \arg ret -> arg ++ " -> " ++ ret ] ]
src/Language/PureScript/Pretty/Types.hsnew file+98
@@ -0,0 +1,98 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Pretty.Types
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+-- Pretty printer for Types
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Pretty.Types (
17+ prettyPrintType,
18+ prettyPrintRow
19+) where
20+
21+import Data.Maybe (fromMaybe)
22+import Data.List (intercalate)
23+import Data.Generics (mkT, everywhere)
24+
25+import Control.Arrow ((<+>))
26+import Control.PatternArrows
27+import Control.Monad.Unify
28+
29+import Language.PureScript.Types
30+import Language.PureScript.Pretty.Common
31+
32+typeLiterals :: Pattern () Type String
33+typeLiterals = mkPattern match
34+ where
35+ match (Object row) = Just $ "{ " ++ prettyPrintRow row ++ " }"
36+ match (TypeVar var) = Just var
37+ match (PrettyPrintArray ty) = Just $ "[" ++ prettyPrintType ty ++ "]"
38+ match (TypeConstructor ctor) = Just $ show ctor
39+ match (TUnknown (Unknown u)) = Just $ 'u' : show u
40+ match (Skolem s _) = Just $ 's' : show s
41+ match (ConstrainedType deps ty) = Just $ "(" ++ intercalate "," (map (\(pn, ty') -> show pn ++ " (" ++ unwords (map prettyPrintType ty') ++ ")") deps) ++ ") => " ++ prettyPrintType ty
42+ match (SaturatedTypeSynonym name args) = Just $ show name ++ "<" ++ intercalate "," (map prettyPrintType args) ++ ">"
43+ match (ForAll ident ty _) = Just $ "forall " ++ ident ++ ". " ++ prettyPrintType ty
44+ match REmpty = Just "()"
45+ match row@RCons{} = Just $ '(' : prettyPrintRow row ++ ")"
46+ match _ = Nothing
47+
48+-- |
49+-- Generate a pretty-printed string representing a Row
50+--
51+prettyPrintRow :: Type -> String
52+prettyPrintRow = (\(tys, rest) -> intercalate ", " (map (uncurry nameAndTypeToPs) tys) ++ tailToPs rest) . toList []
53+ where
54+ nameAndTypeToPs :: String -> Type -> String
55+ nameAndTypeToPs name ty = name ++ " :: " ++ prettyPrintType ty
56+ tailToPs :: Type -> String
57+ tailToPs REmpty = ""
58+ tailToPs (TUnknown (Unknown u)) = " | u" ++ show u
59+ tailToPs (TypeVar var) = " | " ++ var
60+ tailToPs (Skolem s _) = " | s" ++ show s
61+ tailToPs _ = error "Invalid row tail"
62+ toList :: [(String, Type)] -> Type -> ([(String, Type)], Type)
63+ toList tys (RCons name ty row) = toList ((name, ty):tys) row
64+ toList tys r = (tys, r)
65+
66+typeApp :: Pattern () Type (Type, Type)
67+typeApp = mkPattern match
68+ where
69+ match (TypeApp f x) = Just (f, x)
70+ match _ = Nothing
71+
72+appliedFunction :: Pattern () Type (Type, Type)
73+appliedFunction = mkPattern match
74+ where
75+ match (PrettyPrintFunction arg ret) = Just (arg, ret)
76+ match _ = Nothing
77+
78+insertPlaceholders :: Type -> Type
79+insertPlaceholders = everywhere (mkT convert)
80+ where
81+ convert (TypeApp (TypeApp f arg) ret) | f == tyFunction = PrettyPrintFunction arg ret
82+ convert (TypeApp a el) | a == tyArray = PrettyPrintArray el
83+ convert other = other
84+
85+-- |
86+-- Generate a pretty-printed string representing a Type
87+--
88+prettyPrintType :: Type -> String
89+prettyPrintType = fromMaybe (error "Incomplete pattern") . pattern matchType () . insertPlaceholders
90+ where
91+ matchType :: Pattern () Type String
92+ matchType = buildPrettyPrinter operators (typeLiterals <+> fmap parens matchType)
93+ operators :: OperatorTable () Type String
94+ operators =
95+ OperatorTable [ [ AssocL typeApp $ \f x -> f ++ " " ++ x ]
96+ , [ AssocR appliedFunction $ \arg ret -> arg ++ " -> " ++ ret
97+ ]
98+ ]
src/Language/PureScript/Pretty/Values.hsnew file+149
@@ -0,0 +1,149 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Pretty.Values
4+-- Copyright : Kinds.hs(c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+-- Pretty printer for values
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Pretty.Values (
17+ prettyPrintValue,
18+ prettyPrintBinder
19+) where
20+
21+import Data.Maybe (fromMaybe)
22+import Data.List (intercalate)
23+import Control.Arrow ((<+>))
24+import Control.PatternArrows
25+
26+import Language.PureScript.Types
27+import Language.PureScript.Values
28+import Language.PureScript.Pretty.Common
29+import Language.PureScript.Pretty.Types
30+
31+literals :: Pattern () Value String
32+literals = mkPattern match
33+ where
34+ match (NumericLiteral n) = Just $ either show show n
35+ match (StringLiteral s) = Just $ show s
36+ match (BooleanLiteral True) = Just "true"
37+ match (BooleanLiteral False) = Just "false"
38+ match (ArrayLiteral xs) = Just $ "[" ++ intercalate ", " (map prettyPrintValue xs) ++ "]"
39+ match (ObjectLiteral ps) = Just $ "{" ++ intercalate ", " (map (uncurry prettyPrintObjectProperty) ps) ++ "}"
40+ match (Constructor name) = Just $ show name
41+ match (Case values binders) = Just $ "case " ++ unwords (map prettyPrintValue values) ++
42+ " of { " ++ intercalate " ; " (map prettyPrintCaseAlternative binders) ++ " }"
43+ match (Var ident) = Just $ show ident
44+ match (Do els) = Just $ " do { " ++ intercalate "; " (map prettyPrintDoNotationElement els) ++ " }"
45+ match (TypeClassDictionary _ _) = error "Type class dictionary was not replaced"
46+ match _ = Nothing
47+
48+prettyPrintCaseAlternative :: ([Binder], Maybe Guard, Value) -> String
49+prettyPrintCaseAlternative (binders, grd, val) = "(" ++ intercalate ", " (map prettyPrintBinder binders) ++ ") " ++
50+ maybe "" (("| " ++) . prettyPrintValue) grd ++ " -> " ++ prettyPrintValue val
51+
52+ifThenElse :: Pattern () Value ((Value, Value), Value)
53+ifThenElse = mkPattern match
54+ where
55+ match (IfThenElse cond th el) = Just ((th, el), cond)
56+ match _ = Nothing
57+
58+accessor :: Pattern () Value (String, Value)
59+accessor = mkPattern match
60+ where
61+ match (Accessor prop val) = Just (prop, val)
62+ match _ = Nothing
63+
64+objectUpdate :: Pattern () Value ([String], Value)
65+objectUpdate = mkPattern match
66+ where
67+ match (ObjectUpdate o ps) = Just (flip map ps $ \(key, val) -> key ++ " = " ++ prettyPrintValue val, o)
68+ match _ = Nothing
69+
70+app :: Pattern () Value (String, Value)
71+app = mkPattern match
72+ where
73+ match (App val arg) = Just (prettyPrintValue arg, val)
74+ match _ = Nothing
75+
76+lam :: Pattern () Value (String, Value)
77+lam = mkPattern match
78+ where
79+ match (Abs (Left arg) val) = Just (show arg, val)
80+ match _ = Nothing
81+
82+typed :: Pattern () Value (Type, Value)
83+typed = mkPattern match
84+ where
85+ match (TypedValue _ val ty) = Just (ty, val)
86+ match _ = Nothing
87+
88+prettyPrintDoNotationElement :: DoNotationElement -> String
89+prettyPrintDoNotationElement (DoNotationValue val) = prettyPrintValue val
90+prettyPrintDoNotationElement (DoNotationBind binder val) = prettyPrintBinder binder ++ " <- " ++ prettyPrintValue val
91+prettyPrintDoNotationElement (DoNotationLet binder val) = "let " ++ prettyPrintBinder binder ++ " = " ++ prettyPrintValue val
92+
93+-- |
94+-- Generate a pretty-printed string representing a Value
95+--
96+prettyPrintValue :: Value -> String
97+prettyPrintValue = fromMaybe (error "Incomplete pattern") . pattern matchValue ()
98+ where
99+ matchValue :: Pattern () Value String
100+ matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)
101+ operators :: OperatorTable () Value String
102+ operators =
103+ OperatorTable [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ]
104+ , [ Wrap objectUpdate $ \ps val -> val ++ "{ " ++ intercalate ", " ps ++ " }" ]
105+ , [ Wrap app $ \arg val -> val ++ "(" ++ arg ++ ")" ]
106+ , [ Split lam $ \arg val -> "\\" ++ arg ++ " -> " ++ prettyPrintValue val ]
107+ , [ Wrap ifThenElse $ \(th, el) cond -> cond ++ " ? " ++ prettyPrintValue th ++ " : " ++ prettyPrintValue el ]
108+ , [ Wrap typed $ \ty val -> val ++ " :: " ++ prettyPrintType ty ]
109+ ]
110+
111+prettyPrintBinderAtom :: Pattern () Binder String
112+prettyPrintBinderAtom = mkPattern match
113+ where
114+ match :: Binder -> Maybe String
115+ match NullBinder = Just "_"
116+ match (StringBinder str) = Just $ show str
117+ match (NumberBinder num) = Just $ either show show num
118+ match (BooleanBinder True) = Just "true"
119+ match (BooleanBinder False) = Just "false"
120+ match (VarBinder ident) = Just $ show ident
121+ match (ConstructorBinder ctor args) = Just $ show ctor ++ " " ++ unwords (map (parens . prettyPrintBinder) args)
122+ match (ObjectBinder bs) = Just $ "{ " ++ intercalate ", " (map (uncurry prettyPrintObjectPropertyBinder) bs) ++ " }"
123+ match (ArrayBinder bs) = Just $ "[ " ++ intercalate ", " (map prettyPrintBinder bs) ++ " ]"
124+ match (NamedBinder ident binder) = Just $ show ident ++ "@" ++ prettyPrintBinder binder
125+ match _ = Nothing
126+
127+-- |
128+-- Generate a pretty-printed string representing a Binder
129+--
130+prettyPrintBinder :: Binder -> String
131+prettyPrintBinder = fromMaybe (error "Incomplete pattern") . pattern matchBinder ()
132+ where
133+ matchBinder :: Pattern () Binder String
134+ matchBinder = buildPrettyPrinter operators (prettyPrintBinderAtom <+> fmap parens matchBinder)
135+ operators :: OperatorTable () Binder String
136+ operators =
137+ OperatorTable [ [ AssocR matchConsBinder (\b1 b2 -> b1 ++ " : " ++ b2) ] ]
138+
139+matchConsBinder :: Pattern () Binder (Binder, Binder)
140+matchConsBinder = mkPattern match'
141+ where
142+ match' (ConsBinder b1 b2) = Just (b1, b2)
143+ match' _ = Nothing
144+
145+prettyPrintObjectPropertyBinder :: String -> Binder -> String
146+prettyPrintObjectPropertyBinder key binder = key ++ ": " ++ prettyPrintBinder binder
147+
148+prettyPrintObjectProperty :: String -> Value -> String
149+prettyPrintObjectProperty key value = key ++ ": " ++ prettyPrintValue value
src/Language/PureScript/Scope.hsnew file+61
@@ -0,0 +1,61 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Scope
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+-- Utility functions for working with names in scope
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Scope (
17+ usedNames,
18+ unusedNames
19+) where
20+
21+import Control.Applicative ((<$>))
22+
23+import Data.Data
24+import Data.List ((\\), nub)
25+import Data.Generics (extQ, mkQ, everything)
26+
27+import Language.PureScript.Values
28+import Language.PureScript.Names
29+import Language.PureScript.CodeGen.JS.AST
30+
31+-- |
32+-- Gather all used names appearing inside a value
33+--
34+usedNames :: (Data d) => d -> [Ident]
35+usedNames val = nub $ everything (++) (mkQ [] namesV `extQ` namesB `extQ` namesJS) val
36+ where
37+ namesV :: Value -> [Ident]
38+ namesV (Abs (Left arg) _) = [arg]
39+ namesV (Var (Qualified Nothing name)) = [name]
40+ namesV _ = []
41+ namesB :: Binder -> [Ident]
42+ namesB (VarBinder name) = [name]
43+ namesB _ = []
44+ namesJS :: JS -> [Ident]
45+ namesJS (JSVar name) = [Ident name]
46+ namesJS (JSFunction (Just name) args _) = Ident name : (Ident <$> args)
47+ namesJS (JSFunction Nothing args _) = Ident <$> args
48+ namesJS (JSVariableIntroduction name _) = [Ident name]
49+ namesJS (JSFor name _ _ _) = [Ident name]
50+ namesJS _ = []
51+
52+-- |
53+-- Generate a set of names which are unused inside a value, of the form @_{n}@ for an integer @n@
54+--
55+unusedNames :: (Data d) => d -> [Ident]
56+unusedNames val =
57+ let
58+ allNames = usedNames val
59+ varNames = map (Ident . ('_' :) . show) ([1..] :: [Int])
60+ in
61+ varNames \\ allNames
src/Language/PureScript/Sugar.hsnew file+57
@@ -0,0 +1,57 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Sugar
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+-- Desugaring passes
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Sugar (desugar, module S) where
17+
18+import Control.Monad
19+import Control.Arrow ((>>>))
20+
21+import Language.PureScript.Declarations
22+
23+import Language.PureScript.Sugar.Operators as S
24+import Language.PureScript.Sugar.DoNotation as S
25+import Language.PureScript.Sugar.CaseDeclarations as S
26+import Language.PureScript.Sugar.TypeDeclarations as S
27+import Language.PureScript.Sugar.BindingGroups as S
28+import Language.PureScript.Sugar.TypeClasses as S
29+import Language.PureScript.Sugar.Let as S
30+import Language.PureScript.Sugar.Names as S
31+
32+-- |
33+-- The desugaring pipeline proceeds as follows:
34+--
35+-- * Desugar let bindings
36+--
37+-- * Introduce type synonyms for type class dictionaries
38+--
39+-- * Rebracket user-defined binary operators
40+--
41+-- * Desugar do-notation using the @Prelude.Monad@ type class
42+--
43+-- * Desugar top-level case declarations into explicit case expressions
44+--
45+-- * Desugar type declarations into value declarations with explicit type annotations
46+--
47+-- * Group mutually recursive value and data declarations into binding groups.
48+--
49+desugar :: [Module] -> Either String [Module]
50+desugar = rename
51+ >=> desugarTypeClasses
52+ >=> rebracket
53+ >=> desugarDo
54+ >=> desugarLetBindings
55+ >>> desugarCasesModule
56+ >=> desugarTypeDeclarationsModule
57+ >=> createBindingGroupsModule
src/Language/PureScript/Sugar/BindingGroups.hsnew file+121
@@ -0,0 +1,121 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.BindingGroups
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+-- This module implements the desugaring pass which creates binding groups from sets of
13+-- mutually-recursive value declarations and mutually-recursive type declarations.
14+--
15+-----------------------------------------------------------------------------
16+
17+module Language.PureScript.Sugar.BindingGroups (
18+ createBindingGroups,
19+ createBindingGroupsModule,
20+ collapseBindingGroups,
21+ collapseBindingGroupsModule
22+) where
23+
24+import Data.Data
25+import Data.Graph
26+import Data.Generics
27+import Data.List (nub, intersect)
28+import Control.Applicative ((<$>))
29+
30+import Language.PureScript.Declarations
31+import Language.PureScript.Names
32+import Language.PureScript.Values
33+import Language.PureScript.Types
34+
35+-- |
36+-- Replace all sets of mutually-recursive declarations in a module with binding groups
37+--
38+createBindingGroupsModule :: [Module] -> Either String [Module]
39+createBindingGroupsModule = mapM $ \(Module name ds) -> Module name <$> createBindingGroups name ds
40+
41+-- |
42+-- Collapse all binding groups in a module to individual declarations
43+--
44+collapseBindingGroupsModule :: [Module] -> [Module]
45+collapseBindingGroupsModule = map $ \(Module name ds) -> Module name (collapseBindingGroups ds)
46+
47+-- |
48+-- Replace all sets of mutually-recursive declarations with binding groups
49+--
50+createBindingGroups :: ModuleName -> [Declaration] -> Either String [Declaration]
51+createBindingGroups moduleName ds = do
52+ let values = filter isValueDecl ds
53+ dataDecls = filter isDataDecl ds
54+ allProperNames = map getProperName dataDecls
55+ dataVerts = map (\d -> (d, getProperName d, usedProperNames moduleName d `intersect` allProperNames)) dataDecls
56+ dataBindingGroupDecls <- mapM toDataBindingGroup $ stronglyConnComp dataVerts
57+ let allIdents = map getIdent values
58+ valueVerts = map (\d -> (d, getIdent d, usedIdents moduleName d `intersect` allIdents)) values
59+ bindingGroupDecls = map toBindingGroup $ stronglyConnComp valueVerts
60+ return $ filter isImportDecl ds ++
61+ filter isExternDataDecl ds ++
62+ dataBindingGroupDecls ++
63+ filter isTypeClassDeclaration ds ++
64+ filter isFixityDecl ds ++
65+ filter isExternDecl ds ++
66+ bindingGroupDecls
67+
68+-- |
69+-- Collapse all binding groups to individual declarations
70+--
71+collapseBindingGroups :: [Declaration] -> [Declaration]
72+collapseBindingGroups = concatMap go
73+ where
74+ go (DataBindingGroupDeclaration ds) = ds
75+ go (BindingGroupDeclaration ds) = map (\(ident, val) -> ValueDeclaration ident [] Nothing val) ds
76+ go other = [other]
77+
78+usedIdents :: (Data d) => ModuleName -> d -> [Ident]
79+usedIdents moduleName = nub . everything (++) (mkQ [] names)
80+ where
81+ names :: Value -> [Ident]
82+ names (Var (Qualified Nothing name)) = [name]
83+ names (Var (Qualified (Just moduleName') name)) | moduleName == moduleName' = [name]
84+ names _ = []
85+
86+usedProperNames :: (Data d) => ModuleName -> d -> [ProperName]
87+usedProperNames moduleName = nub . everything (++) (mkQ [] names)
88+ where
89+ names :: Type -> [ProperName]
90+ names (TypeConstructor (Qualified (Just moduleName') name)) | moduleName == moduleName' = [name]
91+ names _ = []
92+
93+getIdent :: Declaration -> Ident
94+getIdent (ValueDeclaration ident _ _ _) = ident
95+getIdent _ = error "Expected ValueDeclaration"
96+
97+getProperName :: Declaration -> ProperName
98+getProperName (DataDeclaration pn _ _) = pn
99+getProperName (TypeSynonymDeclaration pn _ _) = pn
100+getProperName _ = error "Expected DataDeclaration"
101+
102+toBindingGroup :: SCC Declaration -> Declaration
103+toBindingGroup (AcyclicSCC d) = d
104+toBindingGroup (CyclicSCC [d]) = d
105+toBindingGroup (CyclicSCC ds') = BindingGroupDeclaration $ map fromValueDecl ds'
106+
107+toDataBindingGroup :: SCC Declaration -> Either String Declaration
108+toDataBindingGroup (AcyclicSCC d) = return d
109+toDataBindingGroup (CyclicSCC [TypeSynonymDeclaration pn _ _]) = Left $ "Cycle in type synonym " ++ show pn
110+toDataBindingGroup (CyclicSCC [d]) = return d
111+toDataBindingGroup (CyclicSCC ds')
112+ | all isTypeSynonym ds' = Left "Cycle in type synonyms"
113+ | otherwise = return $ DataBindingGroupDeclaration ds'
114+ where
115+ isTypeSynonym TypeSynonymDeclaration{} = True
116+ isTypeSynonym _ = False
117+
118+fromValueDecl :: Declaration -> (Ident, Value)
119+fromValueDecl (ValueDeclaration ident [] Nothing val) = (ident, val)
120+fromValueDecl ValueDeclaration{} = error "Binders should have been desugared"
121+fromValueDecl _ = error "Expected ValueDeclaration"
src/Language/PureScript/Sugar/CaseDeclarations.hsnew file+83
@@ -0,0 +1,83 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.CaseDeclarations
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+-- This module implements the desugaring pass which replaces top-level binders with
13+-- case expressions.
14+--
15+-----------------------------------------------------------------------------
16+
17+module Language.PureScript.Sugar.CaseDeclarations (
18+ desugarCases,
19+ desugarCasesModule
20+) where
21+
22+import Data.List (groupBy)
23+import Data.Generics (mkT, everywhere)
24+
25+import Control.Applicative ((<$>))
26+import Control.Monad (forM, join, unless)
27+import Control.Monad.Error.Class
28+
29+import Language.PureScript.Names
30+import Language.PureScript.Values
31+import Language.PureScript.Declarations
32+import Language.PureScript.Scope
33+
34+-- |
35+-- Replace all top-level binders in a module with case expressions.
36+--
37+desugarCasesModule :: [Module] -> Either String [Module]
38+desugarCasesModule ms = forM ms $ \(Module name ds) -> Module name <$> (desugarCases . desugarAbs $ ds)
39+
40+desugarAbs :: [Declaration] -> [Declaration]
41+desugarAbs = everywhere (mkT replace)
42+ where
43+ replace (Abs (Right binder) val) =
44+ let
45+ ident = head $ unusedNames (binder, val)
46+ in
47+ Abs (Left ident) $ Case [Var (Qualified Nothing ident)] [([binder], Nothing, val)]
48+ replace other = other
49+
50+-- |
51+-- Replace all top-level binders with case expressions.
52+--
53+desugarCases :: [Declaration] -> Either String [Declaration]
54+desugarCases = fmap join . mapM toDecls . groupBy inSameGroup
55+
56+inSameGroup :: Declaration -> Declaration -> Bool
57+inSameGroup (ValueDeclaration ident1 _ _ _) (ValueDeclaration ident2 _ _ _) = ident1 == ident2
58+inSameGroup _ _ = False
59+
60+toDecls :: [Declaration] -> Either String [Declaration]
61+toDecls d@[ValueDeclaration _ [] Nothing _] = return d
62+toDecls ds@(ValueDeclaration ident bs _ _ : _) = do
63+ let tuples = map toTuple ds
64+ unless (all ((== length bs) . length . fst) tuples) $
65+ throwError $ "Argument list lengths differ in declaration " ++ show ident
66+ return [makeCaseDeclaration ident tuples]
67+toDecls ds = return ds
68+
69+toTuple :: Declaration -> ([Binder], (Maybe Guard, Value))
70+toTuple (ValueDeclaration _ bs g val) = (bs, (g, val))
71+toTuple _ = error "Not a value declaration"
72+
73+makeCaseDeclaration :: Ident -> [([Binder], (Maybe Guard, Value))] -> Declaration
74+makeCaseDeclaration ident alternatives =
75+ let
76+ argPattern = length . fst . head $ alternatives
77+ args = take argPattern $ unusedNames (ident, alternatives)
78+ vars = map (Var . Qualified Nothing) args
79+ binders = [ (bs, g, val) | (bs, (g, val)) <- alternatives ]
80+ value = foldr (\arg ret -> Abs (Left arg) ret) (Case vars binders) args
81+ in
82+ ValueDeclaration ident [] Nothing value
83+
src/Language/PureScript/Sugar/DoNotation.hsnew file+62
@@ -0,0 +1,62 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Sugar.DoNotation
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+-- This module implements the desugaring pass which replaces do-notation statements with
13+-- appropriate calls to (>>=) from the Prelude.Monad type class.
14+--
15+-----------------------------------------------------------------------------
16+
17+module Language.PureScript.Sugar.DoNotation (
18+ desugarDo
19+) where
20+
21+import Data.Data
22+import Data.Generics
23+
24+import Language.PureScript.Values
25+import Language.PureScript.Names
26+import Language.PureScript.Scope
27+
28+-- |
29+-- Replace all @DoNotationBind@ and @DoNotationValue@ constructors with applications of the Prelude.(>>=) function,
30+-- and all @DoNotationLet@ constructors with let expressions.
31+--
32+desugarDo :: (Data d) => d -> Either String d
33+desugarDo = everywhereM (mkM replace)
34+ where
35+ prelude :: ModuleName
36+ prelude = ModuleName [ProperName "Prelude"]
37+ ret :: Value
38+ ret = Var (Qualified (Just prelude) (Ident "ret"))
39+ bind :: Value
40+ bind = Var (Qualified (Just prelude) (Op ">>="))
41+ replace :: Value -> Either String Value
42+ replace (Do els) = go els
43+ replace other = return other
44+ go :: [DoNotationElement] -> Either String Value
45+ go [] = error "The impossible happened in desugarDo"
46+ go [DoNotationValue val] = return val
47+ go (DoNotationValue val : rest) = do
48+ rest' <- go rest
49+ return $ App (App bind val) (Abs (Left (Ident "_")) rest')
50+ go [DoNotationBind _ _] = Left "Bind statement cannot be the last statement in a do block"
51+ go (DoNotationBind NullBinder val : rest) = go (DoNotationValue val : rest)
52+ go (DoNotationBind (VarBinder ident) val : rest) = do
53+ rest' <- go rest
54+ return $ App (App bind val) (Abs (Left ident) rest')
55+ go (DoNotationBind binder val : rest) = do
56+ rest' <- go rest
57+ let ident = head $ unusedNames rest'
58+ return $ App (App bind val) (Abs (Left ident) (Case [Var (Qualified Nothing ident)] [([binder], Nothing, rest')]))
59+ go [DoNotationLet _ _] = Left "Let statement cannot be the last statement in a do block"
60+ go (DoNotationLet binder val : rest) = do
61+ rest' <- go rest
62+ return $ Case [val] [([binder], Nothing, rest')]
src/Language/PureScript/Sugar/Let.hsnew file+32
@@ -0,0 +1,32 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Sugar.Let
4+-- Copyright : (c) Phil Freeman 2014
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+-- This module implements the desugaring pass which turns let bindings into function applications.
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.Sugar.Let (
17+ desugarLetBindings
18+) where
19+
20+import Data.Generics (mkT, everywhere)
21+
22+import Language.PureScript.Values
23+import Language.PureScript.Declarations
24+
25+-- |
26+-- Turn let bindings into function applications
27+--
28+desugarLetBindings :: [Module] -> [Module]
29+desugarLetBindings = everywhere (mkT go)
30+ where
31+ go (Let binder value result) = Case [value] [([binder], Nothing, result)]
32+ go other = other
src/Language/PureScript/Sugar/Names.hsnew file+239
@@ -0,0 +1,239 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Sugar.Names
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+module Language.PureScript.Sugar.Names (
16+ rename
17+) where
18+
19+import Data.Maybe (fromMaybe)
20+import Data.Generics (extM, mkM, everywhereM)
21+import Data.List (intersect)
22+
23+import Control.Applicative ((<$>), (<*>))
24+import Control.Monad (forM_, unless, foldM, liftM)
25+
26+import qualified Data.Map as M
27+import qualified Data.Set as S
28+
29+import Language.PureScript.Declarations
30+import Language.PureScript.Names
31+import Language.PureScript.Types
32+import Language.PureScript.Values
33+
34+-- |
35+-- The global export environment - every declaration exported from every module
36+--
37+data ExportEnvironment = ExportEnvironment
38+ -- |
39+ -- The types exported from each module
40+ --
41+ { exportedTypes :: M.Map ModuleName (S.Set ProperName)
42+ -- |
43+ -- The data constructors exported from each module, grouped by type constructor
44+ --
45+ , exportedDataConstructors :: M.Map ModuleName (S.Set (ProperName, [ProperName]))
46+ -- |
47+ -- The classes exported from each module
48+ --
49+ , exportedTypeClasses :: M.Map ModuleName (S.Set ProperName)
50+ } deriving (Show)
51+
52+-- |
53+-- An imported environment for a particular module. This also contains the module's own members.
54+--
55+data ImportEnvironment = ImportEnvironment
56+ -- |
57+ -- Local names for types within a module mapped to to their qualified names
58+ --
59+ { importedTypes :: M.Map ProperName (Qualified ProperName)
60+ -- |
61+ -- Local names for data constructors within a module mapped to to their qualified names
62+ --
63+ , importedDataConstructors :: M.Map ProperName (Qualified ProperName)
64+ -- |
65+ -- Local names for classes within a module mapped to to their qualified names
66+ --
67+ , importedTypeClasses :: M.Map ProperName (Qualified ProperName)
68+ } deriving (Show)
69+
70+-- |
71+-- Adds a type belonging to a module to the export environment.
72+--
73+addType :: ExportEnvironment -> ModuleName -> ProperName -> Either String ExportEnvironment
74+addType env mn name = do
75+ types <- addExport (exportedTypes env) mn name
76+ return $ env { exportedTypes = types }
77+
78+-- |
79+-- Adds a group of data constructors with their associated type constructor the export environment.
80+--
81+addDataConstructors :: ExportEnvironment -> ModuleName -> ProperName -> [ProperName] -> Either String ExportEnvironment
82+addDataConstructors env mn tcon dcons = do
83+ dataConstructors <- addExport (exportedDataConstructors env) mn (tcon, dcons)
84+ return $ env { exportedDataConstructors = dataConstructors }
85+
86+-- |
87+-- Adds a class to the export environment.
88+--
89+addTypeclass :: ExportEnvironment -> ModuleName -> ProperName -> Either String ExportEnvironment
90+addTypeclass env mn name = do
91+ classes <- addExport (exportedTypeClasses env) mn name
92+ return $ env { exportedTypeClasses = classes }
93+
94+-- |
95+-- Adds an export to a map of exports of that type.
96+--
97+addExport :: (Ord s, Show s) => M.Map ModuleName (S.Set s) -> ModuleName -> s -> Either String (M.Map ModuleName (S.Set s))
98+addExport exports mn name = case M.lookup mn exports of
99+ Just s -> if S.member name s
100+ then Left $ "Module '" ++ show mn ++ "' has multiple definitions for '" ++ show name ++ "'"
101+ else Right $ M.insert mn (S.insert name s) exports
102+ Nothing -> Right $ M.insert mn (S.singleton name) exports
103+
104+-- |
105+-- Replaces all local names with qualified names within a set of modules.
106+--
107+rename :: [Module] -> Either String [Module]
108+rename modules = do
109+ exports <- findExports modules
110+ mapM (renameInModule' exports) modules
111+ where
112+ renameInModule' exports m = do
113+ imports <- resolveImports exports m
114+ renameInModule imports m
115+
116+-- |
117+-- Replaces all local names with qualified names within a module.
118+--
119+renameInModule :: ImportEnvironment -> Module -> Either String Module
120+renameInModule imports (Module mn decls) =
121+ Module mn <$> mapM updateDecl decls >>= everywhereM (mkM updateType `extM` updateValue `extM` updateBinder)
122+ where
123+ updateDecl (TypeInstanceDeclaration cs (Qualified Nothing cn) ts ds) = do
124+ cn' <- updateClassName cn
125+ cs' <- updateConstraints cs
126+ return $ TypeInstanceDeclaration cs' cn' ts ds
127+ updateDecl d = return d
128+ updateValue (Constructor (Qualified Nothing nm)) = liftM Constructor $ updateDataConstructorName nm
129+ updateValue v = return v
130+ updateBinder (ConstructorBinder (Qualified Nothing nm) b) = liftM (`ConstructorBinder` b) $ updateDataConstructorName nm
131+ updateBinder v = return v
132+ updateType (TypeConstructor (Qualified Nothing nm)) = liftM TypeConstructor $ updateTypeName nm
133+ updateType (SaturatedTypeSynonym (Qualified Nothing nm) tys) = do
134+ nm' <- updateTypeName nm
135+ tys' <- mapM updateType tys
136+ return $ SaturatedTypeSynonym nm' tys'
137+ updateType (ConstrainedType cs t) = liftM (`ConstrainedType` t) $ updateConstraints cs
138+ updateType t = return t
139+ updateConstraints = mapM updateConstraint
140+ updateConstraint (Qualified Nothing nm, ts) = do
141+ nm' <- updateClassName nm
142+ return (nm', ts)
143+ updateConstraint other = return other
144+ updateTypeName = update "type" importedTypes
145+ updateClassName = update "typeclass" importedTypeClasses
146+ updateDataConstructorName = update "data constructor" importedDataConstructors
147+ update t get nm = maybe (Left $ "Unknown " ++ t ++ " '" ++ show nm ++ "' in module '" ++ show mn ++ "'") return $ M.lookup nm (get imports)
148+
149+-- |
150+-- Finds all exported declarations in a set of modules.
151+--
152+findExports :: [Module] -> Either String ExportEnvironment
153+findExports = foldM addModule (ExportEnvironment M.empty M.empty M.empty)
154+ where
155+ addModule env (Module mn ds) = foldM (addDecl mn) env ds
156+ addDecl mn env (TypeClassDeclaration tcn _ _) = addTypeclass env mn tcn
157+ addDecl mn env (DataDeclaration tn _ dcs) = do
158+ env' <- addDataConstructors env mn tn (map fst dcs)
159+ addType env' mn tn
160+ addDecl mn env (TypeSynonymDeclaration tn _ _) = addType env mn tn
161+ addDecl mn env (ExternDataDeclaration tn _) = addType env mn tn
162+ addDecl _ env _ = return env
163+
164+-- |
165+-- Type representing a set of declarations being explicitly imported from a module
166+--
167+type ExplicitImports = [ImportType]
168+
169+-- |
170+-- Finds the imports within a module, mapping the imported module name to an optional set of
171+-- explicitly imported declarations.
172+--
173+findImports :: [Declaration] -> M.Map ModuleName (Maybe ExplicitImports)
174+findImports = foldl findImports' M.empty
175+ where
176+ findImports' result (ImportDeclaration mn Nothing) = M.insert mn Nothing result
177+ findImports' result (ImportDeclaration mn (Just expl)) = M.insert mn (Just expl) result
178+ findImports' result _ = result
179+
180+-- |
181+-- Constructs a local environment for a module.
182+--
183+resolveImports :: ExportEnvironment -> Module -> Either String ImportEnvironment
184+resolveImports env (Module currentModule decls) = ImportEnvironment
185+ <$> resolve (exportedTypes env) (resolveDefs typeImports)
186+ <*> resolve (exportedDataConstructors env) resolveDcons
187+ <*> resolve (exportedTypeClasses env) (resolveDefs (const []))
188+ where
189+ -- A Map from module name to imports from that module, where Nothing indicates everything is to be imported
190+ scope :: M.Map ModuleName (Maybe ExplicitImports)
191+ scope = M.insert currentModule Nothing (findImports decls)
192+
193+ -- Resolve all exported names in a set by applying a type-specific resolver function
194+ resolve :: M.Map ModuleName (S.Set id) ->
195+ (M.Map ProperName (Qualified ProperName) -> ModuleName -> S.Set id -> Maybe ExplicitImports -> Either String (M.Map ProperName (Qualified ProperName))) ->
196+ Either String (M.Map ProperName (Qualified ProperName))
197+ resolve m f = foldM (\m' (mn, maybeExpl) -> f m' mn (fromMaybe S.empty $ mn `M.lookup` m) maybeExpl) M.empty (M.toList scope)
198+
199+ -- Resolve a single name by adding it to the Map with a specified ModuleName, checking first
200+ -- that the name does not currently exist in scope.
201+ resolveDef :: (Ord id, Show id) => ModuleName ->
202+ M.Map id (Qualified id) ->
203+ id ->
204+ Either String (M.Map id (Qualified id))
205+ resolveDef mn result name = case M.lookup name result of
206+ Nothing -> return $ M.insert name (Qualified (Just mn) name) result
207+ Just x@(Qualified (Just mn') _) -> Left $ "Module '" ++ show currentModule ++
208+ if mn' == currentModule || mn == currentModule
209+ then "' defines '" ++ show name ++ "' which conflicts with imported definition '" ++ show (Qualified (Just mn) name) ++ "'"
210+ else "' has conflicting imports for '" ++ show name ++ "': '" ++ show x ++ "', '" ++ show (Qualified (Just mn) name) ++ "'"
211+
212+ -- Resolve a set of ProperName exports for a specific imported set of names
213+ -- This function is used to resolve both types and type classes, hence the filter function as
214+ -- its first argument
215+ resolveDefs :: (ExplicitImports -> [ProperName]) ->
216+ M.Map ProperName (Qualified ProperName) ->
217+ ModuleName ->
218+ S.Set ProperName ->
219+ Maybe ExplicitImports ->
220+ Either String (M.Map ProperName (Qualified ProperName))
221+ resolveDefs filt result mn names maybeExpl = do
222+ names' <- case maybeExpl of
223+ Just expl -> do
224+ forM_ (filt expl) $ \name ->
225+ unless (name `S.member` names) $ Left $ show name ++ " is explictly imported but is not defined in module " ++ show mn
226+ return $ S.toList names `intersect` filt expl
227+ Nothing -> return $ S.toList names
228+ foldM (resolveDef mn) result names'
229+
230+ -- Resolve a set of data constructors keyed by their type constructor
231+ resolveDcons :: M.Map ProperName (Qualified ProperName) ->
232+ ModuleName ->
233+ S.Set (ProperName, [ProperName]) ->
234+ Maybe ExplicitImports ->
235+ Either String (M.Map ProperName (Qualified ProperName))
236+ resolveDcons result mn tcons maybeExpl = foldM (foldM $ resolveDef mn) result $ map snd $
237+ case maybeExpl of
238+ Just expl -> filter ((`elem` typeImports expl) . fst) (S.toList tcons)
239+ Nothing -> S.toList tcons
src/Language/PureScript/Sugar/Operators.hsnew file+118
@@ -0,0 +1,118 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Sugar.Operators
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+-- This module implements the desugaring pass which reapplies binary operators based
13+-- on their fixity data and removes explicit parentheses.
14+--
15+-- The value parser ignores fixity data when parsing binary operator applications, so
16+-- it is necessary to reorder them here.
17+--
18+-----------------------------------------------------------------------------
19+
20+{-# LANGUAGE Rank2Types #-}
21+
22+module Language.PureScript.Sugar.Operators (
23+ rebracket
24+) where
25+
26+import Language.PureScript.Names
27+import Language.PureScript.Declarations
28+import Language.PureScript.Values
29+
30+import Control.Applicative
31+import Control.Arrow (first)
32+import Control.Monad.State
33+
34+import Data.Function (on)
35+import Data.List (groupBy, sortBy)
36+
37+import qualified Data.Map as M
38+import qualified Data.Generics as G
39+import qualified Data.Generics.Extras as G
40+
41+import qualified Text.Parsec as P
42+import qualified Text.Parsec.Pos as P
43+import qualified Text.Parsec.Expr as P
44+
45+-- |
46+-- Remove explicit parentheses and reorder binary operator applications
47+--
48+rebracket :: [Module] -> Either String [Module]
49+rebracket = go M.empty []
50+ where
51+ go _ rb [] = return . reverse $ rb
52+ go m rb (Module name ds : ms) = do
53+ m' <- M.union m <$> collectFixities m name ds
54+ let opTable = customOperatorTable m'
55+ ds' <- G.everywhereM' (G.mkM (matchOperators name opTable)) ds
56+ go m' (Module name (G.everywhere (G.mkT removeParens) ds') : rb) ms
57+
58+removeParens :: Value -> Value
59+removeParens (Parens val) = val
60+removeParens val = val
61+
62+customOperatorTable :: M.Map (Qualified Ident) Fixity -> [[(Qualified Ident, Value -> Value -> Value, Associativity)]]
63+customOperatorTable fixities =
64+ let
65+ -- We make the assumption here that infix operators are not qualified. The parser currently enforces this.
66+ -- The fixity map can therefore map from module name/ident pairs to fixities, where the module name is the name
67+ -- of the module imported into, not from. This is useful in matchOp, but here we have to discard the module name to
68+ -- make sure that the generated code is correct.
69+ applyUserOp (Qualified _ name) t1 = App (App (Var (Qualified Nothing name)) t1)
70+ userOps = map (\(name, Fixity a p) -> (name, applyUserOp name, p, a)) . M.toList $ fixities
71+ sorted = sortBy (flip compare `on` (\(_, _, p, _) -> p)) userOps
72+ groups = groupBy ((==) `on` (\(_, _, p, _) -> p)) sorted
73+ in
74+ map (map (\(name, f, _, a) -> (name, f, a))) groups
75+
76+type Chain = [Either Value (Qualified Ident)]
77+
78+matchOperators :: ModuleName -> [[(Qualified Ident, Value -> Value -> Value, Associativity)]] -> Value -> Either String Value
79+matchOperators moduleName ops = G.everywhereM' (G.mkM parseChains)
80+ where
81+ parseChains :: Value -> Either String Value
82+ parseChains b@BinaryNoParens{} = bracketChain (extendChain b)
83+ parseChains other = return other
84+ extendChain :: Value -> Chain
85+ extendChain (BinaryNoParens name l r) = Left l : Right name : extendChain r
86+ extendChain other = [Left other]
87+ bracketChain :: Chain -> Either String Value
88+ bracketChain = either (Left . show) Right . P.parse (P.buildExpressionParser opTable parseValue <* P.eof) "operator expression"
89+ opTable = map (map (\(name, f, a) -> P.Infix (P.try (matchOp moduleName name) >> return f) (toAssoc a))) ops
90+ ++ [[P.Infix (P.try (parseOp >>= \ident -> return (\t1 t2 -> App (App (Var ident) t1) t2))) P.AssocLeft]]
91+
92+toAssoc :: Associativity -> P.Assoc
93+toAssoc Infixl = P.AssocLeft
94+toAssoc Infixr = P.AssocRight
95+
96+parseValue :: P.Parsec Chain () Value
97+parseValue = P.token show (const (P.initialPos "")) (either Just (const Nothing)) P.<?> "expression"
98+
99+parseOp :: P.Parsec Chain () (Qualified Ident)
100+parseOp = P.token show (const (P.initialPos "")) (either (const Nothing) Just) P.<?> "operator"
101+
102+matchOp :: ModuleName -> Qualified Ident -> P.Parsec Chain () ()
103+matchOp moduleName op = do
104+ ident <- parseOp
105+ guard (qualify moduleName ident == qualify moduleName op)
106+
107+collectFixities :: M.Map (Qualified Ident) Fixity -> ModuleName -> [Declaration] -> Either String (M.Map (Qualified Ident) Fixity)
108+collectFixities m _ [] = return m
109+collectFixities m moduleName (FixityDeclaration fixity name : rest) = do
110+ let qual = Qualified (Just moduleName) (Op name)
111+ when (qual `M.member` m) (Left $ "redefined fixity for " ++ show name)
112+ collectFixities (M.insert qual fixity m) moduleName rest
113+collectFixities m moduleName (ImportDeclaration importedModule _ : rest) = do
114+ let fs = [ (i, fixity) | (Qualified mn i, fixity) <- M.toList m, mn == Just importedModule ]
115+ let m' = M.fromList (map (first (Qualified (Just moduleName))) fs)
116+ collectFixities (m' `M.union` m) moduleName rest
117+collectFixities m moduleName (_:ds) = collectFixities m moduleName ds
118+
src/Language/PureScript/Sugar/TypeClasses.hsnew file+184
@@ -0,0 +1,184 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Sugar.TypeClasses
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+-- This module implements the desugaring pass which creates type synonyms for type class dictionaries
13+-- and dictionary expressions for type class instances.
14+--
15+-----------------------------------------------------------------------------
16+
17+module Language.PureScript.Sugar.TypeClasses (
18+ desugarTypeClasses,
19+ mkDictionaryValueName,
20+ mkDictionaryEntryName
21+) where
22+
23+import Language.PureScript.Declarations
24+import Language.PureScript.Names
25+import Language.PureScript.Types
26+import Language.PureScript.Values
27+import Language.PureScript.CodeGen.JS.AST
28+import Language.PureScript.Sugar.CaseDeclarations
29+
30+import qualified Data.Map as M
31+
32+import Control.Applicative
33+import Control.Monad.State
34+import Control.Arrow (second)
35+
36+import Data.List (intercalate)
37+import Language.PureScript.CodeGen.Common (identToJs, moduleNameToJs)
38+
39+type MemberMap = M.Map (ModuleName, ProperName) ([String], [(String, Type)])
40+
41+type Desugar = StateT MemberMap (Either String)
42+
43+-- |
44+-- Add type synonym declarations for type class dictionary types, and value declarations for type class
45+-- instance dictionary expressions.
46+--
47+desugarTypeClasses :: [Module] -> Either String [Module]
48+desugarTypeClasses = flip evalStateT M.empty . mapM desugarModule
49+
50+desugarModule :: Module -> Desugar Module
51+desugarModule (Module name decls) = Module name <$> concat <$> mapM (desugarDecl name) decls
52+
53+-- |
54+-- Desugar type class and type class instance declarations
55+--
56+-- Type classes become type synonyms for their dictionaries, and type instances become dictionary declarations.
57+-- Additional values are generated to access individual members of a dictionary, with the appropriate type.
58+--
59+-- E.g. the following
60+--
61+-- module Test where
62+--
63+-- class Foo a where
64+-- foo :: a -> a
65+--
66+-- instance Foo String where
67+-- foo s = s ++ s
68+--
69+-- instance (Foo a) => Foo [a] where
70+-- foo = map foo
71+--
72+-- becomes
73+--
74+-- type Foo a = { foo :: a -> a }
75+--
76+-- foreign import foo "function foo(dict) {\
77+-- \ return dict.foo;\
78+-- \}" :: forall a. (Foo a) => a -> a
79+--
80+-- __Test_Foo_string_foo = (\s -> s ++ s) :: String -> String
81+--
82+-- __Test_Foo_string :: {} -> Foo String
83+-- __Test_Foo_string = { foo: __Test_Foo_string_foo :: String -> String (unchecked) }
84+--
85+-- __Test_Foo_array_foo :: forall a. (Foo a) => [a] -> [a]
86+-- __Test_Foo_array_foo _1 = map (foo _1)
87+--
88+-- __Test_Foo_array :: forall a. Foo a -> Foo [a]
89+-- __Test_Foo_array _1 = { foo: __Test_Foo_array_foo _1 :: [a] -> [a] (unchecked) }
90+--
91+desugarDecl :: ModuleName -> Declaration -> Desugar [Declaration]
92+desugarDecl mn d@(TypeClassDeclaration name args members) = do
93+ let tys = map memberToNameAndType members
94+ modify (M.insert (mn, name) (args, tys))
95+ return $ d : typeClassDictionaryDeclaration name args members : map (typeClassMemberToDictionaryAccessor mn name args) members
96+desugarDecl mn d@(TypeInstanceDeclaration deps name ty members) = do
97+ desugared <- lift $ desugarCases members
98+ entries <- mapM (typeInstanceDictionaryEntryDeclaration mn deps name ty) desugared
99+ dictDecl <- typeInstanceDictionaryDeclaration mn deps name ty desugared
100+ return $ d : entries ++ [dictDecl]
101+desugarDecl _ other = return [other]
102+
103+memberToNameAndType :: Declaration -> (String, Type)
104+memberToNameAndType (TypeDeclaration ident ty) = (identToJs ident, ty)
105+memberToNameAndType _ = error "Invalid declaration in type class definition"
106+
107+typeClassDictionaryDeclaration :: ProperName -> [String] -> [Declaration] -> Declaration
108+typeClassDictionaryDeclaration name args members =
109+ TypeSynonymDeclaration name args (Object $ rowFromList (map memberToNameAndType members, REmpty))
110+
111+typeClassMemberToDictionaryAccessor :: ModuleName -> ProperName -> [String] -> Declaration -> Declaration
112+typeClassMemberToDictionaryAccessor mn name args (TypeDeclaration ident ty) =
113+ ExternDeclaration TypeClassAccessorImport ident
114+ (Just (JSFunction (Just $ identToJs ident) ["dict"] (JSBlock [JSReturn (JSAccessor (identToJs ident) (JSVar "dict"))])))
115+ (quantify (ConstrainedType [(Qualified (Just mn) name, map TypeVar args)] ty))
116+typeClassMemberToDictionaryAccessor _ _ _ _ = error "Invalid declaration in type class definition"
117+
118+typeInstanceDictionaryDeclaration :: ModuleName -> [(Qualified ProperName, [Type])] -> Qualified ProperName -> [Type] -> [Declaration] -> Desugar Declaration
119+typeInstanceDictionaryDeclaration mn deps name tys decls = do
120+ m <- get
121+ (args, instanceTys) <- lift $ maybe (Left $ "Type class " ++ show name ++ " is undefined. Type class names must be qualified.") Right
122+ $ M.lookup (qualify mn name) m
123+ let memberTypes = map (second (replaceAllTypeVars (zip args tys))) instanceTys
124+ entryName <- lift $ mkDictionaryValueName mn name tys
125+ memberNames <- mapM (memberToNameAndValue memberTypes) decls
126+ return $ ValueDeclaration entryName [] Nothing
127+ (TypedValue True
128+ (foldr (Abs . (\n -> Left . Ident $ '_' : show n)) (ObjectLiteral memberNames) [1..max 1 (length deps)])
129+ (quantify (if null deps then
130+ function unit (foldl TypeApp (TypeConstructor name) tys)
131+ else
132+ foldr (function . (\(pn, tys') -> foldl TypeApp (TypeConstructor pn) tys')) (foldl TypeApp (TypeConstructor name) tys) deps))
133+ )
134+ where
135+ memberToNameAndValue :: [(String, Type)] -> Declaration -> Desugar (String, Value)
136+ memberToNameAndValue tys' (ValueDeclaration ident _ _ _) = do
137+ memberType <- lift . maybe (Left "Type class member type not found") Right $ lookup (identToJs ident) tys'
138+ memberName <- mkDictionaryEntryName mn name tys ident
139+ return (identToJs ident, TypedValue False
140+ (foldl App (Var (Qualified Nothing memberName)) (map (\n -> Var (Qualified Nothing (Ident ('_' : show n)))) [1..length deps]))
141+ (quantify memberType))
142+ memberToNameAndValue _ _ = error "Invalid declaration in type instance definition"
143+
144+typeInstanceDictionaryEntryDeclaration :: ModuleName -> [(Qualified ProperName, [Type])] -> Qualified ProperName -> [Type] -> Declaration -> Desugar Declaration
145+typeInstanceDictionaryEntryDeclaration mn deps name tys (ValueDeclaration ident [] _ val) = do
146+ m <- get
147+ valTy <- lift $ do (args, members) <- lookupTypeClass m
148+ ty' <- lookupIdent members
149+ return $ replaceAllTypeVars (zip args tys) ty'
150+ entryName <- mkDictionaryEntryName mn name tys ident
151+ return $ ValueDeclaration entryName [] Nothing
152+ (TypedValue True val (quantify (if null deps then valTy else ConstrainedType deps valTy)))
153+ where
154+ lookupTypeClass m = maybe (Left $ "Type class " ++ show name ++ " is undefined. Type class names must be qualified.") Right $ M.lookup (qualify mn name) m
155+ lookupIdent members = maybe (Left $ "Type class " ++ show name ++ " does not have method " ++ show ident) Right $ lookup (identToJs ident) members
156+typeInstanceDictionaryEntryDeclaration _ _ _ _ _ = error "Invalid declaration in type instance definition"
157+
158+
159+qualifiedToString :: ModuleName -> Qualified ProperName -> String
160+qualifiedToString mn (Qualified _ pn) = moduleNameToJs mn ++ "_" ++ runProperName pn
161+
162+
163+-- |
164+-- Generate a name for a type class dictionary, based on the module name, class name and type name
165+--
166+mkDictionaryValueName :: ModuleName -> Qualified ProperName -> [Type] -> Either String Ident
167+mkDictionaryValueName mn cl tys = do
168+ tyStr <- mapM (typeToString mn) tys
169+ return $ Ident $ "__" ++ qualifiedToString mn cl ++ "_" ++ intercalate "_" tyStr
170+
171+typeToString :: ModuleName -> Type -> Either String String
172+typeToString _ (TypeVar _) = return "var"
173+typeToString mn (TypeConstructor ty') = return $ qualifiedToString mn ty'
174+typeToString mn (TypeApp ty' (TypeVar _)) = typeToString mn ty'
175+typeToString _ _ = Left "Type class instance must be of the form T a1 ... an"
176+
177+-- |
178+-- Generate a name for a type class dictionary member, based on the module name, class name, type name and
179+-- member name
180+--
181+mkDictionaryEntryName :: ModuleName -> Qualified ProperName -> [Type] -> Ident -> Desugar Ident
182+mkDictionaryEntryName mn name tys ident = do
183+ Ident dictName <- lift $ mkDictionaryValueName mn name tys
184+ return $ Escaped $ dictName ++ "_" ++ identToJs ident
src/Language/PureScript/Sugar/TypeDeclarations.hsnew file+43
@@ -0,0 +1,43 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Sugar.TypeDeclarations
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+-- This module implements the desugaring pass which replaces top-level type declarations with
13+-- type annotations on the corresponding expression.
14+--
15+-----------------------------------------------------------------------------
16+
17+module Language.PureScript.Sugar.TypeDeclarations (
18+ desugarTypeDeclarations,
19+ desugarTypeDeclarationsModule
20+) where
21+
22+import Control.Applicative
23+import Control.Monad.Error.Class
24+import Control.Monad (forM)
25+
26+import Language.PureScript.Declarations
27+import Language.PureScript.Values
28+
29+-- |
30+-- Replace all top level type declarations in a module with type annotations
31+--
32+desugarTypeDeclarationsModule :: [Module] -> Either String [Module]
33+desugarTypeDeclarationsModule ms = forM ms $ \(Module name ds) -> Module name <$> desugarTypeDeclarations ds
34+
35+-- |
36+-- Replace all top level type declarations with type annotations
37+--
38+desugarTypeDeclarations :: [Declaration] -> Either String [Declaration]
39+desugarTypeDeclarations (TypeDeclaration name ty : ValueDeclaration name' [] Nothing val : rest) | name == name' =
40+ desugarTypeDeclarations (ValueDeclaration name [] Nothing (TypedValue True val ty) : rest)
41+desugarTypeDeclarations (TypeDeclaration name _ : _) = throwError $ "Orphan type declaration for " ++ show name
42+desugarTypeDeclarations (d:ds) = (:) d <$> desugarTypeDeclarations ds
43+desugarTypeDeclarations [] = return []
src/Language/PureScript/TypeChecker.hsnew file+222
@@ -0,0 +1,222 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.TypeChecker
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+-- The top-level type checker, which checks all declarations in a module.
13+--
14+-----------------------------------------------------------------------------
15+
16+{-# LANGUAGE FlexibleInstances #-}
17+
18+module Language.PureScript.TypeChecker (
19+ module T,
20+ typeCheckAll
21+) where
22+
23+import Language.PureScript.TypeChecker.Monad as T
24+import Language.PureScript.TypeChecker.Kinds as T
25+import Language.PureScript.TypeChecker.Types as T
26+import Language.PureScript.TypeChecker.Synonyms as T
27+
28+import Data.Maybe
29+import qualified Data.Map as M
30+import Control.Monad.State
31+import Control.Monad.Error
32+import Data.Either (rights, lefts)
33+
34+import Language.PureScript.Types
35+import Language.PureScript.Names
36+import Language.PureScript.Values
37+import Language.PureScript.Kinds
38+import Language.PureScript.Declarations
39+import Language.PureScript.Sugar.TypeClasses
40+
41+addDataType :: ModuleName -> ProperName -> [String] -> [(ProperName, [Type])] -> Kind -> Check ()
42+addDataType moduleName name args dctors ctorKind = do
43+ env <- getEnv
44+ putEnv $ env { types = M.insert (Qualified (Just moduleName) name) ctorKind (types env) }
45+ forM_ dctors $ \(dctor, tys) ->
46+ rethrow (("Error in data constructor " ++ show dctor ++ ":\n") ++) $
47+ addDataConstructor moduleName name args dctor tys
48+
49+addDataConstructor :: ModuleName -> ProperName -> [String] -> ProperName -> [Type] -> Check ()
50+addDataConstructor moduleName name args dctor tys = do
51+ env <- getEnv
52+ let retTy = foldl TypeApp (TypeConstructor (Qualified (Just moduleName) name)) (map TypeVar args)
53+ let dctorTy = foldr function retTy tys
54+ let polyType = mkForAll args dctorTy
55+ putEnv $ env { dataConstructors = M.insert (Qualified (Just moduleName) dctor) polyType (dataConstructors env) }
56+
57+addTypeSynonym :: ModuleName -> ProperName -> [String] -> Type -> Kind -> Check ()
58+addTypeSynonym moduleName name args ty kind = do
59+ env <- getEnv
60+ putEnv $ env { types = M.insert (Qualified (Just moduleName) name) kind (types env)
61+ , typeSynonyms = M.insert (Qualified (Just moduleName) name) (args, ty) (typeSynonyms env) }
62+
63+valueIsNotDefined :: ModuleName -> Ident -> Check ()
64+valueIsNotDefined moduleName name = do
65+ env <- getEnv
66+ case M.lookup (moduleName, name) (names env) of
67+ Just _ -> throwError $ show name ++ " is already defined"
68+ Nothing -> return ()
69+
70+addValue :: ModuleName -> Ident -> Type -> Check ()
71+addValue moduleName name ty = do
72+ env <- getEnv
73+ putEnv (env { names = M.insert (moduleName, name) (ty, Value) (names env) })
74+
75+addTypeClassDictionaries :: [TypeClassDictionaryInScope] -> Check ()
76+addTypeClassDictionaries entries =
77+ modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = entries ++ (typeClassDictionaries . checkEnv $ st) } }
78+
79+checkTypeClassInstance :: ModuleName -> Type -> Check ()
80+checkTypeClassInstance _ (TypeVar _) = return ()
81+checkTypeClassInstance m (TypeConstructor ctor) = do
82+ env <- getEnv
83+ when (ctor `M.member` typeSynonyms env) $ throwError "Type synonym instances are disallowed"
84+ return ()
85+checkTypeClassInstance m (TypeApp ty (TypeVar _)) = checkTypeClassInstance m ty
86+checkTypeClassInstance _ _ = throwError "Type class instance must be of the form T a1 ... an"
87+
88+-- |
89+-- Type check all declarations in a module
90+--
91+-- At this point, many declarations will have been desugared, but it is still necessary to
92+--
93+-- * Kind-check all types and add them to the @Environment@
94+--
95+-- * Type-check all values and add them to the @Environment@
96+--
97+-- * Bring type class instances into scope
98+--
99+-- * Process module imports
100+--
101+typeCheckAll :: Maybe ModuleName -> ModuleName -> [Declaration] -> Check [Declaration]
102+typeCheckAll _ _ [] = return []
103+typeCheckAll mainModuleName moduleName (d@(DataDeclaration name args dctors) : rest) = do
104+ rethrow (("Error in type constructor " ++ show name ++ ":\n") ++) $ do
105+ ctorKind <- kindsOf moduleName name args (concatMap snd dctors)
106+ addDataType moduleName name args dctors ctorKind
107+ ds <- typeCheckAll mainModuleName moduleName rest
108+ return $ d : ds
109+typeCheckAll mainModuleName moduleName (d@(DataBindingGroupDeclaration tys) : rest) = do
110+ rethrow ("Error in data binding group:\n" ++) $ do
111+ let syns = mapMaybe toTypeSynonym tys
112+ let dataDecls = mapMaybe toDataDecl tys
113+ (syn_ks, data_ks) <- kindsOfAll moduleName syns (map (\(name, args, dctors) -> (name, args, concatMap snd dctors)) dataDecls)
114+ forM_ (zip dataDecls data_ks) $ \((name, args, dctors), ctorKind) ->
115+ addDataType moduleName name args dctors ctorKind
116+ forM_ (zip syns syn_ks) $ \((name, args, ty), kind) ->
117+ addTypeSynonym moduleName name args ty kind
118+ ds <- typeCheckAll mainModuleName moduleName rest
119+ return $ d : ds
120+ where
121+ toTypeSynonym (TypeSynonymDeclaration nm args ty) = Just (nm, args, ty)
122+ toTypeSynonym _ = Nothing
123+ toDataDecl (DataDeclaration nm args dctors) = Just (nm, args, dctors)
124+ toDataDecl _ = Nothing
125+typeCheckAll mainModuleName moduleName (d@(TypeSynonymDeclaration name args ty) : rest) = do
126+ rethrow (("Error in type synonym " ++ show name ++ ":\n") ++) $ do
127+ kind <- kindsOf moduleName name args [ty]
128+ addTypeSynonym moduleName name args ty kind
129+ ds <- typeCheckAll mainModuleName moduleName rest
130+ return $ d : ds
131+typeCheckAll _ _ (TypeDeclaration _ _ : _) = error "Type declarations should have been removed"
132+typeCheckAll mainModuleName moduleName (ValueDeclaration name [] Nothing val : rest) = do
133+ d <- rethrow (("Error in declaration " ++ show name ++ ":\n") ++) $ do
134+ valueIsNotDefined moduleName name
135+ [(_, (val', ty))] <- typesOf mainModuleName moduleName [(name, val)]
136+ addValue moduleName name ty
137+ return $ ValueDeclaration name [] Nothing val'
138+ ds <- typeCheckAll mainModuleName moduleName rest
139+ return $ d : ds
140+typeCheckAll _ _ (ValueDeclaration{} : _) = error "Binders were not desugared"
141+typeCheckAll mainModuleName moduleName (BindingGroupDeclaration vals : rest) = do
142+ d <- rethrow (("Error in binding group " ++ show (map fst vals) ++ ":\n") ++) $ do
143+ forM_ (map fst vals) $ \name ->
144+ valueIsNotDefined moduleName name
145+ tys <- typesOf mainModuleName moduleName vals
146+ vals' <- forM (zip (map fst vals) (map snd tys)) $ \(name, (val, ty)) -> do
147+ addValue moduleName name ty
148+ return (name, val)
149+ return $ BindingGroupDeclaration vals'
150+ ds <- typeCheckAll mainModuleName moduleName rest
151+ return $ d : ds
152+typeCheckAll mainModuleName moduleName (d@(ExternDataDeclaration name kind) : rest) = do
153+ env <- getEnv
154+ putEnv $ env { types = M.insert (Qualified (Just moduleName) name) kind (types env) }
155+ ds <- typeCheckAll mainModuleName moduleName rest
156+ return $ d : ds
157+typeCheckAll mainModuleName moduleName (d@(ExternDeclaration importTy name _ ty) : rest) = do
158+ rethrow (("Error in foreign import declaration " ++ show name ++ ":\n") ++) $ do
159+ env <- getEnv
160+ kind <- kindOf moduleName ty
161+ guardWith "Expected kind *" $ kind == Star
162+ case M.lookup (moduleName, name) (names env) of
163+ Just _ -> throwError $ show name ++ " is already defined"
164+ Nothing -> putEnv (env { names = M.insert (moduleName, name) (ty, Extern importTy) (names env) })
165+ ds <- typeCheckAll mainModuleName moduleName rest
166+ return $ d : ds
167+typeCheckAll mainModuleName moduleName (d@(FixityDeclaration _ name) : rest) = do
168+ ds <- typeCheckAll mainModuleName moduleName rest
169+ env <- getEnv
170+ guardWith ("Fixity declaration with no binding: " ++ name) $ M.member (moduleName, Op name) $ names env
171+ return $ d : ds
172+typeCheckAll mainModuleName currentModule (d@(ImportDeclaration moduleName idents) : rest) = do
173+ env <- getEnv
174+ rethrow errorMessage $ do
175+ guardWith ("Module " ++ show moduleName ++ " does not exist") $ moduleExists env
176+ case idents of
177+ Nothing -> do
178+ shadowIdents (map snd $ filterModule (names env)) env
179+ Just idents' -> do
180+ shadowIdents (nameImports idents') env
181+ shadowTypeClassInstances env
182+ ds <- typeCheckAll mainModuleName currentModule rest
183+ return $ d : ds
184+ where
185+ errorMessage = (("Error in import declaration " ++ show moduleName ++ ":\n") ++)
186+ filterModule = filter ((== moduleName) . fst) . M.keys
187+ filterModuleQ = filter (\(Qualified (Just mn) _) -> mn == moduleName) . M.keys
188+ moduleExists env = not (null (filterModule (names env))) || not (null (filterModuleQ (types env)))
189+ shadowIdents idents' env =
190+ forM_ idents' $ \ident ->
191+ case (moduleName, ident) `M.lookup` names env of
192+ Just (_, Alias _ _) -> return ()
193+ Just (pt, _) -> do
194+ guardWith (show currentModule ++ "." ++ show ident ++ " is already defined") $ (currentModule, ident) `M.notMember` names env
195+ modifyEnv (\e -> e { names = M.insert (currentModule, ident) (pt, Alias moduleName ident) (names e) })
196+ Nothing -> throwError (show moduleName ++ "." ++ show ident ++ " is undefined")
197+ shadowTypeClassInstances env = do
198+ let instances = filter (\tcd ->
199+ let Qualified (Just mn) _ = tcdName tcd in
200+ moduleName == mn && tcdType tcd == TCDRegular
201+ ) (typeClassDictionaries env)
202+ forM_ instances $ \tcd -> do
203+ let (Qualified _ ident) = tcdName tcd
204+ addTypeClassDictionaries [tcd { tcdName = Qualified (Just currentModule) ident, tcdType = TCDAlias (tcdName tcd) }]
205+ constructs (TypeConstructor (Qualified (Just mn) pn')) pn
206+ = mn == moduleName && pn' == pn
207+ constructs (ForAll _ ty _) pn = ty `constructs` pn
208+ constructs (TypeApp (TypeApp t _) ty) pn | t == tyFunction = ty `constructs` pn
209+ constructs (TypeApp ty _) pn = ty `constructs` pn
210+ constructs fn _ = error $ "Invalid arguments to constructs: " ++ show fn
211+typeCheckAll mainModuleName moduleName (d@TypeClassDeclaration{} : rest) = do
212+ env <- getEnv
213+ ds <- typeCheckAll mainModuleName moduleName rest
214+ return $ d : ds
215+typeCheckAll mainModuleName moduleName (d@(TypeInstanceDeclaration deps className tys _) : rest) = do
216+ env <- getEnv
217+ dictName <- Check . lift $ mkDictionaryValueName moduleName className tys
218+ mapM_ (checkTypeClassInstance moduleName) tys
219+ forM_ deps $ mapM_ (checkTypeClassInstance moduleName) . snd
220+ addTypeClassDictionaries [TypeClassDictionaryInScope (Qualified (Just moduleName) dictName) className tys (Just deps) TCDRegular]
221+ ds <- typeCheckAll mainModuleName moduleName rest
222+ return $ d : ds
src/Language/PureScript/TypeChecker/Kinds.hsnew file+166
@@ -0,0 +1,166 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.TypeChecker.Kinds
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+-- This module implements the kind checker
13+--
14+-----------------------------------------------------------------------------
15+
16+{-# OPTIONS_GHC -fno-warn-orphans #-}
17+{-# LANGUAGE MultiParamTypeClasses #-}
18+
19+module Language.PureScript.TypeChecker.Kinds (
20+ kindOf,
21+ kindsOf,
22+ kindsOfAll
23+) where
24+
25+import Language.PureScript.Types
26+import Language.PureScript.Kinds
27+import Language.PureScript.Names
28+import Language.PureScript.TypeChecker.Monad
29+import Language.PureScript.Pretty
30+
31+import Control.Monad.State
32+import Control.Monad.Error
33+import Control.Monad.Unify
34+
35+import Control.Applicative
36+
37+import qualified Data.Map as M
38+
39+instance Partial Kind where
40+ unknown = KUnknown
41+ isUnknown (KUnknown u) = Just u
42+ isUnknown _ = Nothing
43+
44+instance Unifiable Check Kind where
45+ KUnknown u1 =?= KUnknown u2 | u1 == u2 = return ()
46+ KUnknown u =?= k = u =:= k
47+ k =?= KUnknown u = u =:= k
48+ Star =?= Star = return ()
49+ Bang =?= Bang = return ()
50+ Row k1 =?= Row k2 = k1 =?= k2
51+ FunKind k1 k2 =?= FunKind k3 k4 = do
52+ k1 =?= k3
53+ k2 =?= k4
54+ k1 =?= k2 = UnifyT . lift . throwError $ "Cannot unify " ++ prettyPrintKind k1 ++ " with " ++ prettyPrintKind k2 ++ "."
55+
56+-- |
57+-- Infer the kind of a single type
58+--
59+kindOf :: ModuleName -> Type -> Check Kind
60+kindOf _ ty =
61+ rethrow (("Error checking kind of " ++ prettyPrintType ty ++ ":\n") ++) $
62+ fmap tidyUp . liftUnify $ starIfUnknown <$> infer ty
63+ where
64+ tidyUp (k, sub) = sub $? k
65+
66+-- |
67+-- Infer the kind of a type constructor with a collection of arguments and a collection of associated data constructors
68+--
69+kindsOf :: ModuleName -> ProperName -> [String] -> [Type] -> Check Kind
70+kindsOf moduleName name args ts = fmap tidyUp . liftUnify $ do
71+ tyCon <- fresh
72+ kargs <- replicateM (length args) fresh
73+ let dict = (name, tyCon) : zip (map ProperName args) kargs
74+ bindLocalTypeVariables moduleName dict $
75+ solveTypes ts kargs tyCon
76+ where
77+ tidyUp (k, sub) = sub $? k
78+
79+-- |
80+-- Simultaneously infer the kinds of several mutually recursive type constructors
81+--
82+kindsOfAll :: ModuleName -> [(ProperName, [String], Type)] -> [(ProperName, [String], [Type])] -> Check ([Kind], [Kind])
83+kindsOfAll moduleName syns tys = fmap tidyUp . liftUnify $ do
84+ synVars <- replicateM (length syns) fresh
85+ let dict = zipWith (\(name, _, _) var -> (name, var)) syns synVars
86+ bindLocalTypeVariables moduleName dict $ do
87+ tyCons <- replicateM (length tys) fresh
88+ let dict' = zipWith (\(name, _, _) tyCon -> (name, tyCon)) tys tyCons
89+ bindLocalTypeVariables moduleName dict' $ do
90+ data_ks <- zipWithM (\tyCon (_, args, ts) -> do
91+ kargs <- replicateM (length args) fresh
92+ let argDict = zip (map ProperName args) kargs
93+ bindLocalTypeVariables moduleName argDict $
94+ solveTypes ts kargs tyCon) tyCons tys
95+ syn_ks <- zipWithM (\synVar (_, args, ty) -> do
96+ kargs <- replicateM (length args) fresh
97+ let argDict = zip (map ProperName args) kargs
98+ bindLocalTypeVariables moduleName argDict $
99+ solveTypes [ty] kargs synVar) synVars syns
100+ return (syn_ks, data_ks)
101+ where
102+ tidyUp ((ks1, ks2), sub) = (map (starIfUnknown . (sub $?)) ks1, map (starIfUnknown . (sub $?)) ks2)
103+
104+-- |
105+-- Solve the set of kind constraints associated with the data constructors for a type constructor
106+--
107+solveTypes :: [Type] -> [Kind] -> Kind -> UnifyT Kind Check Kind
108+solveTypes ts kargs tyCon = do
109+ ks <- mapM infer ts
110+ tyCon =?= foldr FunKind Star kargs
111+ forM_ ks $ \k -> k =?= Star
112+ return tyCon
113+
114+-- |
115+-- Default all unknown kinds to the Star kind of types
116+--
117+starIfUnknown :: Kind -> Kind
118+starIfUnknown (KUnknown _) = Star
119+starIfUnknown (FunKind k1 k2) = FunKind (starIfUnknown k1) (starIfUnknown k2)
120+starIfUnknown k = k
121+
122+-- |
123+-- Infer a kind for a type
124+--
125+infer :: Type -> UnifyT Kind Check Kind
126+infer (Object row) = do
127+ k <- infer row
128+ k =?= Row Star
129+ return Star
130+infer (TypeVar v) = do
131+ Just moduleName <- checkCurrentModule <$> get
132+ UnifyT . lift $ lookupTypeVariable moduleName (Qualified Nothing (ProperName v))
133+infer (TypeConstructor v) = do
134+ env <- liftCheck getEnv
135+ Just moduleName <- checkCurrentModule <$> get
136+ case M.lookup v (types env) of
137+ Nothing -> UnifyT . lift . throwError $ "Unknown type constructor '" ++ show v ++ "'" ++ show (M.keys (types env))
138+ Just kind -> return kind
139+infer (TypeApp t1 t2) = do
140+ k0 <- fresh
141+ k1 <- infer t1
142+ k2 <- infer t2
143+ k1 =?= FunKind k2 k0
144+ return k0
145+infer (ForAll ident ty _) = do
146+ k1 <- fresh
147+ Just moduleName <- checkCurrentModule <$> get
148+ k2 <- bindLocalTypeVariables moduleName [(ProperName ident, k1)] $ infer ty
149+ k2 =?= Star
150+ return Star
151+infer REmpty = do
152+ k <- fresh
153+ return $ Row k
154+infer (RCons _ ty row) = do
155+ k1 <- infer ty
156+ k2 <- infer row
157+ k2 =?= Row k1
158+ return $ Row k1
159+infer (ConstrainedType deps ty) = do
160+ forM_ deps $ \(className, tys) -> do
161+ _ <- infer $ foldl TypeApp (TypeConstructor className) tys
162+ return ()
163+ k <- infer ty
164+ k =?= Star
165+ return Star
166+infer _ = error "Invalid argument to infer"
src/Language/PureScript/TypeChecker/Monad.hsnew file+281
@@ -0,0 +1,281 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.TypeChecker.Monad
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+-- Monads for type checking and type inference and associated data types
13+--
14+-----------------------------------------------------------------------------
15+
16+{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleInstances, RankNTypes,
17+ MultiParamTypeClasses, FlexibleContexts #-}
18+
19+module Language.PureScript.TypeChecker.Monad where
20+
21+import Language.PureScript.Types
22+import Language.PureScript.Kinds
23+import Language.PureScript.Values
24+import Language.PureScript.Names
25+import Language.PureScript.Declarations
26+
27+import Data.Data
28+import Data.Maybe
29+import Data.Generics (mkT, everywhere)
30+
31+import Control.Applicative
32+import Control.Monad.State
33+import Control.Monad.Error
34+import Control.Monad.Unify
35+import Control.Arrow (first)
36+
37+import qualified Data.Map as M
38+
39+-- |
40+-- The type of a name in the @Environment@
41+--
42+data NameKind
43+ -- |
44+ -- A value introduced as a binding in a module
45+ --
46+ = Value
47+ -- |
48+ -- A foreign import
49+ --
50+ | Extern ForeignImportType
51+ -- |
52+ -- An alias for a value in another module, introduced using an import declaration
53+ --
54+ | Alias ModuleName Ident
55+ -- |
56+ -- A local name introduced using a lambda abstraction, variable introduction or binder
57+ --
58+ | LocalVariable
59+ -- |
60+ -- A data constructor
61+ --
62+ | DataConstructor deriving Show
63+
64+-- |
65+-- The @Environment@ defines all values and types which are currently in scope:
66+--
67+data Environment = Environment {
68+ -- |
69+ -- Value names currently in scope
70+ --
71+ names :: M.Map (ModuleName, Ident) (Type, NameKind)
72+ -- |
73+ -- Type names currently in scope
74+ --
75+ , types :: M.Map (Qualified ProperName) Kind
76+ -- |
77+ -- Data constructors currently in scope, along with their associated data type constructors
78+ --
79+ , dataConstructors :: M.Map (Qualified ProperName) Type
80+ -- |
81+ -- Type synonyms currently in scope
82+ --
83+ , typeSynonyms :: M.Map (Qualified ProperName) ([String], Type)
84+ -- |
85+ -- Available type class dictionaries
86+ --
87+ , typeClassDictionaries :: [TypeClassDictionaryInScope]
88+ } deriving (Show)
89+
90+-- |
91+-- The basic types existing in the external javascript environment
92+--
93+jsTypes ::M.Map (Qualified ProperName) Kind
94+jsTypes = M.fromList [ (Qualified (Just $ ModuleName [ProperName "Prim"]) (ProperName "Function"), FunKind Star (FunKind Star Star))
95+ , (Qualified (Just $ ModuleName [ProperName "Prim"]) (ProperName "Array"), FunKind Star Star)
96+ , (Qualified (Just $ ModuleName [ProperName "Prim"]) (ProperName "String"), Star)
97+ , (Qualified (Just $ ModuleName [ProperName "Prim"]) (ProperName "Number"), Star)
98+ , (Qualified (Just $ ModuleName [ProperName "Prim"]) (ProperName "Boolean"), Star) ]
99+
100+-- |
101+-- The initial environment with no values and only the default javascript types defined
102+--
103+initEnvironment :: Environment
104+initEnvironment = Environment M.empty jsTypes M.empty M.empty []
105+
106+-- |
107+-- Temporarily bind a collection of names to values
108+--
109+bindNames :: (MonadState CheckState m) => M.Map (ModuleName, Ident) (Type, NameKind) -> m a -> m a
110+bindNames newNames action = do
111+ orig <- get
112+ modify $ \st -> st { checkEnv = (checkEnv st) { names = newNames `M.union` (names . checkEnv $ st) } }
113+ a <- action
114+ modify $ \st -> st { checkEnv = (checkEnv st) { names = names . checkEnv $ orig } }
115+ return a
116+
117+-- |
118+-- Temporarily bind a collection of names to types
119+--
120+bindTypes :: (MonadState CheckState m) => M.Map (Qualified ProperName) Kind -> m a -> m a
121+bindTypes newNames action = do
122+ orig <- get
123+ modify $ \st -> st { checkEnv = (checkEnv st) { types = newNames `M.union` (types . checkEnv $ st) } }
124+ a <- action
125+ modify $ \st -> st { checkEnv = (checkEnv st) { types = types . checkEnv $ orig } }
126+ return a
127+
128+-- |
129+-- Temporarily make a collection of type class dictionaries available
130+--
131+withTypeClassDictionaries :: (MonadState CheckState m) => [TypeClassDictionaryInScope] -> m a -> m a
132+withTypeClassDictionaries entries action = do
133+ orig <- get
134+ modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = entries ++ (typeClassDictionaries . checkEnv $ st) } }
135+ a <- action
136+ modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = typeClassDictionaries . checkEnv $ orig } }
137+ return a
138+
139+-- |
140+-- Get the currently available list of type class dictionaries
141+--
142+getTypeClassDictionaries :: (Functor m, MonadState CheckState m) => m [TypeClassDictionaryInScope]
143+getTypeClassDictionaries = typeClassDictionaries . checkEnv <$> get
144+
145+-- |
146+-- Temporarily bind a collection of names to local variables
147+--
148+bindLocalVariables :: (Functor m, MonadState CheckState m) => ModuleName -> [(Ident, Type)] -> m a -> m a
149+bindLocalVariables moduleName bindings =
150+ bindNames (M.fromList $ flip map bindings $ \(name, ty) -> ((moduleName, name), (ty, LocalVariable)))
151+
152+-- |
153+-- Temporarily bind a collection of names to local type variables
154+--
155+bindLocalTypeVariables :: (Functor m, MonadState CheckState m) => ModuleName -> [(ProperName, Kind)] -> m a -> m a
156+bindLocalTypeVariables moduleName bindings =
157+ bindTypes (M.fromList $ flip map bindings $ first $ Qualified (Just moduleName))
158+
159+-- |
160+-- Lookup the type of a value by name in the @Environment@
161+--
162+lookupVariable :: (Functor m, MonadState CheckState m, MonadError String m) => ModuleName -> Qualified Ident -> m Type
163+lookupVariable currentModule (Qualified moduleName var) = do
164+ env <- getEnv
165+ case M.lookup (fromMaybe currentModule moduleName, var) (names env) of
166+ Nothing -> throwError $ show var ++ " is undefined"
167+ Just (ty, _) -> return ty
168+
169+-- |
170+-- Lookup the kind of a type by name in the @Environment@
171+--
172+lookupTypeVariable :: (Functor m, MonadState CheckState m, MonadError String m) => ModuleName -> Qualified ProperName -> m Kind
173+lookupTypeVariable currentModule (Qualified moduleName name) = do
174+ env <- getEnv
175+ case M.lookup (Qualified (Just $ fromMaybe currentModule moduleName) name) (types env) of
176+ Nothing -> throwError $ "Type variable " ++ show name ++ " is undefined"
177+ Just k -> return k
178+
179+-- |
180+-- Canonicalize an identifier by resolving any aliases introduced by module imports
181+--
182+canonicalize :: ModuleName -> Environment -> Qualified Ident -> (ModuleName, Ident)
183+canonicalize _ _ (Qualified (Just mn) i) = (mn, i)
184+canonicalize mn env (Qualified Nothing i) = case (mn, i) `M.lookup` names env of
185+ Just (_, Alias mn' i') -> (mn', i')
186+ _ -> (mn, i)
187+
188+-- |
189+-- State required for type checking:
190+--
191+data CheckState = CheckState {
192+ -- |
193+ -- The current @Environment@
194+ --
195+ checkEnv :: Environment
196+ -- |
197+ -- The next fresh unification variable name
198+ --
199+ , checkNextVar :: Int
200+ -- |
201+ -- The next type class dictionary name
202+ --
203+ , checkNextDictName :: Int
204+ -- |
205+ -- The current module
206+ --
207+ , checkCurrentModule :: Maybe ModuleName
208+ }
209+
210+-- |
211+-- The type checking monad, which provides the state of the type checker, and error reporting capabilities
212+--
213+newtype Check a = Check { unCheck :: StateT CheckState (Either String) a }
214+ deriving (Functor, Monad, Applicative, MonadPlus, MonadState CheckState, MonadError String)
215+
216+-- |
217+-- Get the current @Environment@
218+--
219+getEnv :: (Functor m, MonadState CheckState m) => m Environment
220+getEnv = checkEnv <$> get
221+
222+-- |
223+-- Update the @Environment#
224+--
225+putEnv :: (MonadState CheckState m) => Environment -> m ()
226+putEnv env = modify (\s -> s { checkEnv = env })
227+
228+-- |
229+-- Modify the @Environment@
230+--
231+modifyEnv :: (MonadState CheckState m) => (Environment -> Environment) -> m ()
232+modifyEnv f = modify (\s -> s { checkEnv = f (checkEnv s) })
233+
234+-- |
235+-- Run a computation in the Check monad, failing with an error, or succeeding with a return value and the final @Environment@.
236+--
237+runCheck :: Check a -> Either String (a, Environment)
238+runCheck c = do
239+ (a, s) <- flip runStateT (CheckState initEnvironment 0 0 Nothing) $ unCheck c
240+ return (a, checkEnv s)
241+
242+-- |
243+-- Make an assertion, failing with an error message
244+--
245+guardWith :: (MonadError e m) => e -> Bool -> m ()
246+guardWith _ True = return ()
247+guardWith e False = throwError e
248+
249+-- |
250+-- Rethrow an error with a more detailed error message in the case of failure
251+--
252+rethrow :: (MonadError e m) => (e -> e) -> m a -> m a
253+rethrow f = flip catchError $ \e -> throwError (f e)
254+
255+-- |
256+-- Generate new type class dictionary name
257+--
258+freshDictionaryName :: Check Int
259+freshDictionaryName = do
260+ n <- checkNextDictName <$> get
261+ modify $ \s -> s { checkNextDictName = succ (checkNextDictName s) }
262+ return n
263+
264+-- |
265+-- Lift a computation in the @Check@ monad into the substitution monad.
266+--
267+liftCheck :: Check a -> UnifyT t Check a
268+liftCheck = UnifyT . lift . lift
269+
270+-- |
271+-- Run a computation in the substitution monad, generating a return value and the final substitution.
272+--
273+liftUnify :: (Partial t) => UnifyT t Check a -> Check (a, Substitution t)
274+liftUnify unify = do
275+ st <- get
276+ e <- runUnify (defaultUnifyState { unifyNextVar = checkNextVar st }) unify
277+ case e of
278+ Left err -> throwError err
279+ Right (a, ust) -> do
280+ modify $ \st' -> st' { checkNextVar = unifyNextVar ust }
281+ return (a, unifyCurrentSubstitution ust)
src/Language/PureScript/TypeChecker/Synonyms.hsnew file+60
@@ -0,0 +1,60 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.TypeChecker.Synonyms
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+-- Functions for replacing fully applied type synonyms with the @SaturatedTypeSynonym@ data constructor
13+--
14+-----------------------------------------------------------------------------
15+
16+module Language.PureScript.TypeChecker.Synonyms (
17+ saturateTypeSynonym,
18+ saturateAllTypeSynonyms
19+) where
20+
21+import Language.PureScript.Types
22+import Language.PureScript.Names
23+import Language.PureScript.TypeChecker.Monad (Environment(..))
24+
25+import Control.Applicative ((<$>))
26+import Data.Maybe (fromMaybe)
27+import Data.Data
28+import Data.Generics
29+import Data.Generics.Extras
30+import Control.Monad.Writer
31+import Control.Monad.Error
32+
33+-- |
34+-- Build a type substitution for a type synonym
35+--
36+buildTypeSubstitution :: Environment -> ModuleName -> Qualified ProperName -> Int -> Type -> Either String (Maybe Type)
37+buildTypeSubstitution env moduleName name n = go n []
38+ where
39+ go :: Int -> [Type] -> Type -> Either String (Maybe Type)
40+ go 0 args (TypeConstructor ctor) | name == ctor = return (Just $ SaturatedTypeSynonym ctor args)
41+ go m _ (TypeConstructor ctor) | m > 0 && name == ctor = throwError $ "Partially applied type synonym " ++ show name
42+ go m args (TypeApp f arg) = go (m - 1) (arg:args) f
43+ go _ _ _ = return Nothing
44+
45+-- |
46+-- Replace all instances of a specific type synonym with the @SaturatedTypeSynonym@ data constructor
47+--
48+saturateTypeSynonym :: (Data d) => Environment -> ModuleName -> Qualified ProperName -> Int -> d -> Either String d
49+saturateTypeSynonym env moduleName name n = everywhereM' (mkM replace)
50+ where
51+ replace t = fromMaybe t <$> buildTypeSubstitution env moduleName name n t
52+
53+-- |
54+-- Replace all type synonyms with the @SaturatedTypeSynonym@ data constructor
55+--
56+saturateAllTypeSynonyms :: (Data d) => Environment -> ModuleName -> [(Qualified ProperName, Int)] -> d -> Either String d
57+saturateAllTypeSynonyms env moduleName syns d = foldM (\result (name, n) -> saturateTypeSynonym env moduleName name n result) d syns
58+
59+
60+
src/Language/PureScript/TypeChecker/Types.hsnew file+953
@@ -0,0 +1,953 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.TypeChecker.Types
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+-- This module implements the type checker
13+--
14+-----------------------------------------------------------------------------
15+
16+{-# OPTIONS_GHC -fno-warn-orphans #-}
17+{-# LANGUAGE FlexibleContexts #-}
18+{-# LANGUAGE MultiParamTypeClasses #-}
19+
20+module Language.PureScript.TypeChecker.Types (
21+ typesOf
22+) where
23+
24+{-
25+ The following functions represent the corresponding type checking judgements:
26+
27+ infer
28+ Synthesize a type for a value
29+
30+ check
31+ Check a value has a given type
32+
33+ checkProperties
34+ Check an object with a given type contains specified properties
35+
36+ checkFunctionApplication
37+ Check a function of a given type returns a value of another type when applied to its arguments
38+
39+ subsumes
40+ Check a type subsumes another type
41+-}
42+
43+import Data.List
44+import Data.Maybe (maybeToList, isNothing, isJust, fromMaybe)
45+import qualified Data.Data as D
46+import Data.Generics
47+ (everythingWithContext, mkM, everywhereM, everything, mkT,
48+ something, everywhere, mkQ)
49+import Data.Generics.Extras
50+
51+import Language.PureScript.Values
52+import Language.PureScript.Types
53+import Language.PureScript.Kinds
54+import Language.PureScript.Names
55+import Language.PureScript.TypeChecker.Monad
56+import Language.PureScript.TypeChecker.Kinds
57+import Language.PureScript.TypeChecker.Synonyms
58+import Language.PureScript.Pretty
59+
60+import Control.Monad.State
61+import Control.Monad.Error
62+import Control.Monad.Unify
63+
64+import Control.Applicative
65+import Control.Arrow (Arrow(..))
66+
67+import qualified Data.Map as M
68+import Data.Function (on)
69+import Data.Ord (comparing)
70+
71+instance Partial Type where
72+ unknown = TUnknown
73+ isUnknown (TUnknown u) = Just u
74+ isUnknown _ = Nothing
75+
76+instance Unifiable Check Type where
77+ (=?=) = unifyTypes
78+
79+-- |
80+-- Unify two types, updating the current substitution
81+--
82+unifyTypes :: Type -> Type -> UnifyT Type Check ()
83+unifyTypes t1 t2 = rethrow (\e -> "Error unifying type " ++ prettyPrintType t1 ++ " with type " ++ prettyPrintType t2 ++ ":\n" ++ e) $
84+ unifyTypes' t1 t2
85+ where
86+ unifyTypes' (TUnknown u1) (TUnknown u2) | u1 == u2 = return ()
87+ unifyTypes' (TUnknown u) t = u =:= t
88+ unifyTypes' t (TUnknown u) = u =:= t
89+ unifyTypes' (SaturatedTypeSynonym name args) ty = do
90+ ty1 <- introduceSkolemScope <=< expandTypeSynonym name $ args
91+ ty1 `unifyTypes` ty
92+ unifyTypes' ty s@(SaturatedTypeSynonym _ _) = s `unifyTypes` ty
93+ unifyTypes' (ForAll ident1 ty1 sc1) (ForAll ident2 ty2 sc2) =
94+ case (sc1, sc2) of
95+ (Just sc1', Just sc2') -> do
96+ sko <- newSkolemConstant
97+ let sk1 = skolemize ident1 sko sc1' ty1
98+ let sk2 = skolemize ident2 sko sc2' ty2
99+ sk1 `unifyTypes` sk2
100+ _ -> throwError (prettyPrintType ty1)
101+ unifyTypes' (ForAll ident ty1 (Just sc)) ty2 = do
102+ sko <- newSkolemConstant
103+ let sk = skolemize ident sko sc ty1
104+ sk `unifyTypes` ty2
105+ unifyTypes' ForAll{} _ = throwError "Skolem variable scope is unspecified"
106+ unifyTypes' ty f@ForAll{} = f `unifyTypes` ty
107+ unifyTypes' (Object row1) (Object row2) = row1 =?= row2
108+ unifyTypes' (TypeVar v1) (TypeVar v2) | v1 == v2 = return ()
109+ unifyTypes' (TypeConstructor c1) (TypeConstructor c2) = do
110+ env <- getEnv
111+ Just moduleName <- checkCurrentModule <$> get
112+ guardWith ("Cannot unify " ++ show c1 ++ " with " ++ show c2 ++ ".") (c1 == c2)
113+ unifyTypes' (TypeApp t3 t4) (TypeApp t5 t6) = do
114+ t3 `unifyTypes` t5
115+ t4 `unifyTypes` t6
116+ unifyTypes' (Skolem s1 _) (Skolem s2 _) | s1 == s2 = return ()
117+ unifyTypes' r1@RCons{} r2 = unifyRows r1 r2
118+ unifyTypes' r1 r2@RCons{} = unifyRows r1 r2
119+ unifyTypes' r1@REmpty r2 = unifyRows r1 r2
120+ unifyTypes' r1 r2@REmpty = unifyRows r1 r2
121+ unifyTypes' t3 t4 = throwError $ "Cannot unify " ++ prettyPrintType t3 ++ " with " ++ prettyPrintType t4 ++ "."
122+
123+-- |
124+-- Unify two rows, updating the current substitution
125+--
126+-- Common labels are first identified, and unified. Remaining labels and types are unified with a
127+-- trailing row unification variable, if appropriate, otherwise leftover labels result in a unification
128+-- error.
129+--
130+unifyRows :: Type -> Type -> UnifyT Type Check ()
131+unifyRows r1 r2 =
132+ let
133+ (s1, r1') = rowToList r1
134+ (s2, r2') = rowToList r2
135+ int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
136+ sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]
137+ sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]
138+ in do
139+ forM_ int (uncurry (=?=))
140+ unifyRows' sd1 r1' sd2 r2'
141+ where
142+ unifyRows' :: [(String, Type)] -> Type -> [(String, Type)] -> Type -> UnifyT Type Check ()
143+ unifyRows' [] (TUnknown u) sd r = u =:= rowFromList (sd, r)
144+ unifyRows' sd r [] (TUnknown u) = u =:= rowFromList (sd, r)
145+ unifyRows' ((name, ty):row) r others u@(TUnknown un) = do
146+ occursCheck un ty
147+ forM_ row $ \(_, t) -> occursCheck un t
148+ u' <- fresh
149+ u =?= RCons name ty u'
150+ unifyRows' row r others u'
151+ unifyRows' [] REmpty [] REmpty = return ()
152+ unifyRows' [] (TypeVar v1) [] (TypeVar v2) | v1 == v2 = return ()
153+ unifyRows' [] (Skolem s1 _) [] (Skolem s2 _) | s1 == s2 = return ()
154+ unifyRows' sd3 r3 sd4 r4 = throwError $ "Cannot unify (" ++ prettyPrintRow (rowFromList (sd3, r3)) ++ ") with (" ++ prettyPrintRow (rowFromList (sd4, r4)) ++ ")."
155+
156+-- |
157+-- Infer the types of multiple mutually-recursive values, and return elaborated values including
158+-- type class dictionaries and type annotations.
159+--
160+typesOf :: Maybe ModuleName -> ModuleName -> [(Ident, Value)] -> Check [(Ident, (Value, Type))]
161+typesOf mainModuleName moduleName vals = do
162+ tys <- fmap tidyUp . liftUnify $ do
163+ let
164+ -- Map each declaration to a name/value pair, with an optional type, if the declaration is typed
165+ es = map isTyped vals
166+ -- Filter the typed and untyped declarations
167+ typed = filter (isJust . snd . snd) es
168+ untyped = filter (isNothing . snd . snd) es
169+ -- Make a map of names to typed declarations
170+ typedDict = map (\(ident, (_, Just (ty, _))) -> (ident, ty)) typed
171+ -- Create fresh unification variables for the types of untyped declarations
172+ untypedNames <- replicateM (length untyped) fresh
173+ let
174+ -- Make a map of names to the unification variables of untyped declarations
175+ untypedDict = zip (map fst untyped) untypedNames
176+ -- Create the dictionary of all name/type pairs, which will be added to the environment during type checking
177+ dict = M.fromList (map (\(ident, ty) -> ((moduleName, ident), (ty, LocalVariable))) $ typedDict ++ untypedDict)
178+ forM es $ \e@(_, (val, _)) -> do
179+ -- If the declaration is a function, it has access to other values in the binding group.
180+ -- If not, the generated code might fail at runtime since those values might be undefined.
181+ let dict' = if isFunction val then dict else M.empty
182+ triple@(_, (val', ty)) <- case e of
183+ -- Typed declarations
184+ (ident, (val', Just (ty, checkType))) -> do
185+ -- Kind check
186+ kind <- liftCheck $ kindOf moduleName ty
187+ guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star
188+ -- Check the type with the new names in scope
189+ ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty
190+ val'' <- bindNames dict' $ if checkType
191+ then TypedValue True <$> check val' ty' <*> pure ty'
192+ else return (TypedValue False val' ty')
193+ return (ident, (val'', ty'))
194+ -- Untyped declarations
195+ (ident, (val', Nothing)) -> do
196+ -- Infer the type with the new names in scope
197+ TypedValue _ val'' ty <- bindNames dict' $ infer val'
198+ ty =?= fromMaybe (error "name not found in dictionary") (lookup ident untypedDict)
199+ return (ident, (TypedValue True val'' ty, ty))
200+ -- If --main is enabled, need to check that `main` has type Eff eff a for some eff, a
201+ when (Just moduleName == mainModuleName && fst e == Ident "main") $ do
202+ [eff, a] <- replicateM 2 fresh
203+ ty =?= TypeApp (TypeApp (TypeConstructor (Qualified (Just (ModuleName [ProperName "Control", ProperName "Monad", ProperName "Eff"])) (ProperName "Eff"))) eff) a
204+ -- Make sure unification variables do not escape
205+ escapeCheck val' ty
206+ return triple
207+ forM tys $ \(ident, (val, ty)) -> do
208+ -- Replace type class dictionary placeholders with actual dictionaries
209+ val' <- replaceTypeClassDictionaries moduleName val
210+ -- Check skolem variables did not escape their scope
211+ skolemEscapeCheck val'
212+ -- Remove type synonyms placeholders, remove duplicate row fields, and replace
213+ -- top-level unification variables with named type variables.
214+ let val'' = overTypes (desaturateAllTypeSynonyms . setifyAll) val'
215+ ty' = varIfUnknown . desaturateAllTypeSynonyms . setifyAll $ ty
216+ return (ident, (val'', ty'))
217+ where
218+ -- Apply the substitution that was returned from runUnify to both types and (type-annotated) values
219+ tidyUp (ts, sub) = map (\(i, (val, ty)) -> (i, (overTypes (sub $?) val, sub $? ty))) ts
220+
221+-- |
222+-- Check if a value introduces a function
223+--
224+isFunction :: Value -> Bool
225+isFunction (Abs _ _) = True
226+isFunction (TypedValue _ val _) = isFunction val
227+isFunction _ = False
228+
229+-- |
230+-- Check if a value contains a type annotation
231+--
232+isTyped :: (Ident, Value) -> (Ident, (Value, Maybe (Type, Bool)))
233+isTyped (name, TypedValue checkType value ty) = (name, (value, Just (ty, checkType)))
234+isTyped (name, value) = (name, (value, Nothing))
235+
236+-- |
237+-- Map a function over type annotations appearing inside a value
238+--
239+overTypes :: (Type -> Type) -> Value -> Value
240+overTypes f = everywhere (mkT f)
241+
242+-- |
243+-- Replace type class dictionary placeholders with inferred type class dictionaries
244+--
245+replaceTypeClassDictionaries :: ModuleName -> Value -> Check Value
246+replaceTypeClassDictionaries mn = everywhereM' (mkM go)
247+ where
248+ go (TypeClassDictionary constraint dicts) = entails mn dicts constraint
249+ go other = return other
250+
251+-- |
252+-- Check that the current set of type class dictionaries entail the specified type class goal, and, if so,
253+-- return a type class dictionary reference.
254+--
255+entails :: ModuleName -> [TypeClassDictionaryInScope] -> (Qualified ProperName, [Type]) -> Check Value
256+entails moduleName context goal@(className, tys) = do
257+ env <- getEnv
258+ case go env goal of
259+ [] -> throwError $ "No " ++ show className ++ " instance found for " ++ intercalate ", " (map prettyPrintType tys)
260+ (dict : _) -> return dict
261+ where
262+ go env (className', tys') =
263+ [ mkDictionary (canonicalizeDictionary tcd) args
264+ | tcd <- context
265+ -- Choose type class dictionaries in scope in the current module
266+ , filterModule tcd
267+ -- Make sure the type class name matches the one we are trying to satisfy
268+ , className' == tcdClassName tcd
269+ -- Make sure the type unifies with the type in the type instance definition
270+ , subst <- maybeToList . (>>= verifySubstitution) . fmap concat $ zipWithM (typeHeadsAreEqual moduleName env) tys' (tcdInstanceTypes tcd)
271+ -- Solve any necessary subgoals
272+ , args <- solveSubgoals env subst (tcdDependencies tcd) ]
273+ -- Create dictionaries for subgoals which still need to be solved by calling go recursively
274+ -- E.g. the goal (Show a, Show b) => Show (Either a b) can be satisfied if the current type
275+ -- unifies with Either a b, and we can satisfy the subgoals Show a and Show b recursively.
276+ solveSubgoals :: Environment -> [(String, Type)] -> Maybe [(Qualified ProperName, [Type])] -> [Maybe [Value]]
277+ solveSubgoals _ _ Nothing = return Nothing
278+ solveSubgoals env subst (Just subgoals) = do
279+ dict <- mapM (go env . second (map (replaceAllTypeVars subst))) subgoals
280+ return $ Just dict
281+ -- Make a dictionary from subgoal dictionaries by applying the correct function
282+ mkDictionary :: Qualified Ident -> Maybe [Value] -> Value
283+ mkDictionary fnName Nothing = Var fnName
284+ mkDictionary fnName (Just []) = App (Var fnName) (ObjectLiteral [])
285+ mkDictionary fnName (Just dicts) = foldl App (Var fnName) dicts
286+ -- Filter out type dictionaries which are in scope in the current module
287+ filterModule :: TypeClassDictionaryInScope -> Bool
288+ filterModule (TypeClassDictionaryInScope { tcdName = Qualified (Just mn) _ }) | mn == moduleName = True
289+ filterModule (TypeClassDictionaryInScope { tcdName = Qualified Nothing _ }) = True
290+ filterModule _ = False
291+ -- Resolve a type class dictionary in scope to an actual value by following any (TCDAlias) pointers
292+ -- which originated from module imports
293+ canonicalizeDictionary :: TypeClassDictionaryInScope -> Qualified Ident
294+ canonicalizeDictionary (TypeClassDictionaryInScope { tcdType = TCDRegular, tcdName = nm }) = nm
295+ canonicalizeDictionary (TypeClassDictionaryInScope { tcdType = TCDAlias nm }) = nm
296+ -- Ensure that a substitution is valid
297+ verifySubstitution :: [(String, Type)] -> Maybe [(String, Type)]
298+ verifySubstitution subst = do
299+ let grps = groupBy ((==) `on` fst) subst
300+ guard (all ((==) 1 . length . nubBy ((==) `on` snd)) grps)
301+ return $ map head grps
302+
303+-- |
304+-- Check whether the type heads of two types are equal (for the purposes of type class dictionary lookup),
305+-- and return a substitution from type variables to types which makes the type heads unify.
306+--
307+typeHeadsAreEqual :: ModuleName -> Environment -> Type -> Type -> Maybe [(String, Type)]
308+typeHeadsAreEqual _ _ (Skolem s1 _) (Skolem s2 _) | s1 == s2 = Just []
309+typeHeadsAreEqual _ _ (TypeVar v) t = Just [(v, t)]
310+typeHeadsAreEqual _ _ t (TypeVar v) = Just [(v, t)]
311+typeHeadsAreEqual m e (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = Just []
312+typeHeadsAreEqual m e (TypeApp h1 (TypeVar v)) (TypeApp h2 arg) = (:) (v, arg) <$> typeHeadsAreEqual m e h1 h2
313+typeHeadsAreEqual m e t1@(TypeApp _ _) t2@(TypeApp _ (TypeVar _)) = typeHeadsAreEqual m e t2 t1
314+typeHeadsAreEqual m e (SaturatedTypeSynonym name args) t2 = case expandTypeSynonym' e m name args of
315+ Left _ -> Nothing
316+ Right t1 -> typeHeadsAreEqual m e t1 t2
317+typeHeadsAreEqual _ _ _ _ = Nothing
318+
319+-- |
320+-- Ensure unsolved unification variables do not escape
321+--
322+escapeCheck :: Value -> Type -> UnifyT Type Check ()
323+escapeCheck value ty = do
324+ subst <- unifyCurrentSubstitution <$> UnifyT get
325+ let visibleUnknowns = nub $ unknowns $ subst $? ty
326+ let allUnknowns = findAllTypes value
327+ forM_ allUnknowns $ \t -> do
328+ let unsolvedUnknowns = nub . unknowns $ subst $? t
329+ guardWith "Escape check fails" $ null $ unsolvedUnknowns \\ visibleUnknowns
330+
331+-- |
332+-- Find all type annotations occuring inside a value
333+--
334+findAllTypes :: Value -> [Type]
335+findAllTypes = everything (++) (mkQ [] go)
336+ where
337+ go (TypedValue _ _ ty) = [ty]
338+ go _ = []
339+
340+-- |
341+-- Ensure skolem variables do not escape their scope
342+--
343+skolemEscapeCheck :: Value -> Check ()
344+skolemEscapeCheck (TypedValue False _ _) = return ()
345+skolemEscapeCheck root@TypedValue{} =
346+ -- Every skolem variable is created when a ForAll type is skolemized.
347+ -- This determines the scope of that skolem variable, which is copied from the SkolemScope
348+ -- field of the ForAll constructor.
349+ -- We traverse the tree top-down, and collect any SkolemScopes introduced by ForAlls.
350+ -- If a Skolem is encountered whose SkolemScope is not in the current list, we have found
351+ -- an escaped skolem variable.
352+ case everythingWithContext [] (++) (mkQ ((,) []) go) root of
353+ [] -> return ()
354+ ((binding, val) : _) -> throwError $ "Rigid/skolem type variable bound by " ++ maybe "<unknown>" prettyPrintValue binding ++ " has escaped at " ++ prettyPrintValue val
355+ where
356+ go :: Value -> [(SkolemScope, Value)] -> ([(Maybe Value, Value)], [(SkolemScope, Value)])
357+ go val@(TypedValue _ _ (ForAll _ _ (Just sco))) scos = ([], (sco, val) : scos)
358+ go val@(TypedValue _ _ ty) scos = case collectSkolems ty \\ map fst scos of
359+ (sco : _) -> ([(findBindingScope sco, val)], scos)
360+ _ -> ([], scos)
361+ where
362+ collectSkolems :: Type -> [SkolemScope]
363+ collectSkolems = nub . everything (++) (mkQ [] collect)
364+ where
365+ collect (Skolem _ scope) = [scope]
366+ collect _ = []
367+ go _ scos = ([], scos)
368+ findBindingScope :: SkolemScope -> Maybe Value
369+ findBindingScope sco = something (mkQ Nothing go') root
370+ where
371+ go' val@(TypedValue _ _ (ForAll _ _ (Just sco'))) | sco == sco' = Just val
372+ go' _ = Nothing
373+skolemEscapeCheck val = throwError $ "Untyped value passed to skolemEscapeCheck: " ++ prettyPrintValue val
374+
375+-- |
376+-- Ensure a row contains no duplicate labels
377+--
378+setify :: Type -> Type
379+setify = rowFromList . first (M.toList . M.fromList) . rowToList
380+
381+-- |
382+-- \"Setify\" all rows occuring inside a value
383+--
384+setifyAll :: (D.Data d) => d -> d
385+setifyAll = everywhere (mkT setify)
386+
387+-- |
388+-- Replace outermost unsolved unification variables with named type variables
389+--
390+varIfUnknown :: Type -> Type
391+varIfUnknown ty =
392+ let unks = nub $ unknowns ty
393+ toName = (:) 't' . show
394+ ty' = everywhere (mkT typeToVar) ty
395+ typeToVar :: Type -> Type
396+ typeToVar (TUnknown (Unknown u)) = TypeVar (toName u)
397+ typeToVar t = t
398+ in mkForAll (sort . map (toName . runUnknown) $ unks) ty'
399+
400+-- |
401+-- Remove any ForAlls and ConstrainedType constructors in a type by introducing new unknowns
402+-- or TypeClassDictionary values.
403+--
404+-- This is necessary during type checking to avoid unifying a polymorphic type with a
405+-- unification variable.
406+--
407+instantiatePolyTypeWithUnknowns :: Value -> Type -> UnifyT Type Check (Value, Type)
408+instantiatePolyTypeWithUnknowns val (ForAll ident ty _) = do
409+ ty' <- replaceVarWithUnknown ident ty
410+ instantiatePolyTypeWithUnknowns val ty'
411+instantiatePolyTypeWithUnknowns val (ConstrainedType constraints ty) = do
412+ env <- getEnv
413+ Just moduleName <- checkCurrentModule <$> get
414+ dicts <- getTypeClassDictionaries
415+ (_, ty') <- instantiatePolyTypeWithUnknowns (error "Types under a constraint cannot themselves be constrained") ty
416+ return (foldl App val (map (flip TypeClassDictionary dicts) constraints), ty')
417+instantiatePolyTypeWithUnknowns val ty = return (val, ty)
418+
419+-- |
420+-- Replace a single type variable with a new unification variable
421+--
422+replaceVarWithUnknown :: String -> Type -> UnifyT Type Check Type
423+replaceVarWithUnknown ident ty = do
424+ tu <- fresh
425+ return $ replaceTypeVars ident tu ty
426+
427+-- |
428+-- Replace fully applied type synonyms with the @SaturatedTypeSynonym@ data constructor, which helps generate
429+-- better error messages during unification.
430+--
431+replaceAllTypeSynonyms' :: (D.Data d) => Environment -> ModuleName -> d -> Either String d
432+replaceAllTypeSynonyms' env moduleName d =
433+ let
434+ syns = map (\(name, (args, _)) -> (name, length args)) . M.toList $ typeSynonyms env
435+ in
436+ saturateAllTypeSynonyms env moduleName syns d
437+
438+replaceAllTypeSynonyms :: (Functor m, Monad m, MonadState CheckState m, MonadError String m) => (D.Data d) => d -> m d
439+replaceAllTypeSynonyms d = do
440+ env <- getEnv
441+ Just moduleName <- checkCurrentModule <$> get
442+ either throwError return $ replaceAllTypeSynonyms' env moduleName d
443+
444+-- |
445+-- \"Desaturate\" @SaturatedTypeSynonym@s
446+--
447+desaturateAllTypeSynonyms :: (D.Data d) => d -> d
448+desaturateAllTypeSynonyms = everywhere (mkT replaceSaturatedTypeSynonym)
449+ where
450+ replaceSaturatedTypeSynonym (SaturatedTypeSynonym name args) = foldl TypeApp (TypeConstructor name) args
451+ replaceSaturatedTypeSynonym t = t
452+
453+-- |
454+-- Replace a type synonym and its arguments with the aliased type
455+--
456+expandTypeSynonym' :: Environment -> ModuleName -> Qualified ProperName -> [Type] -> Either String Type
457+expandTypeSynonym' env moduleName name args =
458+ case M.lookup name (typeSynonyms env) of
459+ Just (synArgs, body) -> do
460+ let repl = replaceAllTypeVars (zip synArgs args) body
461+ replaceAllTypeSynonyms' env moduleName repl
462+ Nothing -> error "Type synonym was not defined"
463+
464+expandTypeSynonym :: (Functor m, Monad m, MonadState CheckState m, MonadError String m) => Qualified ProperName -> [Type] -> m Type
465+expandTypeSynonym name args = do
466+ env <- getEnv
467+ Just moduleName <- checkCurrentModule <$> get
468+ either throwError return $ expandTypeSynonym' env moduleName name args
469+
470+-- |
471+-- Ensure a set of property names and value does not contain duplicate labels
472+--
473+ensureNoDuplicateProperties :: (MonadError String m) => [(String, Value)] -> m ()
474+ensureNoDuplicateProperties ps = guardWith "Duplicate property names" $ length (nub . map fst $ ps) == length ps
475+
476+-- |
477+-- Infer a type for a value, rethrowing any error to provide a more useful error message
478+--
479+infer :: Value -> UnifyT Type Check Value
480+infer val = rethrow (\e -> "Error inferring type of term " ++ prettyPrintValue val ++ ":\n" ++ e) $ infer' val
481+
482+-- |
483+-- Infer a type for a value
484+--
485+infer' :: Value -> UnifyT Type Check Value
486+infer' v@(NumericLiteral _) = return $ TypedValue True v tyNumber
487+infer' v@(StringLiteral _) = return $ TypedValue True v tyString
488+infer' v@(BooleanLiteral _) = return $ TypedValue True v tyBoolean
489+infer' (ArrayLiteral vals) = do
490+ ts <- mapM infer vals
491+ els <- fresh
492+ forM_ ts $ \(TypedValue _ _ t) -> els =?= TypeApp tyArray t
493+ return $ TypedValue True (ArrayLiteral ts) els
494+infer' (ObjectLiteral ps) = do
495+ ensureNoDuplicateProperties ps
496+ ts <- mapM (infer . snd) ps
497+ let fields = zipWith (\name (TypedValue _ _ t) -> (name, t)) (map fst ps) ts
498+ ty = Object $ rowFromList (fields, REmpty)
499+ return $ TypedValue True (ObjectLiteral (zip (map fst ps) ts)) ty
500+infer' (ObjectUpdate o ps) = do
501+ ensureNoDuplicateProperties ps
502+ row <- fresh
503+ newVals <- zipWith (\(name, _) t -> (name, t)) ps <$> mapM (infer . snd) ps
504+ let newTys = map (\(name, TypedValue _ _ ty) -> (name, ty)) newVals
505+ oldTys <- zip (map fst ps) <$> replicateM (length ps) fresh
506+ let oldTy = Object $ rowFromList (oldTys, row)
507+ o' <- TypedValue True <$> check o oldTy <*> pure oldTy
508+ return $ TypedValue True (ObjectUpdate o' newVals) $ Object $ rowFromList (newTys, row)
509+infer' (Accessor prop val) = do
510+ typed@(TypedValue _ _ objTy) <- infer val
511+ propTy <- inferProperty objTy prop
512+ case propTy of
513+ Nothing -> do
514+ field <- fresh
515+ rest <- fresh
516+ _ <- subsumes Nothing objTy (Object (RCons prop field rest))
517+ return $ TypedValue True (Accessor prop typed) field
518+ Just ty -> return $ TypedValue True (Accessor prop typed) ty
519+infer' (Abs (Left arg) ret) = do
520+ ty <- fresh
521+ Just moduleName <- checkCurrentModule <$> get
522+ bindLocalVariables moduleName [(arg, ty)] $ do
523+ body@(TypedValue _ _ bodyTy) <- infer' ret
524+ return $ TypedValue True (Abs (Left arg) body) $ function ty bodyTy
525+infer' (Abs (Right _) _) = error "Binder was not desugared"
526+infer' (App f arg) = do
527+ f'@(TypedValue _ _ ft) <- infer f
528+ (ret, app) <- checkFunctionApplication f' ft arg
529+ return $ TypedValue True app ret
530+infer' (Var var) = do
531+ Just moduleName <- checkCurrentModule <$> get
532+ ty <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< lookupVariable moduleName $ var
533+ case ty of
534+ ConstrainedType constraints ty' -> do
535+ env <- getEnv
536+ dicts <- getTypeClassDictionaries
537+ return $ TypedValue True (foldl App (Var var) (map (flip TypeClassDictionary dicts) constraints)) ty'
538+ _ -> return $ TypedValue True (Var var) ty
539+infer' v@(Constructor c) = do
540+ env <- getEnv
541+ Just moduleName <- checkCurrentModule <$> get
542+ case M.lookup c (dataConstructors env) of
543+ Nothing -> throwError $ "Constructor " ++ show c ++ " is undefined"
544+ Just ty -> do ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty
545+ return $ TypedValue True v ty'
546+infer' (Case vals binders) = do
547+ ts <- mapM infer vals
548+ ret <- fresh
549+ binders' <- checkBinders (map (\(TypedValue _ _ t) -> t) ts) ret binders
550+ return $ TypedValue True (Case ts binders') ret
551+infer' (IfThenElse cond th el) = do
552+ cond' <- check cond tyBoolean
553+ v2@(TypedValue _ _ t2) <- infer th
554+ v3@(TypedValue _ _ t3) <- infer el
555+ t2 =?= t3
556+ return $ TypedValue True (IfThenElse cond' v2 v3) t2
557+infer' (TypedValue checkType val ty) = do
558+ Just moduleName <- checkCurrentModule <$> get
559+ kind <- liftCheck $ kindOf moduleName ty
560+ guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star
561+ ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty
562+ val' <- if checkType then check val ty' else return val
563+ return $ TypedValue True val' ty'
564+infer' _ = error "Invalid argument to infer"
565+
566+-- |
567+-- Infer the type of a property inside a record with a given type
568+--
569+inferProperty :: Type -> String -> UnifyT Type Check (Maybe Type)
570+inferProperty (Object row) prop = do
571+ let (props, _) = rowToList row
572+ return $ lookup prop props
573+inferProperty (SaturatedTypeSynonym name args) prop = do
574+ replaced <- introduceSkolemScope <=< expandTypeSynonym name $ args
575+ inferProperty replaced prop
576+inferProperty (ForAll ident ty _) prop = do
577+ replaced <- replaceVarWithUnknown ident ty
578+ inferProperty replaced prop
579+inferProperty _ _ = return Nothing
580+
581+-- |
582+-- Infer the types of variables brought into scope by a binder
583+--
584+inferBinder :: Type -> Binder -> UnifyT Type Check (M.Map Ident Type)
585+inferBinder _ NullBinder = return M.empty
586+inferBinder val (StringBinder _) = val =?= tyString >> return M.empty
587+inferBinder val (NumberBinder _) = val =?= tyNumber >> return M.empty
588+inferBinder val (BooleanBinder _) = val =?= tyBoolean >> return M.empty
589+inferBinder val (VarBinder name) = return $ M.singleton name val
590+inferBinder val (ConstructorBinder ctor binders) = do
591+ env <- getEnv
592+ Just moduleName <- checkCurrentModule <$> get
593+ case M.lookup ctor (dataConstructors env) of
594+ Just ty -> do
595+ (_, fn) <- instantiatePolyTypeWithUnknowns (error "Data constructor types cannot contains constraints") ty
596+ go binders fn
597+ where
598+ go [] ty' = do
599+ subsumes Nothing val ty'
600+ return M.empty
601+ go (binder : binders') (TypeApp (TypeApp t obj) ret) | t == tyFunction =
602+ M.union <$> inferBinder obj binder <*> go binders' ret
603+ go _ _ = throwError $ "Wrong number of arguments to constructor " ++ show ctor
604+ _ -> throwError $ "Constructor " ++ show ctor ++ " is not defined"
605+inferBinder val (ObjectBinder props) = do
606+ row <- fresh
607+ rest <- fresh
608+ m1 <- inferRowProperties row rest props
609+ val =?= Object row
610+ return m1
611+ where
612+ inferRowProperties :: Type -> Type -> [(String, Binder)] -> UnifyT Type Check (M.Map Ident Type)
613+ inferRowProperties nrow row [] = nrow =?= row >> return M.empty
614+ inferRowProperties nrow row ((name, binder):binders) = do
615+ propTy <- fresh
616+ m1 <- inferBinder propTy binder
617+ m2 <- inferRowProperties nrow (RCons name propTy row) binders
618+ return $ m1 `M.union` m2
619+inferBinder val (ArrayBinder binders) = do
620+ el <- fresh
621+ m1 <- M.unions <$> mapM (inferBinder el) binders
622+ val =?= TypeApp tyArray el
623+ return m1
624+inferBinder val (ConsBinder headBinder tailBinder) = do
625+ el <- fresh
626+ m1 <- inferBinder el headBinder
627+ m2 <- inferBinder val tailBinder
628+ val =?= TypeApp tyArray el
629+ return $ m1 `M.union` m2
630+inferBinder val (NamedBinder name binder) = do
631+ m <- inferBinder val binder
632+ return $ M.insert name val m
633+
634+-- |
635+-- Check the types of the return values in a set of binders in a case statement
636+--
637+checkBinders :: [Type] -> Type -> [([Binder], Maybe Guard, Value)] -> UnifyT Type Check [([Binder], Maybe Guard, Value)]
638+checkBinders _ _ [] = return []
639+checkBinders nvals ret ((binders, grd, val):bs) = do
640+ Just moduleName <- checkCurrentModule <$> get
641+ m1 <- M.unions <$> zipWithM inferBinder nvals binders
642+ r <- bindLocalVariables moduleName (M.toList m1) $ do
643+ val' <- TypedValue True <$> check val ret <*> pure ret
644+ case grd of
645+ Nothing -> return (binders, Nothing, val')
646+ Just g -> do
647+ g' <- check g tyBoolean
648+ return (binders, Just g', val')
649+ rs <- checkBinders nvals ret bs
650+ return $ r : rs
651+
652+-- |
653+-- Check that a local variable name is not already used
654+--
655+assignVariable :: Ident -> UnifyT Type Check ()
656+assignVariable name = do
657+ env <- checkEnv <$> get
658+ Just moduleName <- checkCurrentModule <$> get
659+ case M.lookup (moduleName, name) (names env) of
660+ Just _ -> UnifyT . lift . throwError $ "Variable with name " ++ show name ++ " already exists."
661+ _ -> return ()
662+
663+-- |
664+-- Generate a new skolem constant
665+--
666+newSkolemConstant :: UnifyT Type Check Int
667+newSkolemConstant = runUnknown <$> fresh'
668+
669+-- |
670+-- Generate a new skolem scope
671+--
672+newSkolemScope :: UnifyT Type Check SkolemScope
673+newSkolemScope = SkolemScope . runUnknown <$> fresh'
674+
675+-- |
676+-- Skolemize a type variable by replacing its instances with fresh skolem constants
677+--
678+skolemize :: String -> Int -> SkolemScope -> Type -> Type
679+skolemize ident sko scope = replaceTypeVars ident (Skolem sko scope)
680+
681+-- |
682+-- Introduce skolem scope at every occurence of a ForAll
683+--
684+introduceSkolemScope :: Type -> UnifyT Type Check Type
685+introduceSkolemScope = everywhereM (mkM go)
686+ where
687+ go (ForAll ident ty Nothing) = ForAll ident ty <$> (Just <$> newSkolemScope)
688+ go other = return other
689+
690+-- |
691+-- Check the type of a value, rethrowing errors to provide a better error message
692+--
693+check :: Value -> Type -> UnifyT Type Check Value
694+check val ty = rethrow errorMessage $ check' val ty
695+ where
696+ errorMessage msg =
697+ "Error checking type of term " ++
698+ prettyPrintValue val ++
699+ " against type " ++
700+ prettyPrintType ty ++
701+ ":\n" ++
702+ msg
703+
704+-- |
705+-- Check the type of a value
706+--
707+check' :: Value -> Type -> UnifyT Type Check Value
708+check' val (ForAll ident ty _) = do
709+ scope <- newSkolemScope
710+ sko <- newSkolemConstant
711+ let sk = skolemize ident sko scope ty
712+ val' <- check val sk
713+ return $ TypedValue True val' (ForAll ident ty (Just scope))
714+check' val t@(ConstrainedType constraints ty) = do
715+ env <- getEnv
716+ Just moduleName <- checkCurrentModule <$> get
717+ dictNames <- forM constraints $ \(Qualified _ (ProperName className), _) -> do
718+ n <- liftCheck freshDictionaryName
719+ return $ Ident $ "__dict_" ++ className ++ "_" ++ show n
720+ val' <- withTypeClassDictionaries (zipWith (\name (className, instanceTy) ->
721+ TypeClassDictionaryInScope name className instanceTy Nothing TCDRegular) (map (Qualified Nothing) dictNames)
722+ constraints) $ check val ty
723+ return $ TypedValue True (foldr (Abs . Left) val' dictNames) t
724+check' val (SaturatedTypeSynonym name args) = do
725+ ty <- introduceSkolemScope <=< expandTypeSynonym name $ args
726+ val' <- check val ty
727+ return $ TypedValue True val' ty
728+check' val u@(TUnknown _) = do
729+ val'@(TypedValue _ _ ty) <- infer val
730+ -- Don't unify an unknown with an inferred polytype
731+ (val'', ty') <- instantiatePolyTypeWithUnknowns val' ty
732+ ty' =?= u
733+ return $ TypedValue True val'' ty'
734+check' v@(NumericLiteral _) t | t == tyNumber =
735+ return $ TypedValue True v t
736+check' v@(StringLiteral _) t | t == tyString =
737+ return $ TypedValue True v t
738+check' v@(BooleanLiteral _) t | t == tyBoolean =
739+ return $ TypedValue True v t
740+check' (ArrayLiteral vals) t@(TypeApp a ty) | a == tyArray = do
741+ array <- ArrayLiteral <$> forM vals (`check` ty)
742+ return $ TypedValue True array t
743+check' (Abs (Left arg) ret) ty@(TypeApp (TypeApp t argTy) retTy) | t == tyFunction = do
744+ Just moduleName <- checkCurrentModule <$> get
745+ ret' <- bindLocalVariables moduleName [(arg, argTy)] $ check ret retTy
746+ return $ TypedValue True (Abs (Left arg) ret') ty
747+check' (Abs (Right _) _) _ = error "Binder was not desugared"
748+check' (App f arg) ret = do
749+ f'@(TypedValue _ _ ft) <- infer f
750+ (ret', app) <- checkFunctionApplication f' ft arg
751+ subsumes Nothing ret' ret
752+ return $ TypedValue True app ret
753+check' v@(Var var) ty = do
754+ Just moduleName <- checkCurrentModule <$> get
755+ repl <- introduceSkolemScope <=< replaceAllTypeSynonyms <=< lookupVariable moduleName $ var
756+ ty' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty
757+ v' <- subsumes (Just v) repl ty'
758+ case v' of
759+ Nothing -> throwError "Unable to check type subsumption"
760+ Just v'' -> return $ TypedValue True v'' ty'
761+check' (TypedValue checkType val ty1) ty2 = do
762+ Just moduleName <- checkCurrentModule <$> get
763+ kind <- liftCheck $ kindOf moduleName ty1
764+ guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star
765+ ty1' <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty1
766+ val' <- subsumes (Just val) ty1' ty2
767+ case val' of
768+ Nothing -> throwError "Unable to check type subsumption"
769+ Just val'' -> do
770+ val''' <- if checkType then check val'' ty1 else return val''
771+ return $ TypedValue checkType (TypedValue True val''' ty1) ty2
772+check' (Case vals binders) ret = do
773+ vals' <- mapM infer vals
774+ let ts = map (\(TypedValue _ _ t) -> t) vals'
775+ binders' <- checkBinders ts ret binders
776+ return $ TypedValue True (Case vals' binders') ret
777+check' (IfThenElse cond th el) ty = do
778+ cond' <- check cond tyBoolean
779+ th' <- check th ty
780+ el' <- check el ty
781+ return $ TypedValue True (IfThenElse cond' th' el') ty
782+check' (ObjectLiteral ps) t@(Object row) = do
783+ ensureNoDuplicateProperties ps
784+ ps' <- checkProperties ps row False
785+ return $ TypedValue True (ObjectLiteral ps') t
786+check' (ObjectUpdate obj ps) t@(Object row) = do
787+ ensureNoDuplicateProperties ps
788+ us <- zip (map fst ps) <$> replicateM (length ps) fresh
789+ let (propsToCheck, rest) = rowToList row
790+ propsToRemove = map fst ps
791+ remainingProps = filter (\(p, _) -> p `notElem` propsToRemove) propsToCheck
792+ obj' <- check obj (Object (rowFromList (us ++ remainingProps, rest)))
793+ ps' <- checkProperties ps row True
794+ return $ TypedValue True (ObjectUpdate obj' ps') t
795+check' (Accessor prop val) ty = do
796+ rest <- fresh
797+ val' <- check val (Object (RCons prop ty rest))
798+ return $ TypedValue True (Accessor prop val') ty
799+check' (Constructor c) ty = do
800+ env <- getEnv
801+ Just moduleName <- checkCurrentModule <$> get
802+ case M.lookup c (dataConstructors env) of
803+ Nothing -> throwError $ "Constructor " ++ show c ++ " is undefined"
804+ Just ty1 -> do
805+ repl <- introduceSkolemScope <=< replaceAllTypeSynonyms $ ty1
806+ _ <- subsumes Nothing repl ty
807+ return $ TypedValue True (Constructor c) ty
808+check' val ty = throwError $ prettyPrintValue val ++ " does not have type " ++ prettyPrintType ty
809+
810+-- |
811+-- Check the type of a collection of named record fields
812+--
813+-- The @lax@ parameter controls whether or not every record member has to be provided. For object updates, this is not the case.
814+--
815+checkProperties :: [(String, Value)] -> Type -> Bool -> UnifyT Type Check [(String, Value)]
816+checkProperties ps row lax = let (ts, r') = rowToList row in go ps ts r' where
817+ go [] [] REmpty = return []
818+ go [] [] u@(TUnknown _) = do u =?= REmpty
819+ return []
820+ go [] [] (Skolem _ _) | lax = return []
821+ go [] ((p, _): _) _ | lax = return []
822+ | otherwise = throwError $ prettyPrintValue (ObjectLiteral ps) ++ " does not have property " ++ p
823+ go ((p,_):_) [] REmpty = throwError $ "Property " ++ p ++ " is not present in closed object type " ++ prettyPrintRow row
824+ go ((p,v):ps') [] u@(TUnknown _) = do
825+ v'@(TypedValue _ _ ty) <- infer v
826+ rest <- fresh
827+ u =?= RCons p ty rest
828+ ps'' <- go ps' [] rest
829+ return $ (p, v') : ps''
830+ go ((p,v):ps') ts r =
831+ case lookup p ts of
832+ Nothing -> do
833+ v'@(TypedValue _ _ ty) <- infer v
834+ rest <- fresh
835+ r =?= RCons p ty rest
836+ ps'' <- go ps' ts rest
837+ return $ (p, v') : ps''
838+ Just ty -> do
839+ v' <- check v ty
840+ ps'' <- go ps' (delete (p, ty) ts) r
841+ return $ (p, v') : ps''
842+ go _ _ _ = throwError $ prettyPrintValue (ObjectLiteral ps) ++ " does not have type " ++ prettyPrintType (Object row)
843+
844+-- |
845+-- Check the type of a function application, rethrowing errors to provide a better error message
846+--
847+checkFunctionApplication :: Value -> Type -> Value -> UnifyT Type Check (Type, Value)
848+checkFunctionApplication fn fnTy arg = rethrow errorMessage $ checkFunctionApplication' fn fnTy arg
849+ where
850+ errorMessage msg = "Error applying function of type "
851+ ++ prettyPrintType fnTy
852+ ++ " to argument " ++ prettyPrintValue arg
853+ ++ ":\n" ++ msg
854+
855+-- |
856+-- Check the type of a function application
857+--
858+checkFunctionApplication' :: Value -> Type -> Value -> UnifyT Type Check (Type, Value)
859+checkFunctionApplication' fn (TypeApp (TypeApp tyFunction' argTy) retTy) arg = do
860+ tyFunction' =?= tyFunction
861+ arg' <- check arg argTy
862+ return (retTy, App fn arg')
863+checkFunctionApplication' fn (ForAll ident ty _) arg = do
864+ replaced <- replaceVarWithUnknown ident ty
865+ checkFunctionApplication fn replaced arg
866+checkFunctionApplication' fn u@(TUnknown _) arg = do
867+ arg' <- do
868+ TypedValue _ arg' t <- infer arg
869+ (arg'', t') <- instantiatePolyTypeWithUnknowns arg' t
870+ return $ TypedValue True arg'' t'
871+ let ty = (\(TypedValue _ _ t) -> t) arg'
872+ ret <- fresh
873+ u =?= function ty ret
874+ return (ret, App fn arg')
875+checkFunctionApplication' fn (SaturatedTypeSynonym name tyArgs) arg = do
876+ ty <- introduceSkolemScope <=< expandTypeSynonym name $ tyArgs
877+ checkFunctionApplication fn ty arg
878+checkFunctionApplication' fn (ConstrainedType constraints fnTy) arg = do
879+ env <- getEnv
880+ dicts <- getTypeClassDictionaries
881+ Just moduleName <- checkCurrentModule <$> get
882+ checkFunctionApplication' (foldl App fn (map (flip TypeClassDictionary dicts) constraints)) fnTy arg
883+checkFunctionApplication' _ fnTy arg = throwError $ "Cannot apply a function of type "
884+ ++ prettyPrintType fnTy
885+ ++ " to argument " ++ prettyPrintValue arg
886+
887+-- |
888+-- Check whether one type subsumes another, rethrowing errors to provide a better error message
889+--
890+subsumes :: Maybe Value -> Type -> Type -> UnifyT Type Check (Maybe Value)
891+subsumes val ty1 ty2 = rethrow errorMessage $ subsumes' val ty1 ty2
892+ where
893+ errorMessage msg = "Error checking that type "
894+ ++ prettyPrintType ty1
895+ ++ " subsumes type "
896+ ++ prettyPrintType ty2
897+ ++ ":\n" ++ msg
898+
899+-- |
900+-- Check whether one type subsumes another
901+--
902+subsumes' :: Maybe Value -> Type -> Type -> UnifyT Type Check (Maybe Value)
903+subsumes' val (ForAll ident ty1 _) ty2 = do
904+ replaced <- replaceVarWithUnknown ident ty1
905+ subsumes val replaced ty2
906+subsumes' val ty1 (ForAll ident ty2 sco) =
907+ case sco of
908+ Just sco' -> do
909+ sko <- newSkolemConstant
910+ let sk = skolemize ident sko sco' ty2
911+ subsumes val ty1 sk
912+ Nothing -> throwError "Skolem variable scope is unspecified"
913+subsumes' val (TypeApp (TypeApp f1 arg1) ret1) (TypeApp (TypeApp f2 arg2) ret2) | f1 == tyFunction && f2 == tyFunction = do
914+ subsumes Nothing arg2 arg1
915+ subsumes Nothing ret1 ret2
916+ return val
917+subsumes' val (SaturatedTypeSynonym name tyArgs) ty2 = do
918+ ty1 <- introduceSkolemScope <=< expandTypeSynonym name $ tyArgs
919+ subsumes val ty1 ty2
920+subsumes' val ty1 (SaturatedTypeSynonym name tyArgs) = do
921+ ty2 <- introduceSkolemScope <=< expandTypeSynonym name $ tyArgs
922+ subsumes val ty1 ty2
923+subsumes' (Just val) (ConstrainedType constraints ty1) ty2 = do
924+ env <- getEnv
925+ dicts <- getTypeClassDictionaries
926+ Just moduleName <- checkCurrentModule <$> get
927+ _ <- subsumes' Nothing ty1 ty2
928+ return . Just $ foldl App val (map (flip TypeClassDictionary dicts) constraints)
929+subsumes' val (Object r1) (Object r2) = do
930+ let
931+ (ts1, r1') = rowToList r1
932+ (ts2, r2') = rowToList r2
933+ ts1' = sortBy (comparing fst) ts1
934+ ts2' = sortBy (comparing fst) ts2
935+ go ts1' ts2' r1' r2'
936+ return val
937+ where
938+ go [] ts2 r1' r2' = r1' =?= rowFromList (ts2, r2')
939+ go ts1 [] r1' r2' = r2' =?= rowFromList (ts1, r1')
940+ go ((p1, ty1) : ts1) ((p2, ty2) : ts2) r1' r2'
941+ | p1 == p2 = do subsumes Nothing ty1 ty2
942+ go ts1 ts2 r1' r2'
943+ | p1 < p2 = do rest <- fresh
944+ r2' =?= RCons p1 ty1 rest
945+ go ts1 ((p2, ty2) : ts2) r1' rest
946+ | p1 > p2 = do rest <- fresh
947+ r1' =?= RCons p2 ty2 rest
948+ go ((p1, ty1) : ts1) ts2 rest r2'
949+subsumes' val ty1 ty2@(Object _) = subsumes val ty2 ty1
950+subsumes' val ty1 ty2 = do
951+ ty1 =?= ty2
952+ return val
953+
src/Language/PureScript/Types.hsnew file+223
@@ -0,0 +1,223 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Types
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+-- Data types for types
13+--
14+-----------------------------------------------------------------------------
15+
16+{-# LANGUAGE DeriveDataTypeable #-}
17+
18+module Language.PureScript.Types where
19+
20+import Data.Data
21+import Data.List (nub)
22+import Data.Generics (everything, mkQ)
23+
24+import Control.Monad.Unify
25+import Control.Arrow (second)
26+
27+import Language.PureScript.Names
28+
29+-- |
30+-- An identifier for the scope of a skolem variable
31+--
32+newtype SkolemScope = SkolemScope { runSkolemScope :: Int } deriving (Show, Eq, Ord, Data, Typeable)
33+
34+-- |
35+-- The type of types
36+--
37+data Type
38+ -- |
39+ -- A unification variable of type Type
40+ --
41+ = TUnknown Unknown
42+ -- |
43+ -- Javascript numbers
44+ --
45+ | Object Type
46+ -- |
47+ -- A named type variable
48+ --
49+ | TypeVar String
50+ -- |
51+ -- A type constructor
52+ --
53+ | TypeConstructor (Qualified ProperName)
54+ -- |
55+ -- A type application
56+ --
57+ | TypeApp Type Type
58+ -- |
59+ -- A type synonym which is \"saturated\", i.e. fully applied
60+ --
61+ | SaturatedTypeSynonym (Qualified ProperName) [Type]
62+ -- |
63+ -- Forall quantifier
64+ --
65+ | ForAll String Type (Maybe SkolemScope)
66+ -- |
67+ -- A type with a set of type class constraints
68+ --
69+ | ConstrainedType [(Qualified ProperName, [Type])] Type
70+ -- |
71+ -- A skolem constant
72+ --
73+ | Skolem Int SkolemScope
74+ -- |
75+ -- An empty row
76+ --
77+ | REmpty
78+ -- |
79+ -- A non-empty row
80+ --
81+ | RCons String Type Type
82+ -- |
83+ -- A placeholder used in pretty printing
84+ --
85+ | PrettyPrintFunction Type Type
86+ -- |
87+ -- A placeholder used in pretty printing
88+ --
89+ | PrettyPrintArray Type deriving (Show, Eq, Data, Typeable)
90+
91+-- |
92+-- Type constructor for functions
93+--
94+tyFunction :: Type
95+tyFunction = TypeConstructor $ (Qualified $ Just $ ModuleName [ProperName "Prim"]) (ProperName "Function")
96+
97+-- |
98+-- Type constructor for strings
99+--
100+tyString :: Type
101+tyString = TypeConstructor $ (Qualified $ Just $ ModuleName [ProperName "Prim"]) (ProperName "String")
102+
103+-- |
104+-- Type constructor for numbers
105+--
106+tyNumber :: Type
107+tyNumber = TypeConstructor $ (Qualified $ Just $ ModuleName [ProperName "Prim"]) (ProperName "Number")
108+
109+-- |
110+-- Type constructor for booleans
111+--
112+tyBoolean :: Type
113+tyBoolean = TypeConstructor $ (Qualified $ Just $ ModuleName [ProperName "Prim"]) (ProperName "Boolean")
114+
115+-- |
116+-- Type constructor for arrays
117+--
118+tyArray :: Type
119+tyArray = TypeConstructor $ (Qualified $ Just $ ModuleName [ProperName "Prim"]) (ProperName "Array")
120+
121+-- |
122+-- Smart constructor for function types
123+--
124+function :: Type -> Type -> Type
125+function t1 = TypeApp (TypeApp tyFunction t1)
126+
127+-- |
128+-- Convert a row to a list of pairs of labels and types
129+--
130+rowToList :: Type -> ([(String, Type)], Type)
131+rowToList (RCons name ty row) = let (tys, rest) = rowToList row
132+ in ((name, ty):tys, rest)
133+rowToList r = ([], r)
134+
135+-- |
136+-- Convert a list of labels and types to a row
137+--
138+rowFromList :: ([(String, Type)], Type) -> Type
139+rowFromList ([], r) = r
140+rowFromList ((name, t):ts, r) = RCons name t (rowFromList (ts, r))
141+
142+-- |
143+-- Check whether a type is a monotype
144+--
145+isMonoType :: Type -> Bool
146+isMonoType ForAll{} = False
147+isMonoType _ = True
148+
149+-- |
150+-- Universally quantify a type
151+--
152+mkForAll :: [String] -> Type -> Type
153+mkForAll args ty = foldl (\t arg -> ForAll arg t Nothing) ty args
154+
155+-- |
156+-- The empty record type
157+--
158+unit :: Type
159+unit = Object REmpty
160+
161+-- |
162+-- Replace a type variable, taking into account variable shadowing
163+--
164+replaceTypeVars :: String -> Type -> Type -> Type
165+replaceTypeVars = replaceTypeVars' []
166+ where
167+ replaceTypeVars' bound name replacement = go bound
168+ where
169+ go :: [String] -> Type -> Type
170+ go bs (Object r) = Object $ go bs r
171+ go _ (TypeVar v) | v == name = replacement
172+ go bs (TypeApp t1 t2) = TypeApp (go bs t1) (go bs t2)
173+ go bs (SaturatedTypeSynonym name' ts) = SaturatedTypeSynonym name' $ map (go bs) ts
174+ go bs f@(ForAll v t sco) | v == name = f
175+ | v `elem` usedTypeVariables replacement =
176+ let v' = genName v (name : bs ++ usedTypeVariables replacement)
177+ t' = replaceTypeVars' bs v (TypeVar v') t
178+ in ForAll v' (go (v' : bs) t') sco
179+ | otherwise = ForAll v (go (v : bs) t) sco
180+ go bs (ConstrainedType cs t) = ConstrainedType (map (second $ map (go bs)) cs) (go bs t)
181+ go bs (RCons name' t r) = RCons name' (go bs t) (go bs r)
182+ go _ ty = ty
183+ genName orig inUse = try 0
184+ where
185+ try n | (orig ++ show n) `elem` inUse = try (n + 1)
186+ | otherwise = orig ++ show n
187+
188+-- |
189+-- Replace named type variables with types
190+--
191+replaceAllTypeVars :: [(String, Type)] -> Type -> Type
192+replaceAllTypeVars = foldl (\f (name, ty) -> replaceTypeVars name ty . f) id
193+
194+-- |
195+-- Collect all type variables appearing in a type
196+--
197+usedTypeVariables :: Type -> [String]
198+usedTypeVariables = nub . everything (++) (mkQ [] go)
199+ where
200+ go (TypeVar v) = [v]
201+ go _ = []
202+
203+-- |
204+-- Collect all free type variables appearing in a type
205+--
206+freeTypeVariables :: Type -> [String]
207+freeTypeVariables = nub . go []
208+ where
209+ go :: [String] -> Type -> [String]
210+ go bound (Object r) = go bound r
211+ go bound (TypeVar v) | v `notElem` bound = [v]
212+ go bound (TypeApp t1 t2) = go bound t1 ++ go bound t2
213+ go bound (SaturatedTypeSynonym _ ts) = concatMap (go bound) ts
214+ go bound (ForAll v t _) = go (v : bound) t
215+ go bound (ConstrainedType cs t) = concatMap (concatMap (go bound) . snd) cs ++ go bound t
216+ go bound (RCons _ t r) = go bound t ++ go bound r
217+ go _ _ = []
218+
219+-- |
220+-- Universally quantify over all type variables appearing free in a type
221+--
222+quantify :: Type -> Type
223+quantify ty = foldr (\arg t -> ForAll arg t Nothing) ty $ freeTypeVariables ty
src/Language/PureScript/Values.hsnew file+217
@@ -0,0 +1,217 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Language.PureScript.Values
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+-- Data types for values, statements, binders and do notation
13+--
14+-----------------------------------------------------------------------------
15+
16+{-# LANGUAGE DeriveDataTypeable #-}
17+
18+module Language.PureScript.Values where
19+
20+import Language.PureScript.Types
21+import Language.PureScript.Names
22+
23+import Data.Data
24+
25+-- |
26+-- A guard is just a boolean-valued expression that appears alongside a set of binders
27+--
28+type Guard = Value
29+
30+-- |
31+-- Data type for values
32+--
33+data Value
34+ -- |
35+ -- A numeric literal
36+ --
37+ = NumericLiteral (Either Integer Double)
38+ -- |
39+ -- A string literal
40+ --
41+ | StringLiteral String
42+ -- |
43+ -- A boolean literal
44+ --
45+ | BooleanLiteral Bool
46+ -- |
47+ -- Binary operator application. During the rebracketing phase of desugaring, this data constructor
48+ -- will be removed.
49+ --
50+ | BinaryNoParens (Qualified Ident) Value Value
51+ -- |
52+ -- Explicit parentheses. During the rebracketing phase of desugaring, this data constructor
53+ -- will be removed.
54+ --
55+ | Parens Value
56+ -- |
57+ -- An array literal
58+ --
59+ | ArrayLiteral [Value]
60+ -- |
61+ -- An object literal
62+ --
63+ | ObjectLiteral [(String, Value)]
64+ -- |
65+ -- An record property accessor expression
66+ --
67+ | Accessor String Value
68+ -- |
69+ -- Partial record update
70+ --
71+ | ObjectUpdate Value [(String, Value)]
72+ -- |
73+ -- Function introduction
74+ --
75+ | Abs (Either Ident Binder) Value
76+ -- |
77+ -- Function application
78+ --
79+ | App Value Value
80+ -- |
81+ -- Variable
82+ --
83+ | Var (Qualified Ident)
84+ -- |
85+ -- Conditional (if-then-else expression)
86+ --
87+ | IfThenElse Value Value Value
88+ -- |
89+ -- A data constructor
90+ --
91+ | Constructor (Qualified ProperName)
92+ -- |
93+ -- A case expression. During the case expansion phase of desugaring, top-level binders will get
94+ -- desugared into case expressions, hence the need for guards and multiple binders per branch here.
95+ --
96+ | Case [Value] [([Binder], Maybe Guard, Value)]
97+ -- |
98+ -- A value with a type annotation
99+ --
100+ | TypedValue Bool Value Type
101+ -- |
102+ -- A let binding
103+ --
104+ | Let Binder Value Value
105+ -- |
106+ -- A do-notation block
107+ --
108+ | Do [DoNotationElement]
109+ -- |
110+ -- A placeholder for a type class dictionary to be inserted later. At the end of type checking, these
111+ -- placeholders will be replaced with actual expressions representing type classes dictionaries which
112+ -- can be evaluated at runtime. The constructor arguments represent (in order): the type class name and
113+ -- instance type, and the type class dictionaries in scope.
114+ --
115+ | TypeClassDictionary (Qualified ProperName, [Type]) [TypeClassDictionaryInScope] deriving (Show, Data, Typeable)
116+
117+-- |
118+-- The type of a type class dictionary
119+--
120+data TypeClassDictionaryType
121+ -- |
122+ -- A regular type class dictionary
123+ --
124+ = TCDRegular
125+ -- |
126+ -- A type class dictionary which is an alias for an imported dictionary from another module
127+ --
128+ | TCDAlias (Qualified Ident) deriving (Show, Eq, Data, Typeable)
129+
130+-- |
131+-- Data representing a type class dictionary which is in scope
132+--
133+data TypeClassDictionaryInScope
134+ = TypeClassDictionaryInScope {
135+ -- |
136+ -- The identifier with which the dictionary can be accessed at runtime
137+ --
138+ tcdName :: Qualified Ident
139+ -- |
140+ -- The name of the type class to which this type class instance applies
141+ --
142+ , tcdClassName :: Qualified ProperName
143+ -- |
144+ -- The types to which this type class instance applies
145+ --
146+ , tcdInstanceTypes :: [Type]
147+ -- |
148+ -- Type class dependencies which must be satisfied to construct this dictionary
149+ --
150+ , tcdDependencies :: Maybe [(Qualified ProperName, [Type])]
151+ -- |
152+ -- The type of this dictionary
153+ --
154+ , tcdType :: TypeClassDictionaryType
155+ } deriving (Show, Data, Typeable)
156+
157+-- |
158+-- A statement in a do-notation block
159+--
160+data DoNotationElement
161+ -- |
162+ -- A monadic value without a binder
163+ --
164+ = DoNotationValue Value
165+ -- |
166+ -- A monadic value with a binder
167+ --
168+ | DoNotationBind Binder Value
169+ -- |
170+ -- A let statement, i.e. a pure value with a binder
171+ --
172+ | DoNotationLet Binder Value deriving (Show, Data, Typeable)
173+
174+-- |
175+-- Data type for binders
176+--
177+data Binder
178+ -- |
179+ -- Wildcard binder
180+ --
181+ = NullBinder
182+ -- |
183+ -- A binder which matches a boolean literal
184+ --
185+ | BooleanBinder Bool
186+ -- |
187+ -- A binder which matches a string literal
188+ --
189+ | StringBinder String
190+ -- |
191+ -- A binder which matches a numeric literal
192+ --
193+ | NumberBinder (Either Integer Double)
194+ -- |
195+ -- A binder which binds an identifier
196+ --
197+ | VarBinder Ident
198+ -- |
199+ -- A binder which matches a data constructor
200+ --
201+ | ConstructorBinder (Qualified ProperName) [Binder]
202+ -- |
203+ -- A binder which matches a record and binds its properties
204+ --
205+ | ObjectBinder [(String, Binder)]
206+ -- |
207+ -- A binder which matches an array and binds its elements
208+ --
209+ | ArrayBinder [Binder]
210+ -- |
211+ -- A binder which matches an array and binds its head and tail
212+ --
213+ | ConsBinder Binder Binder
214+ -- |
215+ -- A binder which binds its input to an identifier
216+ --
217+ | NamedBinder Ident Binder deriving (Show, Data, Typeable)
src/Tests.hsdeleted−141
@@ -1,141 +0,0 @@
1−module Tests (runTests) where
2−
3−import Prelude.Compat
4−import Data.List
5−import Control.Applicative
6−import Control.Monad
7−
8−import System.Process
9−import System.FilePath
10−import System.IO
11−import System.Directory
12−
13−-------------------------------------------------------------------------------
14−testsDir :: IO (FilePath, FilePath)
15−-------------------------------------------------------------------------------
16−testsDir = do
17− baseDir <- getCurrentDirectory
18− return (baseDir </> "purescript-tests", baseDir)
19−
20−-------------------------------------------------------------------------------
21−runTests :: IO ()
22−-------------------------------------------------------------------------------
23−runTests = do
24−
25− (outputDir, baseDir) <- testsDir
26−
27− outputDirExists <- doesDirectoryExist outputDir
28− when outputDirExists $ removeDirectoryRecursive outputDir
29− createDirectory outputDir
30−
31− let srcDir = outputDir </> "src"
32− createDirectory srcDir
33−
34− callProcess "git" ["clone", "--branch", "v0.13.8", "--depth", "1", "https://github.com/purescript/purescript.git"]
35− let passingDir = baseDir </> "purescript" </> "tests" </> "purs" </> "passing"
36− passingTestCases <- sort . filter (".purs" `isSuffixOf`) <$> getDirectoryContents passingDir
37−
38− setCurrentDirectory outputDir
39−
40− fetchPackages
41−
42− let tests = filter (`notElem` skipped) passingTestCases
43−
44− tmp <- getTemporaryDirectory
45− createDirectoryIfMissing False (tmp </> logpath)
46− outputFile <- openFile (tmp </> logpath </> logfile) WriteMode
47− hClose outputFile
48−
49− -- Run the tests
50− --
51− forM_ tests $ \inputFile -> do
52− --
53− -- Compile/build
54− --
55− putStrLn $ "Compiling test " ++ inputFile ++ " ..."
56− setCurrentDirectory outputDir
57− copyFile (passingDir </> inputFile) (srcDir </> inputFile)
58−
59− let testCaseDir = passingDir </> (takeWhile (/='.') inputFile)
60− testCaseDirExists <- doesDirectoryExist testCaseDir
61− when testCaseDirExists $ callProcess "cp" ["-R", testCaseDir, srcDir]
62−
63− callProcess "rm" ["-rf", "output"]
64− callProcess "rm" ["-rf", "Main"]
65− callProcess "spago" ["build"]
66− --
67− -- Run executable file
68− --
69− outputFile <- openFile (tmp </> logpath </> logfile) AppendMode
70− hPutStrLn outputFile ("\n" ++ inputFile ++ ":")
71− proc <- runProcess ("./" </> "Main") [] Nothing Nothing Nothing (Just outputFile) Nothing
72−
73− removeFile (srcDir </> inputFile)
74− when testCaseDirExists $ callProcess "rm" ["-rf", srcDir </> (takeWhile (/='.') inputFile)]
75−
76− -- TODO: support failing test cases
77− --
78− -- let failing = baseDir </> "examples" </> "failing"
79− -- failingTestCases <- sort . filter (".purs" `isSuffixOf`) <$> getDirectoryContents failing
80− --
81−
82− setCurrentDirectory baseDir
83− putStrLn "PureScript tests finished"
84− putStrLn $ "Total tests available: " ++ show (length passingTestCases)
85− putStrLn $ "Tests run: " ++ show (length tests)
86− putStrLn $ "Tests skipped: " ++ show (length skipped)
87−
88−-------------------------------------------------------------------------------
89−packages :: [String]
90−-------------------------------------------------------------------------------
91−packages =
92− [ "arrays"
93− , "assert"
94− , "console"
95− , "control"
96− , "effect"
97− , "foldable-traversable"
98− , "functions"
99− , "generics-rep"
100− , "invariant"
101− , "newtype"
102− , "partial"
103− , "prelude"
104− , "proxy"
105− , "refs"
106− , "st"
107− , "type-equality"
108− , "typelevel-prelude"
109− ]
110−
111−-------------------------------------------------------------------------------
112−fetchPackages :: IO ()
113−-------------------------------------------------------------------------------
114−fetchPackages = do
115− callProcess "spago" ["init"]
116− callCommand "sed '$s/\\(}\\)/, backend = \"psgo\"\\1/' < spago.dhall | dhall format > spago.tmp"
117− callCommand "mv spago.tmp spago.dhall"
118−
119− mapM (callProcess "spago" . (\p -> ["install", p])) packages
120− return ()
121−
122−-------------------------------------------------------------------------------
123−skipped :: [String]
124−-------------------------------------------------------------------------------
125−skipped =
126− [ "2172.purs" -- foreign in Main needed (test manually)
127− , "EffFn.purs" -- foreign in Main needed (test manually)
128− , "FunWithFunDeps.purs" -- foreign in Main needed (test manually)
129− , "NumberLiterals.purs" -- unreliable float string comparison (test manually)
130− , "PolyLabels.purs" -- foreign in Main needed (test manually)
131− , "RowUnion.purs" -- foreign in Main needed (test manually)
132− , "ShadowedModuleName.purs" -- ?
133− , "StringEdgeCases.purs" -- javascript char encoding specific
134− , "StringEscapes.purs" -- Partially javascript-char-encoding-specific (test manually)
135− ]
136−
137−logpath :: FilePath
138−logpath = "purescript-output"
139−
140−logfile :: FilePath
141−logfile = "purescript-tests.out"
stack.nixdeleted−23
@@ -1,23 +0,0 @@
1−#
2−# You may need to manually run `unset STACK_IN_NIX_SHELL`
3−# (doesn't work from a `shellHook`; see: https://github.com/commercialhaskell/stack/issues/5000
4−#
5−#
6−# You may need to set LC_ALL when building, e.g.
7−# LC_ALL=en_US.iso88591 stack --nix build; see e.g. https://github.com/koalaman/shellcheck/issues/324
8−#
9−#
10−{ pkgs ?
11− import (builtins.fetchTarball {
12− name = "nixos-release-19.03";
13− url = https://github.com/nixos/nixpkgs/archive/34c7eb7545d155cc5b6f499b23a7cb1c96ab4d59.tar.gz;
14− sha256 = "11z6ajj108fy2q5g8y4higlcaqncrbjm3dnv17pvif6avagw4mcb";
15− }) {}
16−}:
17−
18−pkgs.haskell.lib.buildStackProject {
19− name = "default-stack-shell";
20− ghc = pkgs.haskell.compiler.ghc865;
21− buildInputs = with pkgs; [git git-lfs gmp ncurses zlib];
22− LANG = "en_US.UTF-8";
23−}
stack.yamldeleted−24
@@ -1,24 +0,0 @@
1−resolver: lts-13.26
2−
3−packages:
4−- .
5−
6−extra-deps:
7−- git: https://github.com/purescript/purescript
8− commit: 9cad73ed8ea7df3011032ddbd2f3de5a0c08629c
9−- happy-1.19.9
10−- language-javascript-0.7.0.0
11−- network-3.0.1.1
12−- these-1.0.1
13−- semialign-1
14−
15−nix:
16− enable: false
17− shell-file: stack.nix
18−
19−flags:
20− aeson-pretty:
21− lib-only: true
22− these:
23− assoc: false
24− quickcheck: false
support/ffi-loader.godeleted−30
@@ -1,30 +0,0 @@
1−package ffi_loader
2−
3−// Load PureScript standard library FFI packages. Comment out the ones you don't need for
4−// faster/smaller builds.
5−
6−import (
7− _ "github.com/purescript-native/go-ffi/purescript-arrays"
8− _ "github.com/purescript-native/go-ffi/purescript-assert"
9− _ "github.com/purescript-native/go-ffi/purescript-console"
10− _ "github.com/purescript-native/go-ffi/purescript-effect"
11− _ "github.com/purescript-native/go-ffi/purescript-enums"
12− _ "github.com/purescript-native/go-ffi/purescript-exceptions"
13− _ "github.com/purescript-native/go-ffi/purescript-foldable-traversable"
14− _ "github.com/purescript-native/go-ffi/purescript-functions"
15− _ "github.com/purescript-native/go-ffi/purescript-globals"
16− _ "github.com/purescript-native/go-ffi/purescript-integers"
17− _ "github.com/purescript-native/go-ffi/purescript-lazy"
18− _ "github.com/purescript-native/go-ffi/purescript-math"
19− _ "github.com/purescript-native/go-ffi/purescript-partial"
20− _ "github.com/purescript-native/go-ffi/purescript-prelude"
21− _ "github.com/purescript-native/go-ffi/purescript-random"
22− _ "github.com/purescript-native/go-ffi/purescript-refs"
23− _ "github.com/purescript-native/go-ffi/purescript-st"
24− _ "github.com/purescript-native/go-ffi/purescript-strings"
25− _ "github.com/purescript-native/go-ffi/purescript-unfoldable"
26−)
27−
28−// Add your own FFI packages here.
29−
30−import ()
support/go.mod.ffi-loaderdeleted−2
@@ -1,2 +0,0 @@
1−module $PROJECT/purescript-native/ffi-loader
2−
support/go.mod.outputdeleted−2
@@ -1,2 +0,0 @@
1−module $PROJECT/purescript-native/output
2−
support/go.mod.workingdeleted−1
@@ -1 +0,0 @@
1−module $PROJECT/example
test/Spec.hsdeleted−2
@@ -1,2 +0,0 @@
1−main :: IO ()
2−main = putStrLn "Test suite not yet implemented"
tests/Main.hsnew file+99
@@ -0,0 +1,99 @@
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 DoAndIfThenElse #-}
16+
17+module Main (main) where
18+
19+import qualified Language.PureScript as P
20+
21+import Data.List (isSuffixOf)
22+import Data.Traversable (traverse)
23+import Control.Monad
24+import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
25+import System.Exit
26+import System.Process
27+import System.FilePath (pathSeparator)
28+import System.Directory (getCurrentDirectory, getDirectoryContents, findExecutable)
29+import Text.Parsec (ParseError)
30+import qualified Paths_purescript as Paths
31+import qualified System.IO.UTF8 as U
32+
33+preludeFilename :: IO FilePath
34+preludeFilename = Paths.getDataFileName "prelude/prelude.purs"
35+
36+readInput :: [FilePath] -> IO (Either ParseError [P.Module])
37+readInput inputFiles = fmap (fmap concat . sequence) $ forM inputFiles $ \inputFile -> do
38+ text <- U.readFile inputFile
39+ return $ P.runIndentParser inputFile P.parseModules text
40+
41+compile :: P.Options -> [FilePath] -> IO (Either String String)
42+compile opts inputFiles = do
43+ modules <- readInput inputFiles
44+ case modules of
45+ Left parseError ->
46+ return (Left $ show parseError)
47+ Right ms ->
48+ case P.compile opts ms of
49+ Left typeError ->
50+ return (Left typeError)
51+ Right (js, _, _) ->
52+ return (Right js)
53+
54+assert :: P.Options -> [FilePath] -> (Either String String -> IO (Maybe String)) -> IO ()
55+assert opts inputFiles f = do
56+ e <- compile opts inputFiles
57+ maybeErr <- f e
58+ case maybeErr of
59+ Just err -> putStrLn err >> exitFailure
60+ Nothing -> return ()
61+
62+assertCompiles :: FilePath -> IO ()
63+assertCompiles inputFile = do
64+ putStrLn $ "assert " ++ inputFile ++ " compiles successfully"
65+ prelude <- preludeFilename
66+ assert (P.defaultOptions { P.optionsMain = Just "Main", P.optionsNoOptimizations = True, P.optionsModules = ["Main"] }) [prelude, inputFile] $ either (return . Just) $ \js -> do
67+ process <- findNodeProcess
68+ result <- traverse (\node -> readProcessWithExitCode node [] js) process
69+ case result of
70+ Just (ExitSuccess, out, _) -> putStrLn out >> return Nothing
71+ Just (ExitFailure _, _, err) -> return $ Just err
72+ Nothing -> return $ Just "Couldn't find node.js executable"
73+
74+findNodeProcess :: IO (Maybe String)
75+findNodeProcess = runMaybeT . msum $ map (MaybeT . findExecutable) names
76+ where names = ["nodejs", "node"]
77+
78+assertDoesNotCompile :: FilePath -> IO ()
79+assertDoesNotCompile inputFile = do
80+ putStrLn $ "assert " ++ inputFile ++ " does not compile"
81+ assert P.defaultOptions [inputFile] $ \e ->
82+ case e of
83+ Left _ -> return Nothing
84+ Right _ -> return $ Just "Should not have compiled"
85+
86+main :: IO ()
87+main = do
88+ cd <- getCurrentDirectory
89+ putStrLn cd
90+ let examples = cd ++ pathSeparator : "examples"
91+ let passing = examples ++ pathSeparator : "passing"
92+ passingTestCases <- getDirectoryContents passing
93+ forM_ passingTestCases $ \inputFile -> when (".purs" `isSuffixOf` inputFile) $
94+ assertCompiles (passing ++ pathSeparator : inputFile)
95+ let failing = examples ++ pathSeparator : "failing"
96+ failingTestCases <- getDirectoryContents failing
97+ forM_ failingTestCases $ \inputFile -> when (".purs" `isSuffixOf` inputFile) $
98+ assertDoesNotCompile (failing ++ pathSeparator : inputFile)
99+ exitSuccess