git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
142 files changed+2716−7411
since splitsnapshots
unifiedsplit
.gitignore+15 .travis.yml−3 CONTRIBUTING.md−14 ChangeLog.md+3 LICENSE+26−16 README-go.md+48 README.md+28−835 Setup.hs+2 Setup.lhs−6 app/Main.hs+250 default.nix+23 examples/.gitignore−1 examples/failing/Arrays.purs−3 examples/failing/Do.purs−10 examples/failing/Import.purs−3 examples/failing/KindError.purs−3 examples/failing/LocalVars.purs−6 examples/failing/PatternScope.purs−10 examples/failing/Rank2Types.purs−5 examples/failing/ReadShow.purs−7 examples/failing/SkolemEscape.purs−5 examples/failing/TypeClasses.purs−7 examples/failing/TypeError.purs−3 examples/passing/Arrays.purs−21 examples/passing/Assign.purs−9 examples/passing/Auto.purs−11 examples/passing/Church.purs−14 examples/passing/Conditional.purs−7 examples/passing/Cons.purs−9 examples/passing/Console.purs−25 examples/passing/DataImport.purs−12 examples/passing/Do.purs−55 examples/passing/Dollar.purs−12 examples/passing/Eff.purs−62 examples/passing/ExternData.purs−15 examples/passing/ExternRaw.purs−13 examples/passing/FFI.purs−12 examples/passing/Functions.purs−13 examples/passing/Guards.purs−10 examples/passing/IfThenElse.purs−36 examples/passing/Import.purs−12 examples/passing/List.purs−21 examples/passing/Match.purs−5 examples/passing/Maybe.purs−11 examples/passing/Module.purs−20 examples/passing/Monad.purs−28 examples/passing/MutRec.purs−15 examples/passing/NamedPatterns.purs−5 examples/passing/Nested.purs−5 examples/passing/ObjectUpdate.purs−16 examples/passing/Objects.purs−14 examples/passing/Operators.purs−44 examples/passing/OptimizerBug.purs−5 examples/passing/Patterns.purs−25 examples/passing/Person.purs−9 examples/passing/Rank2Data.purs−25 examples/passing/Rank2Types.purs−19 examples/passing/Recursion.purs−6 examples/passing/TailCall.purs−10 examples/passing/TopLevelCase.purs−14 examples/passing/TypeClasses.purs−38 examples/passing/TypeDecl.purs−16 examples/passing/TypeSynonyms.purs−33 examples/passing/iota.purs−7 examples/passing/s.purs−3 examples/shelltest/Console.js−19 examples/shelltest/List.js−7 examples/shelltest/Maybe.js−5 examples/shelltest/runAll.test−16 examples/shelltest/runMain.js−1 libraries/.gitignore−1 libraries/jquery/README.md−7 libraries/jquery/jquery.purs−30 libraries/jquery/tests/jquery.purs−11 libraries/prelude/Makefile−3 libraries/prelude/prelude.js−42 libraries/prelude/prelude.purs−329 libraries/prelude/tests/Eff.purs−41 package.yaml+86 psgo.cabal+145 purescript.cabal−84 release.md−86 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−24 src/Language/PureScript.hs−46 src/Language/PureScript/CodeGen.hs−19 src/Language/PureScript/CodeGen/Externs.hs−47 src/Language/PureScript/CodeGen/JS.hs−227 src/Language/PureScript/CodeGen/JS/AST.hs−56 src/Language/PureScript/CodeGen/Monad.hs−32 src/Language/PureScript/CodeGen/Optimize.hs−232 src/Language/PureScript/Declarations.hs−48 src/Language/PureScript/Kinds.hs−27 src/Language/PureScript/Names.hs−45 src/Language/PureScript/Options.hs−25 src/Language/PureScript/Parser.hs−22 src/Language/PureScript/Parser/Common.hs−256 src/Language/PureScript/Parser/Declarations.hs−145 src/Language/PureScript/Parser/JS.hs−169 src/Language/PureScript/Parser/Kinds.hs−42 src/Language/PureScript/Parser/State.hs−22 src/Language/PureScript/Parser/Types.hs−119 src/Language/PureScript/Parser/Values.hs−298 src/Language/PureScript/Pretty.hs−23 src/Language/PureScript/Pretty/Common.hs−79 src/Language/PureScript/Pretty/JS.hs−239 src/Language/PureScript/Pretty/Kinds.hs−54 src/Language/PureScript/Pretty/Types.hs−91 src/Language/PureScript/Pretty/Values.hs−221 src/Language/PureScript/Scope.hs−56 src/Language/PureScript/Sugar.hs−34 src/Language/PureScript/Sugar/BindingGroups.hs−98 src/Language/PureScript/Sugar/CaseDeclarations.hs−67 src/Language/PureScript/Sugar/DoNotation.hs−52 src/Language/PureScript/Sugar/Operators.hs−132 src/Language/PureScript/Sugar/TypeClasses.hs−133 src/Language/PureScript/Sugar/TypeDeclarations.hs−35 src/Language/PureScript/TypeChecker.hs−216 src/Language/PureScript/TypeChecker/Kinds.hs−144 src/Language/PureScript/TypeChecker/Monad.hs−235 src/Language/PureScript/TypeChecker/Synonyms.hs−49 src/Language/PureScript/TypeChecker/Types.hs−794 src/Language/PureScript/Types.hs−77 src/Language/PureScript/Unknown.hs−24 src/Language/PureScript/Values.hs−109 src/Main.hs−116 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−71
.gitignore+15
@@ -1,8 +1,23 @@
11dist
22cabal-dev
3+.cabal-sandbox
4+cabal.sandbox.config
35*.o
46*.hi
57*.chi
68*.chs.h
79*.lksh*
810.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.ymldeleted−3
@@ -1,3 +0,0 @@
1−language: haskell
2−notifications:
3− email: false
CONTRIBUTING.mddeleted−14
@@ -1,14 +0,0 @@
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−- Run `cabal test`
7−- Consider adding a full test with Javascript to `examples/shelltest`
8−- Please run `hlint`.
9−
10−If you would like to contribute, please consider the issues in the current milestone first.
11−
12−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.
13−
14−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.mdnew file+3
@@ -0,0 +1,3 @@
1+# Changelog for pscpp
2+
3+## Unreleased changes
LICENSE+26−16
@@ -1,20 +1,30 @@
1−The MIT License (MIT)
1+Copyright Andy Arvanitis (c) 2018
22
3−Copyright (c) 2013 Phil Freeman
3+All rights reserved.
44
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:
5+Redistribution and use in source and binary forms, with or without
6+modification, are permitted provided that the following conditions are met:
117
12−The above copyright notice and this permission notice shall be included in all
13−copies or substantial portions of the Software.
8+ * Redistributions of source code must retain the above copyright
9+ notice, this list of conditions and the following disclaimer.
1410
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.
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.
README-go.mdnew file+48
@@ -0,0 +1,48 @@
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+28−835
@@ -1,848 +1,41 @@
1−purescript
2−==========
1+[![PureScript](https://raw.githubusercontent.com/purescript/purescript/master/logo.png)](http://purescript.org)
32
4−[![Build Status](https://secure.travis-ci.org/paf31/purescript.png?branch=master)](http://travis-ci.org/paf31/purescript)
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.
54
6−A small strongly, statically typed compile-to-JS language with basic extensible records and type-safe blocks
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).
76
8−Bitcoin donations are gratefully accepted at 14ZhCym28WDuFhocP44tU1dBpCzjX1DvhF.
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`
920
10−## Current Features
1121
12−- Full Type Inference
13−- Higher Kinded Polymorphism
14−- Support for basic Javascript types
15−- Extensible records
16−- Type-safe blocks with for/while/assignment etc.
17−- Functions with multiple arguments
18−- Pattern matching
19−- Simple FFI
20−- Modules
21−- Rank N Types
22−- Do Notation
23−- Optional tail-call elimination
22+#### Requirements for building `pscpp` and `psgo`
2423
25−## Try It!
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/))
2625
27−Try PureScript in the browser [here](http://tryps.functorial.com/).
26+#### Requirements for using PureScript + purescript-native
2827
29−## License
28+* A recent version (0.13+) of [purescript](https://github.com/purescript/purescript/releases).
3029
31−See the `LICENSE` file
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.
3234
33−## Contributing
3435
35−Contributions are always encouraged! Please see `CONTRIBUTING.md` for guidelines.
36−
37−Join the discussion on FreeNode at [irc://irc.freenode.net#purescript](irc://irc.freenode.net#purescript).
38−
39−## Installation
40−
41−Install the Haskell Plaform, then `cabal install`
42−
43−## Usage
44−
45−The `psc` executable takes a list of PureScript source files as arguments and by default writes out its errors or output to the console.
46−
47−The following options are supported:
48−
49− -s --stdin
50− Read input from standard input instead of from files
51−
52− -o --output
53− Write the generated Javascript to the specified file
54−
55− -e --foreign imports
56− Write a list of foreign imports declarations to the specified file in addition to generating Javascript output
57−
58− --runtime-type-checks
59− Generate simple runtime type checks for function arguments with simple types.
60−
61− --tco
62− Perform tail-call elimination on the generated Javascript.
63−
64− --no-prelude
65− Do not include the Prelude in the generated Javascript.
66−
67− --magic-do
68− Overload the `do` keyword to inline calls to `bind` for the `Eff` monad, to generate more efficient code.
69−
70− --run-main
71− Generate a call to `Main.main` after all other generated Javascript.
72−
73−## Motivation
74−
75−I was looking for a simple functional language which would compile to JavaScript and have the following characteristics:
76−
77−- Generate simple readable Javascript
78−- Provide the ability to compile to tight loops if necessary
79−- Reasonable type system
80−- Ideally, written in a programming language I would enjoy working in
81−- Provides a simple interface to existing Javascript code
82−
83−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.
84−
85−PureScript is *not* designed to be a general-purpose programming language. The primary use case is as a generator for purely-functional core libraries, with the main application code written in another language.
86−
87−PureScript can also be seen as a trade-off between a theoretically ideal language and one which generates reasonably high performance code.
88−
89−## Hello, PureScript!
90−
91−As an introductory example, here is the usual "Hello World" written in PureScript:
92−
93−```haskell
94−module Main where
95−
96−foreign import console :: { log :: String -> {} }
97−
98−main = \ -> console.log "Hello, World!"
99−```
100−
101−which compiles to the following Javascript:
102−
103−```javascript
104−var Main;
105−(function (Main) {
106− function main() {
107− return console.log("Hello, World!");
108− };
109− Main.main = main;
110−})(Main = Main || {});
111−```
112−
113−## Another Example
114−
115−The following code defines a `Person` data type and a function to generate a string representation for a `Person`:
116−
117−```haskell
118−data Person = Person { name :: String, age :: Number }
119−
120−foreign import numberToString :: Number -> String
121−
122−showPerson :: Person -> String
123−showPerson (Person o) = o.name ++ ", aged " ++ numberToString(o.age)
124−```
125−
126−Line by line, this reads as follows:
127−
128−- `Person` is a data type with one constructor, also called `Person`
129− - The `Person` constructor takes an object with two properties, `name` which is a `String`, and `age` which is a `Number`
130−- The `numberToString` function is written in Javascript, and converts a `Number` to its `String` representation
131−- The `showPerson` function takes a `Person` and returns a `String`
132−- `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.
133−
134−The generated Javascript looks like this:
135−
136−```javascript
137−var Person = function (value) {
138− return { ctor: 'Person', value: value };
139−};
140−
141−function showPerson(_1) {
142− if (_1.ctor === "Person") {
143− return _1.value.name + ", aged " + numberToString(_1.value.age);
144− };
145− throw "Failed pattern match";
146−};
147−
148−```
149−
150−## Type System
151−
152−The type system defines the following types:
153−
154−- Primitive Types
155− - Number
156− - String
157− - Boolean
158−- Arrays
159− - E.g. `[String]`, `[[Number]]`
160−- Records
161− - E.g. `{ foo :: String, bar :: Number }`
162−- Tagged Unions
163− - E.g. `data Foo a = Foo | Bar String`
164−- Functions
165− - E.g. `Number -> String`
166− - E.g. `(Number, Number) -> Number`
167− - Functions can have zero or more arguments
168−- Polymorphic types
169− - E.g. `forall a. a -> a`
170−
171−## Primitive Types
172−
173−The three primitive types `String`, `Number` and `Boolean` correspond to their Javascript equivalents at runtime.
174−
175−PureScript supports the same binary and unary operations on primitive types as Javascript, with the following exceptions:
176−
177−- String concatenation is denoted `++` to differentiate it from numeric addition, `+`
178−- PureScript's `==` and `!=` correspond to Javascript's strong equality tests `===` and `!==`
179−
180−Examples:
181−
182−```haskell
183−num = 1 + 2 * 3
184−str = "Hello, " ++ "World!"
185−bool = 1 > 2 || true
186−```
187−
188−## Arrays
189−
190−PureScript arrays correspond to Javascript arrays at runtime, but all elements must have the same type.
191−
192−Array literals look like Javascript array literals: `[1, 2, 3]`
193−
194−Array elements can be read using array index notation `arr !! index`
195−
196−## Records
197−
198−PureScript records correspond to Javascript objects.
199−
200−Record literals look like Javascript object literals: `{ foo: "Foo" }`
201−
202−Properties can be read by using dot notation: `o.foo`
203−
204−## Tagged Unions
205−
206−Tagged unions consist of one or more constructors, each of which takes zero or one arguments.
207−
208−Tagged unions can only be created using their constructors, and deconstructed through pattern matching (see later).
209−
210−For example:
211−
212−```haskell
213−data Foo a = Foo | Bar String
214−
215−runFoo Foo = "It's a Foo"
216−runFoo (Bar s) = "It's a Bar. The string is " ++ s
217−
218−test = runFoo Foo ++ runFoo (Bar "Test")
219−```
220−
221−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.
222−
223−`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.
224−
225−## Functions
226−
227−Functions in PureScript can have zero or more arguments in general, just like in Javascript.
228−
229−Functions are introduced by using a backslash followed by a list of argument names:
230−
231−```haskell
232−test1 = \a b -> a + b
233−```
234−
235−which would correspond to the Javascript
236−
237−```javascript
238−function test1(a) {
239− return function (b) {
240− return a + b;
241− }
242−}
243−```
244−
245−Multiple argument functions can be introduced by wrapping the arguments in parentheses, and separating them with commas:
246−
247−```haskell
248−test1 = \(a, b) -> a + b
249−```
250−
251−which generates
252−
253−```javascript
254−function test1(a, b) {
255− return a + b;
256−}
257−```
258−
259−In the case of a function with no arguments, the parentheses may be omitted, as follows:
260−
261−```haskell
262−test2 = \ -> 100
263−```
264−
265−which would correspond to the Javascript `function test2() { return 100; }`
266−
267−Multiple-argument and single-argument syntax can be mixed, as follows:
268−
269−```haskell
270−test3 = \a (b, c) d -> a + b + c + d
271−```
272−
273−which generates
274−
275−```javascript
276−function test3(a) {
277− return function (b, c) {
278− return function (d) {
279− return a + b + c + d;
280− }
281− }
282−}
283−```
284−
285−Functions are applied by providing their arguments inside parentheses:
286−
287−```haskell
288−test1(1, 2, 3)
289−test2()
290−```
291−
292−A special case is made in the case of functions with one argument. These functions can be applied without parentheses, and function application associates to the left:
293−
294−```haskell
295−-- has type Number -> Number -> Number -> Number
296−addThree = \a b c -> a + b + c
297−
298−-- has type Number -> Number -> Number
299−addThree 1
300−
301−-- has type Number -> Number
302−addThree 1 2
303−
304−-- has type Number
305−addThree 1 2 3
306−```
307−
308−## Polymorphic Types
309−
310−Expressions defined at the top level may have polymorphic types.
311−
312−Here is an example:
313−
314−```haskell
315−identity x = x
316−```
317−
318−`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.
319−
320−A type annotation can also be provided:
321−
322−```haskell
323−identity :: forall a. a -> a
324−identity x = x
325−```
326−
327−Functions may also be polymorphic in row types or type variables with other kinds (see "Kind System"):
328−
329−```haskell
330−addProps o = o.foo + o.bar
331−```
332−
333−Here, `addProps` is inferred to have type `forall r. { foo :: Number, bar :: Number | r } -> Number`. That is, it can take any type which has properties `Foo` and `Bar`, and *any other record properties*.
334−
335−So, the following compiles:
336−
337−```haskell
338−addProps { foo: 1, bar: 2, baz: 3 }
339−```
340−
341−but the following does not:
342−
343−```haskell
344−addProps { foo: 1 }
345−```
346−
347−since the `bar` property is missing.
348−
349−Again, a type annotation can be provided if necessary.
350−
351−## Rank N Types
352−
353−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.
354−
355−In most cases, a type annotation is necessary when using this feature.
356−
357−As an example, we can pass a polymorphic function as an argument to another function:
358−
359−```haskell
360−poly :: (forall a. a -> a) -> Boolean
361−poly f = (f 0 < 1) == f true
362−```
363−
364−Notice that the polymorphic function's type argument is instantiated to both `Number` and `Boolean`.
365−
366−An argument to `poly` must indeed be polymorphic. For example, the following fails:
367−
368−```haskell
369−test = poly (\n -> n + 1)
370−```
371−
372−since the skolemized type variable `a` does not unify with `Number`.
373−
374−## Type Inference
375−
376−All types can be inferred, but annotations can optionally be provided.
377−
378−## Kind System
379−
380−There are two primitive kinds, the kind `*` of types and the kind `!` of effects.
381−
382−For each kind `k` there is also a kind `# k` of rows, with types of kind `k`. 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.
383−
384−Higher kinded types are also supported. That is, a type variable can refer to not only a type or a row, but a type constructor, or row constructor etc.
385−
386−## Whitespace
387−
388−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.
389−
390−That is, the following is valid:
391−
392−```haskell
393−foo = bar(x) +
394− baz(x)
395−```
396−
397−But this is not:
398−
399−```haskell
400−foo = bar(x) +
401−baz(x)
402−```
403−
404−## Blocks
405−
406−Blocks are collections of statements wrapped in braces `{ ... }`. Blocks must return a value of the same type on every branch of execution.
407−
408−The following types of statement are supported:
409−
410−- Variable introduction
411−- Variable assignment
412−- For loops
413−- For-each loops
414−- While loops
415−- If-Then-Else statements
416−
417−Here is an example of a power function defined using a block:
418−
419−```haskell
420−pow n p = {
421− var m = n;
422− for (i <- 0 until p) {
423− m = m * n;
424− }
425− return m;
426− }
427−```
428−
429−Blocks enable local mutation of their variables, but mutation is not allowed in general. The type system prevents mutable variables from escaping their scope.
430−
431−That is, while the example above is valid, the following does not compile:
432−
433−```haskell
434−incr n = {
435− n = n + 1;
436− return n;
437− }
438−```
439−
440−The variable `n` is not mutable, and so the assignment in the first line of the `do` block is not allowed.
441−
442−This function can be rewritten as follows:
443−
444−```haskell
445−incr n = {
446− var m = n;
447− m = m + 1;
448− return m;
449− }
450−```
451−
452−## For Loops
453−
454−For loops look like this:
455−
456−```haskell
457−total = {
458− var n = 0;
459− for (i <- 0 until 10) {
460− n = n + i;
461− }
462− return n;
463− }
464−```
465−
466−The bounds `0` and `10` are inclusive and exclusive respectively.
467−
468−## For-Each Loops
469−
470−For each loops loop over the elements in an array using the `Object.forEach` method. A polyfill may be required for some browsers:
471−
472−```haskell
473−total arr = {
474− var n = 0;
475− foreach (i in arr) {
476− n = n + i;
477− }
478− return n;
479− }
480−```
481−
482−## While Loops
483−
484−The syntax of a while loop is similar to a foreach loop:
485−
486−```haskell
487−log2 n = {
488− var count = 0;
489− var m = n;
490− while (m > 1) {
491− m = m / 2;
492− count = count + 1;
493− }
494− return count;
495− }
496−```
497−
498−## If-Then-Else Statements
499−
500−Else branches are optional, and may contain further `if` statements, just as in Javascript:
501−
502−```haskell
503−collatz n = {
504− var count = 0;
505− var m = n;
506− while (m > 1) {
507− if (m % 2 == 0) {
508− m = m / 2;
509− } else {
510− m = m * 3 + 1;
511− }
512− count = count + 1;
513− }
514− return count;
515− }
516−```
517−
518−## If-Then-Else Expressions
519−
520−The `if`, `then` and `else` keywords can also be used to create conditional expressions. In this case, the `else` block is always required.
521−
522−For example,
523−
524−```haskell
525−conditional = if 2 > 1 then "ok" else "oops"
526−```
527−
528−## Do Notation
529−
530−The `do` keyword introduces simple syntactic sugar for monadic expressions.
531−
532−Here is an example, using the maybe monad:
533−
534−```haskell
535−data Maybe a = Nothing | Just a
536−
537−bindMaybe Nothing _ = Nothing
538−bindMaybe (Just a) f = f a
539−
540−maybe = { ret: Just, bind: bindMaybe }
541−
542−isEven n | n % 2 == 0 = Just {}
543−isEven _ = Nothing
544−
545−evenSum a b = maybe do
546− n <- a
547− m <- b
548− let sum = n + m
549− isEven sum
550− return sum
551−```
552−
553−`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`.
554−
555−This example illustrates the following aspects of `do` notation:
556−
557−- The `do` keyword is preceded by a value `m` which is a record. The record must contain fields `ret` and `bind` which determine the monad which will be used in the computation.
558−- Statements can have the following form:
559− - `a <- x` which desugars to `m.bind x (\a -> ...)`
560− - `let a = x` which desugars to `(\a -> ...)(x)`
561− - `return a` which desugars to `m.ret a`
562− - `x` which desugars to `m.bind x (\_ -> ...)` or just `x` if this is the last statement.
563−
564−Not illustrated here, but equally valid is the use of a binder on the left hand side of `<-` or `=`. For example:
565−
566−```haskell
567−test arr = maybe do
568− (x:y:_) <- arr
569− return x + y
570−```
571−
572−A pattern match failure will generate a runtime exception, just as in the case of a regular `case` statement.
573−
574−## Pattern Matching
575−
576−Pattern matching deconstructs a value to bring zero or more expressions into scope. Pattern matches are introduced with the `case` keyword.
577−
578−Pattern matches have the following general form
579−
580−```haskell
581−case value of
582− pattern -> result
583− -- ...
584− pattern -> result
585−```
586−
587−Pattern matching can also be used in the declaration of functions, as we have already seen:
588−
589−```haskell
590−fn pattern_1 ... pattern_n = result
591−```
592−
593−Any of the above types of pattern are also valid when introducing functions. In addition, patterns can also be grouped in parentheses to introduce multiple-arugument functions. For example,
594−
595−```haskell
596−example x (y, z) w = x * y + z * w
597−```
598−
599−The following pattern types are supported:
600−
601−- Wildcard pattern
602−- Literal patterns
603−- Variable pattern
604−- Array patterns
605−- Cons patterns
606−- Record patterns
607−- Named patterns
608−- Guards
609−
610−Patterns need not be exhaustive. A pattern match failed exception will be thrown at runtime if no pattern matches the input.
611−
612−## Wildcard Patterns
613−
614−The wilcard `_` matches any input and brings nothing into scope:
615−
616−```haskell
617−case x of
618− _ -> 0
619−```
620−
621−## Literal Patterns
622−
623−Literal patterns are provided to match on primitives:
624−
625−```haskell
626−case booleanValue of
627− true -> 0
628− false -> 1
629−
630−case stringValue of
631− "Foo" -> 0
632− _ -> 1
633−
634−case numericValue of
635− 0 -> 0
636− _ -> 1
637−```
638−
639−## Variable Pattern
640−
641−A variable pattern matches any input and binds that input to its name:
642−
643−```haskell
644−case foo(x) of
645− result -> bar(result)
646−```
647−
648−## Array Patterns
649−
650−Array patterns match an input which is an array, and bring its elements into scope.
651−
652−For example:
653−
654−```haskell
655−f = \arr -> case arr of
656− [x] -> x
657− [x, y] -> x * y + f xs
658− _ -> 0
659−```
660−
661−Here, the first pattern only matches arrays of length one, and brings the first element of the array into scope.
662−
663−The second pattern matches arrays with two elements, and brings the first and second elements into scope.
664−
665−## Cons Patterns
666−
667−The head and tail of a non-empty array can be matched by using a cons pattern:
668−
669−```haskell
670−add = \arr -> case arr of
671− [] -> 0
672− x : xs -> x + add xs
673−```
674−
675−`:` associates to the right:
676−
677−```haskell
678−addPairs = \arr -> case arr of
679− x : y : xs -> x * y + addPairs xs
680− _ -> 0
681−```
682−
683−## Record Patterns
684−
685−Record patterns match an input which is a record, and bring its properties into scope.
686−
687−```haskell
688−f = \o -> case o of
689− { foo = "Foo" } -> o.bar
690− _ -> 0
691−```
692−
693−## Nested Patterns
694−
695−The patterns above can be combined to create larger patterns.
696−
697−For example:
698−
699−```haskell
700−f = \o -> case o of
701− { arr = x : _, take = "car" } -> x
702− { arr = _ : x : _, take = "cadr" } -> x
703− _ -> 0
704−```
705−
706−## Named Patterns
707−
708−Named patterns bring additional names into scope when using nested patterns. Any pattern can be named by using the `@` symbol:
709−
710−```haskell
711−f = \arr -> case arr of
712− a@(_ : _ : _) -> true
713− a -> false
714−```
715−
716−Here, in the first pattern, any array with two or more elements will be matched and bound to the variable `a`.
717−
718−## Guards
719−
720−Guards are used to impose additional constraints inside a pattern using boolean-valued expressions, and are introduced with a pipe after the pattern:
721−
722−```haskell
723−evens = \arr -> case arr of
724− [] -> 0
725− x : xs | x % 2 == 0 -> 1 + evens xs
726− _ : xs -> evens xs
727−```
728−
729−When defining a function, guards appear after all patterns:
730−
731−```haskell
732−greater x y | x > y = true
733−greater _ _ = false
734−```
735−
736−## Type Synonyms
737−
738−For convenience, it is possible to declare a synonym for a type using the `type` keyword. Type synonyms can include type arguments.
739−
740−For example:
741−
742−```haskell
743−type Foo = { foo :: Number, bar Number }
744−
745−addFoo :: Foo -> Number
746−addFoo = \o -> o.foo + o.bar
747−```
748−## Record Updates
749−
750−Properties on records can be updated using the following syntax: `o { key = value, ..., key = value }`
751−
752−For example, the following function increments the `foo` property on its argument:
753−
754−```haskell
755−incr = \o -> o { foo = o.foo + 1 }
756−```
757−
758−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
759−
760−```haskell
761−Object.prototype.extend = function(o, p) {
762− return $.extend({}, o, p);
763−};
764−```
765−
766−## Operators
767−
768−In addition to the standard operators, user-defined infix operators can be created by enclosing names in parentheses:
769−
770−E.g. to create a synonym for string concatenation:
771−
772−```haskell
773−(<>) = \s1 s2 -> s1 ++ s2
774−
775−greeting = "Hello" <> "World!"
776−```
777−
778−Regular functions can be used as operators by enclosing their names in backticks:
779−
780−```haskell
781−foo = \x y -> x * y + y
782−
783−test = 10 `foo` 20
784−```
785−
786−Fixity declarations can associate a precedence level, which is a natural number, to a user-defined operator, and specify which way it associates:
787−
788−```haskell
789−infixl 5 <>
790−infixr 7 %%
791−```
792−
793−## Modules
794−
795−Modules are introduced using the `module` keyword. All code must be placed in a module.
796−
797−Introduce a module as follows, with a list of declarations:
798−
799−```haskell
800−module A where
801−
802−id x = x
803−```
804−
805−Names may be qualified by using a dot:
806−
807−```
808−foo = A.foo
809−bar = A.B.bar
810−```
811−
812−All the names in a module can be aliased using the `import` declaration:
813−
814−```haskell
815−import A
816−```
817−
818−You can also limit which names are going to be aliased:
819−
820−```haskell
821−import A.B (bar)
822−```
823−
824−## Foreign Function Interface
825−
826−The `foreign import` keyword declares a value which is defined in Javascript, and its type:
827−
828−```haskell
829−foreign import pow :: (Number, Number) -> Number
830−```
831−
832−To declare a new type with no constructors, use `foreign import data` and provide the kind:
833−
834−```haskell
835−foreign import data IO :: * -> *
836−
837−foreign import console :: {
838− log :: String -> IO {}
839−}
840−```
841−
842−To alias a name of a field defined on a Javascript type to a PureScript function, use `foreign import member`. For example, to define a function `length` which accesses the `length` member of an array:
843−
844−```haskell
845−foreign import member "length" length :: forall a. [a] -> Number
846−```
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)
84739
84840
41+---
Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
Setup.lhsdeleted−6
@@ -1,6 +0,0 @@
1−#!/usr/bin/runhaskell
2−> module Main where
3−> import Distribution.Simple
4−> main :: IO ()
5−> main = defaultMain
6−
app/Main.hsnew file+250
@@ -0,0 +1,250 @@
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.nixnew file+23
@@ -0,0 +1,23 @@
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+}
examples/.gitignoredeleted−1
@@ -1 +0,0 @@
1−shelltest/tests
examples/failing/Arrays.pursdeleted−3
@@ -1,3 +0,0 @@
1−module Arrays where
2−
3− test = \arr -> arr !! (0 !! 0)
examples/failing/Do.pursdeleted−10
@@ -1,10 +0,0 @@
1−module Do where
2−
3−id = { ret: \x -> x, bind: \x f -> f x }
4−
5−test1 = id do let x = 1
6−
7−test2 y = id do x <- y
8−
9−test3 = id do return 1
10− return 2
examples/failing/Import.pursdeleted−3
@@ -1,3 +0,0 @@
1−module Module where
2−
3− import UndefinedModule
examples/failing/KindError.pursdeleted−3
@@ -1,3 +0,0 @@
1−module KindError where
2−
3− data KindError f a = One f | Two f a
examples/failing/LocalVars.pursdeleted−6
@@ -1,6 +0,0 @@
1−module LocalVars where
2−
3− bad = \x -> {
4− x = x + 1;
5− return x;
6− }
examples/failing/PatternScope.pursdeleted−10
@@ -1,10 +0,0 @@
1−module PatternScope where
2−
3− -- Pattern scope doesn't leak
4− foobar = \x -> {
5− var y = case x of
6− z | z % 2 == 0 -> 1
7− _ -> 2;
8− return z;
9− }
10−
examples/failing/Rank2Types.pursdeleted−5
@@ -1,5 +0,0 @@
1−module Rank2Types where
2−
3− foreign import test :: (forall a. a -> a) -> Number
4−
5− test1 = test (\n -> n + 1)
examples/failing/ReadShow.pursdeleted−7
@@ -1,7 +0,0 @@
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/SkolemEscape.pursdeleted−5
@@ -1,5 +0,0 @@
1−module SkolemEscape where
2−
3− foreign import foo :: (forall a. a -> a) -> Number
4−
5− test = \x -> foo x
examples/failing/TypeClasses.pursdeleted−7
@@ -1,7 +0,0 @@
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/TypeError.pursdeleted−3
@@ -1,3 +0,0 @@
1−module TypeError where
2−
3− test = x ++ "A"
examples/passing/Arrays.pursdeleted−21
@@ -1,21 +0,0 @@
1−module Arrays where
2−
3−test1 = \arr -> arr !! 0 + arr !! 1
4−
5−test2 = \arr -> case arr of
6− [x, y] -> x + y
7− [x] -> x
8− [] -> 0
9− (x : y : _) -> x + y
10−
11−data Tree = One Number | Some [Tree]
12−
13−test3 = \(tree, sum) -> case tree of
14− One n -> n
15− Some (n1 : n2 : rest) -> test3(n1, sum) * 10 + test3(n2, sum) * 5 + sum(rest)
16−
17−test4 = \arr -> case arr of
18− [] -> 0
19− [_] -> 0
20− x : y : xs -> x * y + test4 xs
21−
examples/passing/Assign.pursdeleted−9
@@ -1,9 +0,0 @@
1−module Assign where
2−
3− sum = \n -> {
4− var x = 0;
5− for (i <- 0 until n) {
6− x = x + i;
7− }
8− return x;
9− }
examples/passing/Auto.pursdeleted−11
@@ -1,11 +0,0 @@
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)
examples/passing/Church.pursdeleted−14
@@ -1,14 +0,0 @@
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)
examples/passing/Conditional.pursdeleted−7
@@ -1,7 +0,0 @@
1−module Conditional where
2−
3− fns = \f -> if f true then f else \x -> x
4−
5− bin = \x -> if x && !x then x else x
6−
7− not = \x -> if x then false else true
examples/passing/Cons.pursdeleted−9
@@ -1,9 +0,0 @@
1−module Cons where
2−
3− infixr 6 :
4−
5− foreign import (:) :: forall a. a -> [a] -> [a]
6−
7− test1 = \xs -> 1 : xs
8−
9− test2 = 1 : 2 : 3 : []
examples/passing/Console.pursdeleted−25
@@ -1,25 +0,0 @@
1−module Console where
2−
3− foreign import data IO :: * -> *
4−
5− foreign import ret :: forall a. a -> IO a
6−
7− foreign import (>>=) :: forall a b. IO a -> (a -> IO b) -> IO b
8−
9− (*>) = \a -> \b -> a >>= \x -> b
10−
11− foreign import putStrLn :: String -> IO {}
12−
13− replicateM_ :: forall a. Number -> IO a -> IO {}
14− replicateM_ = \n -> \x ->
15− {
16− var io = ret {};
17− for (i <- 0 until n)
18− {
19− io = x *> io;
20− }
21− return io;
22− }
23−
24− main = replicateM_ 10 (putStrLn "Hello World!")
25−
examples/passing/DataImport.pursdeleted−12
@@ -1,12 +0,0 @@
1−module M1 where
2−
3−data Test = Test
4−
5−module M2 where
6−
7−import M1
8−
9−test :: Test -> M1.Test
10−test t = t
11−
12−testCtor = Test
examples/passing/Do.pursdeleted−55
@@ -1,55 +0,0 @@
1−module Do where
2−
3−data Maybe a = Nothing | Just a
4−
5−bindMaybe :: forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
6−bindMaybe Nothing _ = Nothing
7−bindMaybe (Just a) f = f a
8−
9−maybe = { ret: Just, bind: bindMaybe }
10−
11−test1 = maybe do Just "abc"
12−
13−test2 = maybe do return "xyz"
14−
15−test3 = maybe do
16− (x : _) <- Just [1, 2, 3]
17− (y : _) <- Just [4, 5, 6]
18− return x + y
19−
20−test4 = maybe do
21− Just 1
22− Nothing :: Maybe Number
23− return 2
24−
25−test5 mx my = maybe do
26− x <- mx
27− y <- my
28− return x + y
29−
30−test6 mx my mz = maybe do
31− x <- mx
32− y <- my
33− let sum = x + y
34− z <- mz
35− return z + sum
36−
37−test7 mx = maybe do let Just x = mx
38− return x
39−
40−test8 = maybe do return (maybe do return 1)
41−
42−(<$>) :: forall a b. (a -> b) -> Maybe a -> Maybe b
43−(<$>) f m = maybe do
44− a <- m
45− return f a
46−
47−(<*>) :: forall a b. (Maybe (a -> b)) -> Maybe a -> Maybe b
48−(<*>) f m = maybe do
49− g <- f
50− a <- m
51− return g a
52−
53−foo x y z = x + y + z
54−
55−test9 = foo <$> Just 1 <*> Just 2 <*> Just 3
examples/passing/Dollar.pursdeleted−12
@@ -1,12 +0,0 @@
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
examples/passing/Eff.pursdeleted−62
@@ -1,62 +0,0 @@
1−module Eff where
2−
3−-- Eff Monad
4−
5−foreign import data Eff :: # ! -> * -> *
6−
7−foreign import ret :: forall e a. a -> Eff e a
8−
9−foreign import (>>=) :: forall e a b. Eff e a -> (a -> Eff e b) -> Eff e b
10−
11−type Pure a = forall e. Eff e a
12−
13−foreign import runPure :: forall a. Pure a -> a
14−
15−eff = { ret: ret, bind: (>>=) }
16−
17−-- Errors
18−
19−foreign import data Error :: * -> !
20−
21−foreign import throwError :: forall e r. e -> Eff (err :: Error e | r) {}
22−
23−foreign import catchError :: forall e r a. (e -> Eff r a) -> Eff (err :: Error e | r) a -> Eff r a
24−
25−-- State
26−
27−foreign import data State :: * -> !
28−
29−foreign import get :: forall s r. Eff (state :: State s | r) s
30−
31−foreign import set :: forall s r. s -> Eff (state :: State s | r) {}
32−
33−foreign import runState :: forall s r a. s -> Eff (state :: State s | r) a -> Eff r { value :: a, state :: s }
34−
35−-- ST
36−
37−foreign import data ST :: * -> !
38−
39−foreign import data STRef :: * -> * -> *
40−
41−foreign import newSTRef :: forall a h r. a -> Eff (st :: ST h | r) (STRef h a)
42−
43−foreign import readSTRef :: forall a h r. STRef h a -> Eff (st :: ST h | r) a
44−
45−foreign import modifySTRef :: forall a h r. (a -> a) -> STRef h a -> Eff (st :: ST h | r) {}
46−
47−foreign import runST :: forall a r. (forall h. Eff (st :: ST h | r) a) -> Eff r a
48−
49−-- Tests
50−
51−test1 = runPure (runState 0 (catchError (\s -> ret 0)
52− (eff do
53− s <- get
54− throwError "Error!"
55− set (s + 1)
56− return s)))
57−
58−test2 = runPure (runST (eff do
59− ref <- newSTRef 0
60− modifySTRef (\n -> n + 1) ref
61− readSTRef ref))
62−
examples/passing/ExternData.pursdeleted−15
@@ -1,15 +0,0 @@
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 ret :: 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
examples/passing/ExternRaw.pursdeleted−13
@@ -1,13 +0,0 @@
1−module ExternRaw where
2−
3−foreign import first "function first(xs) { return xs[0]; }" :: forall a. [a] -> a
4−
5−foreign import cond "function cond(b, t, f) { return b ? t : f; }" :: forall a. (Boolean, a, a) -> a
6−
7−foreign import loop "function loop() { while (true) {} }" :: forall a. a
8−
9−foreign import concat "function concat(xs) { \
10− \ return function(ys) { \
11− \ return xs.concat(ys); \
12− \ };\
13− \}" :: forall a. [a] -> [a] -> [a]
examples/passing/FFI.pursdeleted−12
@@ -1,12 +0,0 @@
1−module FFI where
2−
3−foreign import foo :: String -> String
4−
5−bar :: String -> String
6−bar = \x -> foo (x ++ "bar")
7−
8−module FFIModuleTest where
9−
10−import FFI
11−
12−baz = foo "test"
examples/passing/Functions.pursdeleted−13
@@ -1,13 +0,0 @@
1−module Functions where
2−
3− test1 = \ -> 0
4−
5− test2 = \() -> 0
6−
7− test3 = \a (b, c) d -> a + b + c + d
8−
9− test4 = \(a) -> a
10−
11− test5 = \(%%) -> 1 %% 2
12−
13− test6 = \((+++), (***)) -> 1 +++ 2 *** 3
examples/passing/Guards.pursdeleted−10
@@ -1,10 +0,0 @@
1−module Guards where
2−
3− collatz = \x -> case x of
4− y | y % 2 == 0 -> y / 2
5− y -> y * 3 + 1
6−
7− -- Guards have access to current scope
8− collatz2 = \x y -> case x of
9− z | y > 0 -> z / 2
10− z -> z * 3 + 1
examples/passing/IfThenElse.pursdeleted−36
@@ -1,36 +0,0 @@
1−module IfThenElse where
2−
3− testIf =
4− {
5− var x = 0;
6− if (x == 0) {
7− x = x + 1;
8− }
9− return x;
10− }
11−
12− testIfElse =
13− {
14− var x = 0;
15− if (x == 0) {
16− x = x + 1;
17− } else {
18− x = x - 1;
19− }
20− return x;
21− }
22−
23− testIfElseIf = \x ->
24− {
25− var y = x;
26− while (y > 1) {
27− if (y % 3 == 0) {
28− y = y / 3;
29− } else if (y % 3 == 1) {
30− y = (y - 1) % 3;
31− } else {
32− y = y * 4 + 1;
33− }
34− }
35− return y;
36− }
examples/passing/Import.pursdeleted−12
@@ -1,12 +0,0 @@
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
examples/passing/List.pursdeleted−21
@@ -1,21 +0,0 @@
1−module List where
2−
3− data List a
4− = Nil
5− | Cons
6− { head :: a
7− , tail :: List a
8− }
9−
10− isNull Nil = true
11− isNull _ = false
12−
13− concat Nil l2 = l2
14− concat (Cons x) l2 = Cons
15− { head: x.head
16− , tail: concat x.tail l2
17− }
18−
19− flatten Nil = Nil
20− flatten (Cons cons) = concat cons.head (flatten cons.tail)
21−
examples/passing/Match.pursdeleted−5
@@ -1,5 +0,0 @@
1−module Match where
2−
3− data Foo a = Foo
4−
5− foo = \f -> case f of Foo -> "foo"
examples/passing/Maybe.pursdeleted−11
@@ -1,11 +0,0 @@
1−module Maybe where
2−
3− data Maybe a = Nothing | Just a
4−
5− maybe :: forall a b. b -> (a -> b) -> Maybe a -> b
6− maybe b _ Nothing = b
7− maybe _ f (Just a) = f a
8−
9− fmap m f = maybe Nothing (\a -> Just (f a)) m
10−
11− bind m f = maybe Nothing f m
examples/passing/Module.pursdeleted−20
@@ -1,20 +0,0 @@
1−module M1 where
2−
3− data Foo = Foo String
4−
5− foo :: M1.Foo -> String
6− foo = \f -> case f of Foo s -> s ++ "foo"
7−
8− bar :: Foo -> String
9− bar = foo
10−
11− incr :: Number -> Number
12− incr x = x + 1
13−
14−module M2 where
15−
16− baz :: M1.Foo -> String
17− baz = M1.foo
18−
19− match :: M1.Foo -> String
20− match = \f -> case f of M1.Foo s -> s ++ "foo"
examples/passing/Monad.pursdeleted−28
@@ -1,28 +0,0 @@
1−module Monad where
2−
3− type Monad m = { ret :: 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 = { ret : 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 = { ret : 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.ret 1) (\n1 ->
23− m.bind (m.ret "Test") (\n2 ->
24− m.ret n1))
25−
26− test1 = test id
27−
28− test2 = test maybe
examples/passing/MutRec.pursdeleted−15
@@ -1,15 +0,0 @@
1−module MutRec where
2−
3− f 0 = 0
4− f x = g x + 1
5−
6− g x = f (x / 2)
7−
8− data Even = Zero | Even Odd
9−
10− data Odd = Odd Even
11−
12− evenToNumber Zero = 0
13− evenToNumber (Even n) = oddToNumber n + 1
14−
15− oddToNumber (Odd n) = evenToNumber n + 1
examples/passing/NamedPatterns.pursdeleted−5
@@ -1,5 +0,0 @@
1−module NamedPatterns where
2−
3− foo = \x -> case x of
4− y@{ foo = "Foo" } -> y
5− y -> y
examples/passing/Nested.pursdeleted−5
@@ -1,5 +0,0 @@
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)
examples/passing/ObjectUpdate.pursdeleted−16
@@ -1,16 +0,0 @@
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" }
examples/passing/Objects.pursdeleted−14
@@ -1,14 +0,0 @@
1−module Objects where
2−
3− test = \x -> x.foo + x.bar
4−
5− append = \o -> { foo: o.foo, bar: 1 }
6−
7− apTest = append({foo : "Foo", baz: "Baz"})
8−
9− f = (\a -> a.b.c) { b: { c: 1, d: "Hello" }, e: "World" }
10−
11− g = (\a -> a.f { x: 1, y: "y" }) { f: \o -> o.x + 1 }
12−
13− typed :: { foo :: Number }
14− typed = { foo: 0 }
examples/passing/Operators.pursdeleted−44
@@ -1,44 +0,0 @@
1−module Operators1 where
2−
3− (@@) :: forall a b. (a -> b) -> a -> b
4− (@@) = \f x -> f x
5−
6− foo :: String -> String
7− foo = \s -> s
8−
9− test8 = foo @@ "Hello World"
10−
11− bar = \s1 s2 -> s1 ++ s2
12−
13−module Operators2 where
14−
15− test1 = \(x, y, z) -> x * y + z(x)(y)
16−
17− test2 = (\x -> x.foo false) { foo : \_ -> 1 }
18−
19− test3 = (\(x, y) -> x)(1 + 2 * (1 + 2), true && (false || false))
20−
21− k = \x -> \y -> x
22−
23− test4 = 1 `k` 2
24−
25− infixl 5 %%
26−
27− (%%) = \x -> \y -> x * y + y
28−
29− test5 = 1 %% 2 %% 3
30−
31− test6 = ((\x -> x) `k` 2) 3
32−
33− (<>) = \s1 -> \s2 -> s1 ++ s2
34−
35− test7 = "Hello" <> "World!"
36−
37− test9 = Operators1.foo Operators1.@@ "Hello World"
38−
39− test10 = "Hello" `Operators1.bar` "World"
40−
41− (...) :: forall a. [a] -> [a] -> [a]
42− (...) = \as -> \bs -> as
43−
44− test11 = [1, 2, 3] ... [4, 5, 6]
examples/passing/OptimizerBug.pursdeleted−5
@@ -1,5 +0,0 @@
1−module OptimizerBug where
2−
3−x = 1 + y
4−
5−y = x
examples/passing/Patterns.pursdeleted−25
@@ -1,25 +0,0 @@
1−module Patterns where
2−
3− test = \x -> case x of
4− { str = "Foo", bool = true } -> true
5− { str = "Bar", bool = b } -> b
6− _ -> false
7−
8− f = \o -> case o of
9− { foo = "Foo" } -> o.bar
10− _ -> 0
11−
12− g = \o -> case o of
13− { arr = [x : xs], take = "car" } -> x
14− { arr = [_, x : xs], take = "cadr" } -> x
15− _ -> 0
16−
17−
18− h = \o -> case o of
19− a@[_,_,_] -> a
20− _ -> []
21−
22− isDesc = \o -> case o of
23− [x, y] | x > y -> true
24− _ -> false
25−
examples/passing/Person.pursdeleted−9
@@ -1,9 +0,0 @@
1−module Person where
2−
3− data Person = Person { name :: String, age :: Number }
4−
5− foreign import itoa :: Number -> String
6−
7− showPerson :: Person -> String
8− showPerson = \p -> case p of
9− Person o -> o.name ++ ", aged " ++ itoa(o.age)
examples/passing/Rank2Data.pursdeleted−25
@@ -1,25 +0,0 @@
1−module Rank2Data where
2−
3− data Id = Id forall a. a -> a
4−
5− runId = \id a -> case id of
6− Id f -> f a
7−
8− data Nat = Nat forall r. r -> (r -> r) -> r
9−
10− runNat = \nat -> case nat of
11− Nat f -> f 0 (\n -> n + 1)
12−
13− zero = Nat (\zero _ -> zero)
14−
15− succ = \n -> case n of
16− Nat f -> Nat (\zero succ -> succ (f zero succ))
17−
18− add = \n m -> case n of
19− Nat f -> case m of
20− Nat g -> Nat (\zero succ -> g (f zero succ) succ)
21−
22− one = succ zero
23− two = succ zero
24− four = add two two
25− fourNumber = runNat four
examples/passing/Rank2Types.pursdeleted−19
@@ -1,19 +0,0 @@
1−module Rank2Types where
2−
3− test1 :: (forall a. (a -> a)) -> Number
4− test1 = \f -> f 0
5−
6− foreign import data ST :: * -> * -> *
7−
8− foreign import runST :: forall a. (forall s. ST s a) -> a
9−
10− foreign import exampleST :: forall s. ST s Number
11−
12− testST = runST exampleST
13−
14− foreign import push :: forall el. el -> [el] -> [el]
15−
16− replicateM :: forall m a. (forall a. a -> m a) -> (forall a b. m a -> (a -> m b) -> m b) -> Number -> m a -> m [a]
17− replicateM = \ret bind n m -> case n of
18− 0 -> ret []
19− n -> bind m (\x -> bind (replicateM ret bind (n - 1) m) (\xs -> ret (push x xs)))
examples/passing/Recursion.pursdeleted−6
@@ -1,6 +0,0 @@
1−module Recursion where
2−
3− fib = \n -> case n of
4− 0 -> 1
5− 1 -> 1
6− n -> fib (n - 1) + fib (n - 2)
examples/passing/TailCall.pursdeleted−10
@@ -1,10 +0,0 @@
1−module TailCall where
2−
3−test n [] = n
4−test n (x:xs) = test (n + x) xs
5−
6−loop x = loop (x + 1)
7−
8−notATailCall = \x ->
9− (\notATailCall -> notATailCall x) (\x -> x)
10−
examples/passing/TopLevelCase.pursdeleted−14
@@ -1,14 +0,0 @@
1−module TopLevelCase where
2−
3− gcd :: (Number, Number) -> Number
4− gcd (0, x) = x
5− gcd (x, 0) = x
6− gcd (x, y) | x > y = gcd (x % y, y)
7− gcd (x, y) = gcd (y % x, x)
8−
9− guardsTest (x:xs) | x > 0 = guardsTest xs
10− guardsTest xs = xs
11−
12− data A = A
13−
14− parseTest A 0 = 0
examples/passing/TypeClasses.pursdeleted−38
@@ -1,38 +0,0 @@
1−module TypeClasses where
2−
3−class Show a where
4− show :: a -> String
5−
6−instance TypeClasses.Show String where
7− show s = s
8−
9−test1 = show "testing"
10−
11−f :: forall a. (TypeClasses.Show a) => a -> String
12−f x = show x
13−
14−test2 = f "testing"
15−
16−data Data a = Data a
17−
18−instance (TypeClasses.Show a) => TypeClasses.Show (Data a) where
19− show (Data a) = "Data (" ++ show a ++ ")"
20−
21−test3 = show (Data "testing")
22−
23−class Monad m where
24− ret :: forall a. a -> m a
25− bind :: forall a b. m a -> (a -> m b) -> m b
26−
27−instance TypeClasses.Monad Data where
28− ret = Data
29− bind (Data a) f = f a
30−
31−data Maybe a = Nothing | Just a
32−
33−instance TypeClasses.Monad Maybe where
34− ret = Just
35− bind Nothing _ = Nothing
36− bind (Just a) f = f a
37−
38−test4 = Just 1 `bind` (\n -> Just (n + 1))
examples/passing/TypeDecl.pursdeleted−16
@@ -1,16 +0,0 @@
1−module TypeDecl where
2−
3− id :: forall a. (a) -> a
4− id = \x -> x
5−
6− k :: String -> Number -> String
7− k = \x -> \y -> x
8−
9− iterate :: forall a. Number -> (a -> a) -> a -> a
10− iterate = \n -> \f -> \a -> {
11− var result = a;
12− for (i <- 0 until n) {
13− result = f result;
14− }
15− return result;
16− }
examples/passing/TypeSynonyms.pursdeleted−33
@@ -1,33 +0,0 @@
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 ->
12− {
13− var b = l1.get a;
14− var b1 = l2.set b c;
15− return l1.set a b1;
16− }
17− }
18−
19− type Pair a b = { fst :: a, snd :: b }
20−
21− fst :: forall a b. Lens (Pair a b) a
22− fst =
23− { get: \p -> p.fst
24− , set: \p -> \a -> { fst: a, snd: p.snd }
25− }
26−
27− test1 :: forall a b c. Lens (Pair (Pair a b) c) a
28− test1 = composeLenses fst fst
29−
30− foreign import head :: forall a. Lens [a] a
31−
32− test2 :: forall a b c. Lens (Pair [Pair a b] c) a
33− test2 = composeLenses fst (composeLenses head fst)
examples/passing/iota.pursdeleted−7
@@ -1,7 +0,0 @@
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
examples/passing/s.pursdeleted−3
@@ -1,3 +0,0 @@
1−module S where
2−
3− s = \x y z -> x z (y z)
examples/shelltest/Console.jsdeleted−19
@@ -1,19 +0,0 @@
1−// data IO a = \ -> a
2−
3−// ret :: forall a. a -> IO a
4−var ret = function(a) {
5− return function() { return a; };
6−}
7−
8−// (>>=) :: forall a b. IO a -> (a -> IO b) -> IO b
9−var $62$62$61 = function(first) {
10− return function (f) {
11− return function () {
12− var a = first();
13− return f(a)();
14− };
15− };
16−};
17−
18−// putStrLn :: String -> IO {}
19−var putStrLn = function(str) { return function() { console.log(str); return {}; }; };
examples/shelltest/List.jsdeleted−7
@@ -1,7 +0,0 @@
1−var l1 = List.Cons({ head: 1, tail: List.Nil });
2−var l2 = List.Cons({ head: 2, tail: List.Nil });
3−var l3 = List.Cons({ head: l1, tail: List.Cons({ head: l2, tail: List.Nil }) });
4−var flat = List.flatten(l3);
5−var f1 = flat.value.head;
6−var f2 = flat.value.tail.value.head
7−console.log([f1, f2]);
examples/shelltest/Maybe.jsdeleted−5
@@ -1,5 +0,0 @@
1−console.log(Maybe.bind(Maybe.Just("a"))(function(a) {
2− return Maybe.bind(Maybe.Just("b"))(function(b) {
3− return Maybe.Just(a + b);
4− });
5−}));
examples/shelltest/runAll.testdeleted−16
@@ -1,16 +0,0 @@
1−# Maybe
2−mkdir -p tests && ../../dist/build/psc/psc --no-prelude ../passing/Maybe.purs -o tests/Maybe.js && cat tests/Maybe.js Maybe.js | nodejs
3−<<<
4−>>>
5−{ ctor: 'Maybe.Just', value: 'ab' }
6−>>>2
7−>>>= 0
8−
9−# List
10−mkdir -p tests && ../../dist/build/psc/psc ../passing/List.purs -o tests/List.js && cat tests/List.js List.js | nodejs
11−<<<
12−>>>
13−[ 1, 2 ]
14−>>>2
15−>>>= 0
16−
examples/shelltest/runMain.jsdeleted−1
@@ -1 +0,0 @@
1−main();
libraries/.gitignoredeleted−1
@@ -1 +0,0 @@
1−*/all.js
libraries/jquery/README.mddeleted−7
@@ -1,7 +0,0 @@
1−# JQuery Library
2−
3−A work in progress.
4−
5−To build the test, use
6−
7− psc jquery.purs tests/jquery.purs
libraries/jquery/jquery.pursdeleted−30
@@ -1,30 +0,0 @@
1−module JQuery where
2−
3− import Eff
4−
5− -- An effect type which indicates DOM manipulation
6− foreign import data DOM :: !
7−
8− -- The jQuery wrapper type
9− foreign import data JQuery :: *
10−
11− -- Wrapper function for jQuery selection $('..')
12− foreign import select "function select(selector) { return function () { return jQuery(selector); }; }" :: forall eff. String -> Eff (dom :: DOM | eff) JQuery
13−
14− -- Wrapper function for jQuery creation e.g. $('<div>')
15− foreign import create "function create(html) { return function () { return jQuery(html); }; }" :: forall eff. String -> Eff (dom :: DOM | eff) JQuery
16−
17− -- .attr({ ... })
18− foreign import attr "function attr(attrs) { return function(ob) { return function () { return ob.attr(attrs); }; }; }" :: forall eff attr. { | attr } -> JQuery -> Eff (dom :: DOM | eff) JQuery
19−
20− -- .css({ ... })
21− foreign import css "function css(props) { return function(ob) { return function () { return ob.css(props); }; }; }" :: forall eff css. { | css } -> JQuery -> Eff (dom :: DOM | eff) JQuery
22−
23− -- .append(...)
24− foreign import append "function append(ob1) { return function(ob) { return function () { return ob.append(ob1); }; }; }" :: forall eff. JQuery -> JQuery -> Eff (dom :: DOM | eff) JQuery
25−
26− -- .append(...)
27− foreign import appendText "function appendText(s) { return function(ob) { return function () { return ob.append(s); }; }; }" :: forall eff. String -> JQuery -> Eff (dom :: DOM | eff) JQuery
28−
29− -- Get the document body
30− foreign import body "function body() { return jQuery(document.body); }" :: forall eff. Eff (dom :: DOM | eff) JQuery
libraries/jquery/tests/jquery.pursdeleted−11
@@ -1,11 +0,0 @@
1−module Main where
2−
3−import Eff
4−import JQuery
5−
6−main = eff do
7− b <- body
8− div <- create "<div>"
9− { color: "red" } `css` div
10− appendText "Hello World" div
11− div `append` b
libraries/prelude/Makefiledeleted−3
@@ -1,3 +0,0 @@
1−all:
2− ../../dist/build/psc/psc --no-prelude prelude.purs -o all.js
3− cat prelude.js >> all.js
libraries/prelude/prelude.jsdeleted−42
@@ -1,42 +0,0 @@
1−// Arrays
2−
3−function indexOf(l) { return function (e) { return l.indexOf(e); }; }
4−function lastIndexOf(l) { return function (e) { return l.lastIndexOf(e); }; }
5−function concat(l1) { return function (l2) { return l1.concat(l2); }; }
6−function join(l) { return l.join(); }
7−function joinWith(l) { return function (s) { return l.join(s); }; }
8−function push(l) { return function (e) { var l1 = l.slice(); l1.push(e); return l1; }; }
9−function reverse(l) { var l1 = l.slice(); l1.reverse(); return l1; }
10−function shift(l) { var l1 = l.slice(); l1.shift(); return l1; }
11−function slice(s) { return function(e) { return function (l) { return l.slice(s, e); }; }; }
12−function sort(l) { var l1 = l.slice(); l.sort(); return l1; }
13−function splice(s) { return function(e) { return function(l1) { return function(l2) { return l2.splice(s, e, l1); }; }; }; }
14−
15−function charAt(i) { return function(s) { return s.charAt(i); }; }
16−function indexOfS(s1) { return function(s2) { return s2.indexOf(s2); }; }
17−function lastIndexOfS(s1) { return function(s2) { return s2.lastIndexOf(s2); }; }
18−function localeCompare(s1) { return function(s2) { return s1.localeCompare(s2); }; }
19−function replace(s1) { return function(s2) { return function(s3) { return s3.replace(s1, s2) }; }; }
20−function sliceS(st) { return function(e) { return function(s) { return s.slice(st, e); }; }; }
21−function split(sep) { return function(s) { return s.split(s); }; }
22−function substr(n1) { return function(n2) { return function(s) { return s.substr(n1, n2); }; }; }
23−function substring(n1) { return function(n2) { return function(s) { return s.substring(n1, n2); }; }; }
24−function toLower(s) { return s.toLower(); }
25−function toUpper(s) { return s.toUpper(); }
26−function trim(s) { return s.trim(); }
27−
28−function regex(s1) { return function(s2) { return new Regex(s1, s2); }; };
29−function test(r) { return function (s) { return r.test(s); }; };
30−function match(r) { return function (s) { return s.match(r); }; };
31−function replaceR(r) { return function(s1) { return function(s2) { return s2.replace(r, s1) }; }; }
32−function search(r) { return function (s) { return s.search(r); }; };
33−
34−var nan = NaN;
35−var infinity = Infinity;
36−function toExponential(n) { return n.toExponential(); }
37−function toFixed(d) { return function(n) { return n.toFixed(d); }; }
38−function toPrecision(d) { return function(n) { return n.toPrecision(d); }; }
39−function numberToString(n) { return n.toString(); }
40−
41−var math = Math;
42−
libraries/prelude/prelude.pursdeleted−329
@@ -1,329 +0,0 @@
1−module Prelude where
2−
3− id :: forall a. a -> a
4− id = \x -> x
5−
6− flip :: forall a b c. (a -> b -> c) -> b -> a -> c
7− flip = \f -> \b -> \a -> f a b
8−
9− konst :: forall a b. a -> b -> a
10− konst = \a -> \b -> a
11−
12− (|>) :: forall a b c. (a -> b) -> (b -> c) -> a -> c
13− (|>) = \f -> \g -> \a -> g (f a)
14−
15− infixr 5 |>
16−
17− (<|) :: forall a b c. (b -> c) -> (a -> b) -> a -> c
18− (<|) = flip (|>)
19−
20− infixr 5 <|
21−
22− ($) :: forall a b. (a -> b) -> a -> b
23− ($) f x = f x
24−
25− infixr 1000 $
26−
27−module Maybe where
28−
29− data Maybe a = Nothing | Just a
30−
31− maybe :: forall a b. b -> (a -> b) -> Maybe a -> b
32− maybe b _ Nothing = b
33− maybe _ f (Just a) = f a
34−
35− fromMaybe :: forall a. a -> Maybe a -> a
36− fromMaybe a = maybe a Prelude.id
37−
38− bindMaybe :: forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
39− bindMaybe m f = maybe Nothing f m
40−
41−module Either where
42−
43− data Either a b = Left a | Right b
44−
45− either :: forall a b c. (a -> c) -> (b -> c) -> Either a b -> c
46− either f _ (Left a) = f a
47− either _ g (Right b) = g b
48−
49− bindEither :: forall e a b. Either e a -> (a -> Either e b) -> Either e b
50− bindEither = either (\e _ -> Left e) (\a f -> f a)
51−
52−module Arrays where
53−
54− import Maybe
55−
56− head :: forall a. [a] -> a
57− head (x : _) = x
58−
59− headSafe :: forall a. [a] -> Maybe a
60− headSafe (x : _) = Just x
61− headSafe _ = Nothing
62−
63− tail :: forall a. [a] -> [a]
64− tail (_ : xs) = xs
65−
66− tailSafe :: forall a. [a] -> Maybe [a]
67− tailSafe (_ : xs) = Just xs
68− tailSafe _ = Nothing
69−
70− map :: forall a b. (a -> b) -> [a] -> [b]
71− map _ [] = []
72− map f (x:xs) = f x : map f xs
73−
74− foldr :: forall a b. (a -> b -> a) -> a -> [b] -> a
75− foldr f a (b : bs) = f (foldr f a bs) b
76− foldr _ a [] = a
77−
78− foldl :: forall a b. (a -> b -> b) -> b -> [a] -> b
79− foldl _ b [] = b
80− foldl f b (a:as) = foldl f (f a b) as
81−
82− foreign import length "function length(xs) { \
83− \ return xs.length; \
84− \}" :: forall a. [a] -> Number
85−
86− foreign import indexOf :: forall a. [a] -> a -> Number
87−
88− foreign import lastIndexOf :: forall a. [a] -> a -> Number
89−
90− foreign import concat :: forall a. [a] -> [a] -> [a]
91−
92− foreign import join :: [String] -> String
93−
94− foreign import joinWith :: [String] -> String -> String
95−
96− foreign import push :: forall a. [a] -> a -> [a]
97−
98− foreign import reverse :: forall a. [a] -> [a]
99−
100− foreign import shift :: forall a. [a] -> [a]
101−
102− foreign import slice :: forall a. Number -> Number -> [a] -> [a]
103−
104− foreign import sort :: forall a. [a] -> [a]
105−
106− foreign import splice :: forall a. Number -> Number -> [a] -> [a] -> [a]
107−
108− infixr 6 :
109−
110− (:) :: forall a. a -> [a] -> [a]
111− (:) a = concat [a]
112−
113− concatMap :: forall a b. [a] -> (a -> [b]) -> [b]
114− concatMap [] f = []
115− concatMap (a:as) f = f a `concat` concatMap as f
116−
117− filter :: forall a. (a -> Boolean) -> [a] -> [a]
118− filter _ [] = []
119− filter p (x:xs) | p x = x : filter p xs
120− filter p (_:xs) = filter p xs
121−
122− empty :: forall a. [a] -> Boolean
123− empty [] = true
124− empty _ = false
125−
126− range :: Number -> Number -> [Number]
127− range lo hi = {
128− var ns = [];
129− for (n <- lo until hi) {
130− ns = push ns n;
131− }
132− return ns;
133− }
134−
135− zipWith :: forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
136− zipWith f (a:as) (b:bs) = f a b : zipWith f as bs
137− zipWith _ _ _ = []
138−
139− any :: forall a. (a -> Boolean) -> [a] -> Boolean
140− any _ [] = false
141− any p (a:as) = p a || any p as
142−
143− all :: forall a. (a -> Boolean) -> [a] -> Boolean
144− all _ [] = true
145− all p (a:as) = p a && all p as
146−
147−module Tuple where
148−
149− import Arrays
150−
151− type Tuple a b = { fst :: a, snd :: b }
152−
153− curry :: forall a b c. (Tuple a b -> c) -> a -> b -> c
154− curry f a b = f { fst: a, snd: b }
155−
156− uncurry :: forall a b c. (a -> b -> c) -> Tuple a b -> c
157− uncurry f t = f t.fst t.snd
158−
159− tuple :: forall a b. a -> b -> Tuple a b
160− tuple = curry Prelude.id
161−
162− zip :: forall a b. [a] -> [b] -> [Tuple a b]
163− zip = zipWith tuple
164−
165− unzip :: forall a b. [Tuple a b] -> Tuple [a] [b]
166− unzip (t:ts) = case unzip ts of
167− { fst = as, snd = bs } -> tuple (t.fst : as) (t.snd : bs)
168− unzip [] = tuple [] []
169−
170−module String where
171−
172− foreign import lengthS "function lengthS(s) {\
173− \ return s.length;\
174− \}" :: String -> Number
175−
176− foreign import charAt :: Number -> String -> String
177−
178− foreign import indexOfS :: String -> String -> Number
179−
180− foreign import lastIndexOfS :: String -> String -> Number
181−
182− foreign import localeCompare :: String -> String -> Number
183−
184− foreign import replace :: String -> String -> String -> String
185−
186− foreign import sliceS :: Number -> Number -> String -> String
187−
188− foreign import split :: String -> String -> [String]
189−
190− foreign import substr :: Number -> Number -> String -> String
191−
192− foreign import substring :: Number -> Number -> String -> String
193−
194− foreign import toLower :: String -> String
195−
196− foreign import toUpper :: String -> String
197−
198− foreign import trim :: String -> String
199−
200−module Regex where
201−
202− foreign import data Regex :: *
203−
204− foreign import regex :: String -> String -> Regex
205−
206− foreign import test :: Regex -> String -> Boolean
207−
208− foreign import match :: Regex -> String -> [String]
209−
210− foreign import replaceR :: Regex -> String -> String -> String
211−
212− foreign import search :: Regex -> String -> Number
213−
214−module Global where
215−
216− foreign import nan :: Number
217−
218− foreign import infinity :: Number
219−
220− foreign import toExponential :: Number -> String
221−
222− foreign import toFixed :: Number -> Number -> String
223−
224− foreign import toPrecision :: Number -> Number -> String
225−
226− foreign import numberToString :: Number -> String
227−
228− foreign import isNaN :: Number -> Boolean
229−
230− foreign import isFinite :: Number -> Boolean
231−
232− foreign import parseFloat :: String -> Number
233−
234− foreign import parseInt :: String -> Number
235−
236− foreign import encodeURIComponent :: String -> String
237−
238− foreign import decodeURIComponent :: String -> String
239−
240− foreign import encodeURI :: String -> String
241−
242− foreign import decodeURI :: String -> String
243−
244−module Math where
245−
246− type Math =
247− { abs :: Number -> Number
248− , acos :: Number -> Number
249− , asin :: Number -> Number
250− , atan :: Number -> Number
251− , atan2 :: (Number, Number) -> Number
252− , aceil :: Number -> Number
253− , cos :: Number -> Number
254− , exp :: Number -> Number
255− , floor :: Number -> Number
256− , log :: Number -> Number
257− , max :: (Number, Number) -> Number
258− , pow :: (Number, Number) -> Number
259− , random :: () -> Number
260− , round :: Number -> Number
261− , sin :: Number -> Number
262− , sqrt :: Number -> Number
263− , tan :: Number -> Number
264− }
265−
266− foreign import math :: Math
267−
268−module Eff where
269−
270− foreign import data Eff :: # ! -> * -> *
271−
272− foreign import retEff "function retEff(a) { return function() { return a; }; }" :: forall e a. a -> Eff e a
273−
274− foreign import bindEff "function bindEff(a) { return function(f) { return function() { return f(a())(); }; }; }" :: forall e a b. Eff e a -> (a -> Eff e b) -> Eff e b
275−
276− type Pure a = forall e. Eff e a
277−
278− foreign import runPure "function runPure(f) { return f(); }" :: forall a. Pure a -> a
279−
280− eff = { ret: retEff, bind: bindEff }
281−
282−module Errors where
283−
284− import Eff
285−
286− foreign import data Error :: * -> !
287−
288− foreign import throwError "function throwError(e) { return function() { throw e; }; }" :: forall a e r. e -> Eff (err :: Error e | r) a
289−
290− foreign import catchError "function catchError(c) { return function(t) { return function() { try { return t(); } catch(e) { return c(e)(); } }; }; }" :: forall e r a. (e -> Eff r a) -> Eff (err :: Error e | r) a -> Eff r a
291−
292−module IORef where
293−
294− import Eff
295−
296− foreign import data Ref :: !
297−
298− foreign import data IORef :: * -> *
299−
300− foreign import newIORef :: forall s r. s -> Eff (ref :: Ref | r) (IORef s)
301−
302− foreign import readIORef :: forall s r. IORef s -> Eff (ref :: Ref | r) s
303−
304− foreign import writeIORef :: forall s r. IORef s -> s -> Eff (ref :: Ref | r) {}
305−
306−module Trace where
307−
308− import Eff
309−
310− foreign import data Trace :: !
311−
312− foreign import trace "function trace(s) { return function() { console.log(s); return {}; }; }" :: forall r. String -> Eff (trace :: Trace | r) {}
313−
314−module ST where
315−
316− import Eff
317−
318− foreign import data ST :: * -> !
319−
320− foreign import data STRef :: * -> * -> *
321−
322− foreign import newSTRef :: forall a h r. a -> Eff (st :: ST h | r) (STRef h a)
323−
324− foreign import readSTRef :: forall a h r. STRef h a -> Eff (st :: ST h | r) a
325−
326− foreign import modifySTRef :: forall a h r. (a -> a) -> STRef h a -> Eff (st :: ST h | r) {}
327−
328− foreign import runST :: forall a r. (forall h. Eff (st :: ST h | r) a) -> Eff r a
329−
libraries/prelude/tests/Eff.pursdeleted−41
@@ -1,41 +0,0 @@
1−module Tests where
2−
3−import Prelude
4−import Eff
5−import Errors
6−import Trace
7−
8−test1 n = runPure $ catchError (\s -> eff do return 0) $ eff do
9− case {} of
10− _ | n > 10 -> eff do
11− throwError "Error!"
12− _ -> eff do return n
13−
14−test2 = eff do
15− trace "Hello World"
16− throwError "Error!"
17−
18−test3 n = catchError (\s -> eff do return 0) $ eff do
19− case {} of
20− _ | n > 10 -> eff do
21− trace "n > 10"
22− throwError "Error!"
23− _ -> eff do return n
24−
25−test4 = eff do
26− trace "Hello World!"
27− return 0
28−
29−test5 = eff do
30− trace "Hello World!"
31− test5
32−
33−test6 s = eff do
34− trace s
35− test6 (s ++ " test")
36−
37−module Main where
38−
39−import Tests
40−
41−main = test6 ""
package.yamlnew file+86
@@ -0,0 +1,86 @@
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
psgo.cabalnew file+145
@@ -0,0 +1,145 @@
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.cabaldeleted−84
@@ -1,84 +0,0 @@
1−name: purescript
2−version: 0.2.14
3−cabal-version: >=1.8
4−build-type: Simple
5−license: MIT
6−license-file: LICENSE
7−copyright: (c) Phil Freeman 2013
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−author: Phil Freeman <paf31@cantab.net>
14−data-dir: ""
15−data-files: libraries/prelude/prelude.purs
16−
17−library
18− build-depends: base >=4 && <5, cmdtheline -any, containers -any,
19− directory -any, filepath -any, mtl -any, parsec -any, syb -any,
20− transformers -any, utf8-string -any
21− exposed-modules: Data.Generics.Extras
22− Language.PureScript
23− Language.PureScript.Options
24− Language.PureScript.Declarations
25− Language.PureScript.Kinds
26− Language.PureScript.Names
27− Language.PureScript.Types
28− Language.PureScript.Unknown
29− Language.PureScript.Values
30− Language.PureScript.Scope
31− Language.PureScript.Sugar
32− Language.PureScript.Sugar.CaseDeclarations
33− Language.PureScript.Sugar.DoNotation
34− Language.PureScript.Sugar.TypeDeclarations
35− Language.PureScript.Sugar.BindingGroups
36− Language.PureScript.Sugar.Operators
37− Language.PureScript.Sugar.TypeClasses
38− Language.PureScript.CodeGen
39− Language.PureScript.CodeGen.Externs
40− Language.PureScript.CodeGen.JS
41− Language.PureScript.CodeGen.JS.AST
42− Language.PureScript.CodeGen.Monad
43− Language.PureScript.CodeGen.Optimize
44− Language.PureScript.Parser
45− Language.PureScript.Parser.Common
46− Language.PureScript.Parser.Declarations
47− Language.PureScript.Parser.Kinds
48− Language.PureScript.Parser.State
49− Language.PureScript.Parser.Types
50− Language.PureScript.Parser.Values
51− Language.PureScript.Parser.JS
52− Language.PureScript.Pretty
53− Language.PureScript.Pretty.Common
54− Language.PureScript.Pretty.JS
55− Language.PureScript.Pretty.Kinds
56− Language.PureScript.Pretty.Types
57− Language.PureScript.Pretty.Values
58− Language.PureScript.TypeChecker
59− Language.PureScript.TypeChecker.Kinds
60− Language.PureScript.TypeChecker.Monad
61− Language.PureScript.TypeChecker.Synonyms
62− Language.PureScript.TypeChecker.Types
63− exposed: True
64− buildable: True
65− hs-source-dirs: src
66−
67−executable psc
68− build-depends: base >=4 && <5, cmdtheline -any, containers -any,
69− directory -any, filepath -any, mtl -any, parsec -any,
70− purescript -any, syb -any, transformers -any, utf8-string -any
71− main-is: Main.hs
72− buildable: True
73− hs-source-dirs: src
74− other-modules:
75− ghc-options: -Wall -O2
76−
77−test-suite tests
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− type: exitcode-stdio-1.0
82− main-is: Main.hs
83− buildable: True
84− hs-source-dirs: tests
release.mddeleted−86
@@ -1,86 +0,0 @@
1−## 0.2.0 Changes
2−
3−Many thanks to the [contributors](https://github.com/paf31/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.
86−
src/CodeGen/IL.hsnew file+321
@@ -0,0 +1,321 @@
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.hsnew file+196
@@ -0,0 +1,196 @@
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.hsnew file+81
@@ -0,0 +1,81 @@
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.hsnew file+18
@@ -0,0 +1,18 @@
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.hsnew file+435
@@ -0,0 +1,435 @@
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.hsnew file+146
@@ -0,0 +1,146 @@
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.hsnew file+141
@@ -0,0 +1,141 @@
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.hsnew file+527
@@ -0,0 +1,527 @@
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.hsdeleted−24
@@ -1,24 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE Rank2Types #-}
16−
17−module Data.Generics.Extras where
18−
19−import Data.Data
20−
21−everywhereM' :: (Monad m, Data d) => (forall d1. (Data d1) => d1 -> m d1) -> d -> m d
22−everywhereM' f x = do
23− y <- f x
24− gmapM (everywhereM' f) y
src/Language/PureScript.hsdeleted−46
@@ -1,46 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript (module P, compile) where
16−
17−import Language.PureScript.Values as P
18−import Language.PureScript.Types as P
19−import Language.PureScript.Kinds as P
20−import Language.PureScript.Declarations as P
21−import Language.PureScript.Names as P
22−import Language.PureScript.Parser as P
23−import Language.PureScript.CodeGen as P
24−import Language.PureScript.TypeChecker as P
25−import Language.PureScript.Pretty as P
26−import Language.PureScript.Sugar as P
27−import Language.PureScript.Options as P
28−
29−import Data.List (intercalate)
30−import Control.Monad (when, forM)
31−import Control.Applicative ((<$>))
32−import qualified Data.Map as M
33−
34−compile :: Options -> [Module] -> Either String (String, String, Environment)
35−compile opts ms = do
36− desugared <- desugar ms
37− (elaborated, env) <- runCheck $ forM desugared $ \(Module moduleName decls) -> Module moduleName <$> typeCheckAll (ModuleName moduleName) decls
38− let js = concatMap (flip (moduleToJs opts) env) $ elaborated
39− let exts = intercalate "\n" . map (flip moduleToPs env) $ elaborated
40− js' <- case () of
41− _ | optionsRunMain opts -> do
42− when ((ModuleName (ProperName "Main"), Ident "main") `M.notMember` (names env)) $
43− Left "Main.main is undefined"
44− return $ js ++ [JSApp (JSAccessor "main" (JSVar (Ident "Main"))) []]
45− | otherwise -> return js
46− return (prettyPrintJS js', exts, env)
src/Language/PureScript/CodeGen.hsdeleted−19
@@ -1,19 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.CodeGen (module C) where
16−
17−import Language.PureScript.CodeGen.JS as C
18−import Language.PureScript.CodeGen.Externs as C
19−import Language.PureScript.CodeGen.Optimize as C
src/Language/PureScript/CodeGen/Externs.hsdeleted−47
@@ -1,47 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.CodeGen.Externs (
16− moduleToPs
17−) where
18−
19−import Data.Maybe (maybeToList, mapMaybe)
20−import qualified Data.Map as M
21−import Language.PureScript.Declarations
22−import Language.PureScript.TypeChecker.Monad
23−import Language.PureScript.Pretty
24−import Language.PureScript.Names
25−import Data.List (intercalate)
26−
27−moduleToPs :: Module -> Environment -> String
28−moduleToPs (Module pname@(ProperName moduleName) decls) env =
29− "module " ++ moduleName ++ " where\n" ++
30− (intercalate "\n" . map (" " ++) . concatMap (declToPs (ModuleName pname) env) $ decls)
31−
32−declToPs :: ModuleName -> Environment -> Declaration -> [String]
33−declToPs path env (ValueDeclaration name _ _ _) = maybeToList $ do
34− (ty, _) <- M.lookup (path, name) $ names env
35− return $ "foreign import " ++ show name ++ " :: " ++ prettyPrintType ty
36−declToPs path env (BindingGroupDeclaration vals) = do
37− flip mapMaybe vals $ \(name, _) -> do
38− (ty, _) <- M.lookup (path, name) $ names env
39− return $ "foreign import " ++ show name ++ " :: " ++ prettyPrintType ty
40−declToPs path env (DataDeclaration name _ _) = maybeToList $ do
41− (kind, _) <- M.lookup (path, name) $ types env
42− return $ "foreign import data " ++ show name ++ " :: " ++ prettyPrintKind kind
43−declToPs _ _ (ExternDataDeclaration name kind) =
44− return $ "foreign import data " ++ show name ++ " :: " ++ prettyPrintKind kind
45−declToPs _ _ (TypeSynonymDeclaration name args ty) =
46− return $ "type " ++ show name ++ " " ++ unwords args ++ " = " ++ prettyPrintType ty
47−declToPs _ _ _ = []
src/Language/PureScript/CodeGen/JS.hsdeleted−227
@@ -1,227 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.CodeGen.JS (
16− module AST,
17− declToJs,
18− moduleToJs
19−) where
20−
21−import Data.Maybe (mapMaybe)
22−import qualified Data.Map as M
23−import Control.Arrow (second)
24−import Control.Monad (replicateM, forM)
25−
26−import Language.PureScript.TypeChecker (Environment(..), NameKind(..))
27−import Language.PureScript.Values
28−import Language.PureScript.Names
29−import Language.PureScript.Scope
30−import Language.PureScript.Declarations
31−import Language.PureScript.Pretty.Common
32−import Language.PureScript.CodeGen.Monad
33−import Language.PureScript.Options
34−import Language.PureScript.CodeGen.JS.AST as AST
35−import Language.PureScript.Types
36−import Language.PureScript.CodeGen.Optimize
37−
38−moduleToJs :: Options -> Module -> Environment -> [JS]
39−moduleToJs opts (Module pname@(ProperName name) decls) env =
40− mapMaybe filterRawDecls decls ++
41− [ JSVariableIntroduction (Ident name) Nothing
42− , JSApp (JSFunction Nothing [Ident name]
43− (JSBlock (concat $ mapMaybe (\decl -> fmap (map $ optimize opts) $ declToJs opts (ModuleName pname) decl env) decls)))
44− [JSAssignment (JSAssignVariable (Ident name))
45− (JSBinary Or (JSVar (Ident name)) (JSObjectLiteral []))]
46− ]
47− where
48− filterRawDecls (ExternDeclaration _ (Just js) _) = Just js
49− filterRawDecls _ = Nothing
50−
51−declToJs :: Options -> ModuleName -> Declaration -> Environment -> Maybe [JS]
52−declToJs opts mp (ValueDeclaration ident _ _ val) e =
53− Just [ JSVariableIntroduction ident (Just (valueToJs opts mp e val)),
54− setProperty (identToJs ident) (JSVar ident) mp ]
55−declToJs opts mp (BindingGroupDeclaration vals) e =
56− Just $ concatMap (\(ident, val) ->
57− [ JSVariableIntroduction ident (Just (valueToJs opts mp e val)),
58− setProperty (identToJs ident) (JSVar ident) mp ]
59− ) vals
60−declToJs _ mp (DataDeclaration _ _ ctors) _ =
61− Just $ flip concatMap ctors $ \(pn@(ProperName ctor), maybeTy) ->
62− let
63− ctorJs =
64− case maybeTy of
65− Nothing -> JSVariableIntroduction (Ident ctor) (Just (JSObjectLiteral [ ("ctor", JSStringLiteral (show (Qualified (Just mp) pn))) ]))
66− Just _ -> JSFunction (Just (Ident ctor)) [Ident "value"]
67− (JSBlock [JSReturn
68− (JSObjectLiteral [ ("ctor", JSStringLiteral (show (Qualified (Just mp) pn)))
69− , ("value", JSVar (Ident "value")) ])])
70− in [ ctorJs, setProperty ctor (JSVar (Ident ctor)) mp ]
71−declToJs _ _ _ _ = Nothing
72−
73−setProperty :: String -> JS -> ModuleName -> JS
74−setProperty prop val (ModuleName (ProperName moduleName)) = JSAssignment (JSAssignProperty prop (JSAssignVariable (Ident moduleName))) val
75−
76−valueToJs :: Options -> ModuleName -> Environment -> Value -> JS
77−valueToJs _ _ _ (NumericLiteral n) = JSNumericLiteral n
78−valueToJs _ _ _ (StringLiteral s) = JSStringLiteral s
79−valueToJs _ _ _ (BooleanLiteral b) = JSBooleanLiteral b
80−valueToJs opts m e (ArrayLiteral xs) = JSArrayLiteral (map (valueToJs opts m e) xs)
81−valueToJs opts m e (ObjectLiteral ps) = JSObjectLiteral (map (second (valueToJs opts m e)) ps)
82−valueToJs opts m e (ObjectUpdate o ps) = JSApp (JSAccessor "extend" (JSVar (Ident "Object"))) [ valueToJs opts m e o, JSObjectLiteral (map (second (valueToJs opts m e)) ps)]
83−valueToJs _ m e (Constructor (Qualified Nothing name)) =
84− case M.lookup (m, name) (dataConstructors e) of
85− Just (_, Alias aliasModule aliasIdent) -> qualifiedToJS identToJs (Qualified (Just aliasModule) aliasIdent)
86− _ -> JSVar . Ident . runProperName $ name
87−valueToJs _ _ _ (Constructor name) = qualifiedToJS runProperName name
88−valueToJs opts m e (Block sts) = JSApp (JSFunction Nothing [] (JSBlock (map (statementToJs opts m e) sts))) []
89−valueToJs opts m e (Case values binders) = bindersToJs opts m e binders (map (valueToJs opts m e) values)
90−valueToJs opts m e (IfThenElse cond th el) = JSConditional (valueToJs opts m e cond) (valueToJs opts m e th) (valueToJs opts m e el)
91−valueToJs opts m e (Accessor prop val) = JSAccessor prop (valueToJs opts m e val)
92−valueToJs opts m e (Indexer index val) = JSIndexer (valueToJs opts m e index) (valueToJs opts m e val)
93−valueToJs opts m e (App val args) = JSApp (valueToJs opts m e val) (map (valueToJs opts m e) args)
94−valueToJs opts m e (Abs args val) = JSFunction Nothing args (JSBlock [JSReturn (valueToJs opts m e val)])
95−valueToJs opts m e (TypedValue (Abs args val) ty) | optionsPerformRuntimeTypeChecks opts = JSFunction Nothing args (JSBlock $ runtimeTypeChecks args ty ++ [JSReturn (valueToJs opts m e val)])
96−valueToJs opts m e (Unary op val) = JSUnary op (valueToJs opts m e val)
97−valueToJs opts m e (Binary op v1 v2) = JSBinary op (valueToJs opts m e v1) (valueToJs opts m e v2)
98−valueToJs _ m e (Var ident) = varToJs m e ident
99−valueToJs opts m e (TypedValue val _) = valueToJs opts m e val
100−valueToJs _ _ _ (TypeClassDictionary _ _) = error "Type class dictionary was not replaced"
101−valueToJs _ _ _ _ = error "Invalid argument to valueToJs"
102−
103−runtimeTypeChecks :: [Ident] -> Type -> [JS]
104−runtimeTypeChecks args ty =
105− let
106− argTys = getFunctionArgumentTypes ty
107− in
108− concat $ zipWith argumentCheck (map JSVar args) argTys
109− where
110− getFunctionArgumentTypes :: Type -> [Type]
111− getFunctionArgumentTypes (Function funArgs _) = funArgs
112− getFunctionArgumentTypes (ForAll _ ty') = getFunctionArgumentTypes ty'
113− getFunctionArgumentTypes _ = []
114− argumentCheck :: JS -> Type -> [JS]
115− argumentCheck val Number = [typeCheck val "number"]
116− argumentCheck val String = [typeCheck val "string"]
117− argumentCheck val Boolean = [typeCheck val "boolean"]
118− argumentCheck val (Array _) = [arrayCheck val]
119− argumentCheck val (Object row) =
120− let
121− (pairs, _) = rowToList row
122− in
123− typeCheck val "object" : concatMap (\(prop, ty') -> argumentCheck (JSAccessor prop val) ty') pairs
124− argumentCheck val (Function _ _) = [typeCheck val "function"]
125− argumentCheck val (ForAll _ ty') = argumentCheck val ty'
126− argumentCheck _ _ = []
127− typeCheck :: JS -> String -> JS
128− typeCheck js ty' = JSIfElse (JSBinary NotEqualTo (JSTypeOf js) (JSStringLiteral ty')) (JSBlock [JSThrow (JSStringLiteral $ ty' ++ " expected")]) Nothing
129− arrayCheck :: JS -> JS
130− arrayCheck js = JSIfElse (JSUnary Not (JSApp (JSAccessor "isArray" (JSVar (Ident "Array"))) [js])) (JSBlock [JSThrow (JSStringLiteral "Array expected")]) Nothing
131−
132−varToJs :: ModuleName -> Environment -> Qualified Ident -> JS
133−varToJs m e qual@(Qualified _ ident) = case M.lookup (qualify m qual) (names e) of
134− Just (_, ty) | isExtern ty -> JSVar ident
135− Just (_, Alias aliasModule aliasIdent) -> qualifiedToJS identToJs (Qualified (Just aliasModule) aliasIdent)
136− _ -> qualifiedToJS identToJs qual
137− where
138− isExtern Extern = True
139− isExtern (Alias m' ident') = case M.lookup (m', ident') (names e) of
140− Just (_, ty') -> isExtern ty'
141− Nothing -> error "Undefined alias in varToJs"
142− isExtern _ = False
143−
144−qualifiedToJS :: (a -> String) -> Qualified a -> JS
145−qualifiedToJS f (Qualified (Just (ModuleName (ProperName m))) a) = JSAccessor (f a) (JSVar (Ident m))
146−qualifiedToJS f (Qualified Nothing a) = JSVar (Ident (f a))
147−
148−bindersToJs :: Options -> ModuleName -> Environment -> [([Binder], Maybe Guard, Value)] -> [JS] -> JS
149−bindersToJs opts m e binders vals = runGen (unusedNames (binders, vals)) $ do
150− valNames <- replicateM (length vals) fresh
151− jss <- forM binders $ \(bs, grd, result) -> go valNames [JSReturn (valueToJs opts m e result)] bs grd
152− return $ JSApp (JSFunction Nothing valNames (JSBlock (concat jss ++ [JSThrow (JSStringLiteral "Failed pattern match")])))
153− vals
154− where
155− go :: [Ident] -> [JS] -> [Binder] -> Maybe Guard -> Gen [JS]
156− go _ done [] Nothing = return done
157− go _ done [] (Just cond) = return [JSIfElse (valueToJs opts m e cond) (JSBlock done) Nothing]
158− go (v:vs) done' (b:bs) grd = do
159− done'' <- go vs done' bs grd
160− binderToJs m e v done'' b
161− go _ _ _ _ = error "Invalid arguments to bindersToJs"
162−
163−binderToJs :: ModuleName -> Environment -> Ident -> [JS] -> Binder -> Gen [JS]
164−binderToJs _ _ _ done NullBinder = return done
165−binderToJs _ _ varName done (StringBinder str) =
166− return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSStringLiteral str)) (JSBlock done) Nothing]
167−binderToJs _ _ varName done (NumberBinder num) =
168− return [JSIfElse (JSBinary EqualTo (JSVar varName) (JSNumericLiteral num)) (JSBlock done) Nothing]
169−binderToJs _ _ varName done (BooleanBinder True) =
170− return [JSIfElse (JSVar varName) (JSBlock done) Nothing]
171−binderToJs _ _ varName done (BooleanBinder False) =
172− return [JSIfElse (JSUnary Not (JSVar varName)) (JSBlock done) Nothing]
173−binderToJs _ _ varName done (VarBinder ident) =
174− return (JSVariableIntroduction ident (Just (JSVar varName)) : done)
175−binderToJs m _ varName done (NullaryBinder ctor) =
176− return [JSIfElse (JSBinary EqualTo (JSAccessor "ctor" (JSVar varName)) (JSStringLiteral (show ((\(mp, nm) -> Qualified (Just mp) nm) $ qualify m ctor)))) (JSBlock done) Nothing]
177−binderToJs m e varName done (UnaryBinder ctor b) = do
178− value <- fresh
179− js <- binderToJs m e value done b
180− return [JSIfElse (JSBinary EqualTo (JSAccessor "ctor" (JSVar varName)) (JSStringLiteral (show ((\(mp, nm) -> Qualified (Just mp) nm) $ qualify m ctor)))) (JSBlock (JSVariableIntroduction value (Just (JSAccessor "value" (JSVar varName))) : js)) Nothing]
181−binderToJs m e varName done (ObjectBinder bs) = go done bs
182− where
183− go :: [JS] -> [(String, Binder)] -> Gen [JS]
184− go done' [] = return done'
185− go done' ((prop, binder):bs') = do
186− propVar <- fresh
187− done'' <- go done' bs'
188− js <- binderToJs m e propVar done'' binder
189− return (JSVariableIntroduction propVar (Just (JSAccessor prop (JSVar varName))) : js)
190−binderToJs m e varName done (ArrayBinder bs) = do
191− js <- go done 0 bs
192− return [JSIfElse (JSBinary EqualTo (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left (fromIntegral $ length bs)))) (JSBlock js) Nothing]
193− where
194− go :: [JS] -> Integer -> [Binder] -> Gen [JS]
195− go done' _ [] = return done'
196− go done' index (binder:bs') = do
197− elVar <- fresh
198− done'' <- go done' (index + 1) bs'
199− js <- binderToJs m e elVar done'' binder
200− return (JSVariableIntroduction elVar (Just (JSIndexer (JSNumericLiteral (Left index)) (JSVar varName))) : js)
201−binderToJs m e varName done (ConsBinder headBinder tailBinder) = do
202− headVar <- fresh
203− tailVar <- fresh
204− js1 <- binderToJs m e headVar done headBinder
205− js2 <- binderToJs m e tailVar js1 tailBinder
206− return [JSIfElse (JSBinary GreaterThan (JSAccessor "length" (JSVar varName)) (JSNumericLiteral (Left 0))) (JSBlock
207− ( JSVariableIntroduction headVar (Just (JSIndexer (JSNumericLiteral (Left 0)) (JSVar varName))) :
208− JSVariableIntroduction tailVar (Just (JSApp (JSAccessor "slice" (JSVar varName)) [JSNumericLiteral (Left 1)])) :
209− js2
210− )) Nothing]
211−binderToJs m e varName done (NamedBinder ident binder) = do
212− js <- binderToJs m e varName done binder
213− return (JSVariableIntroduction ident (Just (JSVar varName)) : js)
214−
215−statementToJs :: Options -> ModuleName -> Environment -> Statement -> JS
216−statementToJs opts m e (VariableIntroduction ident value) = JSVariableIntroduction ident (Just (valueToJs opts m e value))
217−statementToJs opts m e (Assignment target value) = JSAssignment (JSAssignVariable target) (valueToJs opts m e value)
218−statementToJs opts m e (While cond sts) = JSWhile (valueToJs opts m e cond) (JSBlock (map (statementToJs opts m e) sts))
219−statementToJs opts m e (For ident start end sts) = JSFor ident (valueToJs opts m e start) (valueToJs opts m e end) (JSBlock (map (statementToJs opts m e) sts))
220−statementToJs opts m e (If ifst) = ifToJs ifst
221− where
222− ifToJs :: IfStatement -> JS
223− ifToJs (IfStatement cond thens elses) = JSIfElse (valueToJs opts m e cond) (JSBlock (map (statementToJs opts m e) thens)) (fmap elseToJs elses)
224− elseToJs :: ElseStatement -> JS
225− elseToJs (Else sts) = JSBlock (map (statementToJs opts m e) sts)
226− elseToJs (ElseIf elif) = ifToJs elif
227−statementToJs opts m e (Return value) = JSReturn (valueToJs opts m e value)
src/Language/PureScript/CodeGen/JS/AST.hsdeleted−56
@@ -1,56 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE DeriveDataTypeable #-}
16−
17−module Language.PureScript.CodeGen.JS.AST where
18−
19−import Language.PureScript.Names
20−import Language.PureScript.Values
21−
22−import Data.Data
23−
24−data JS
25− = JSNumericLiteral (Either Integer Double)
26− | JSStringLiteral String
27− | JSBooleanLiteral Bool
28− | JSUnary UnaryOperator JS
29− | JSBinary BinaryOperator JS JS
30− | JSArrayLiteral [JS]
31− | JSIndexer JS JS
32− | JSObjectLiteral [(String, JS)]
33− | JSAccessor String JS
34− | JSFunction (Maybe Ident) [Ident] JS
35− | JSApp JS [JS]
36− | JSVar Ident
37− | JSConditional JS JS JS
38− | JSBlock [JS]
39− | JSVariableIntroduction Ident (Maybe JS)
40− | JSAssignment JSAssignment JS
41− | JSWhile JS JS
42− | JSFor Ident JS JS JS
43− | JSIfElse JS JS (Maybe JS)
44− | JSReturn JS
45− | JSThrow JS
46− | JSTypeOf JS
47− | JSLabel String JS
48− | JSBreak String
49− | JSContinue String
50− | JSRaw String deriving (Show, Data, Typeable)
51−
52−data JSAssignment
53− = JSAssignVariable Ident
54− | JSAssignProperty String JSAssignment deriving (Show, Data, Typeable)
55−
56−
src/Language/PureScript/CodeGen/Monad.hsdeleted−32
@@ -1,32 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
16−
17−module Language.PureScript.CodeGen.Monad where
18−
19−import Control.Monad.State
20−import Control.Applicative
21−import Language.PureScript.Names
22−
23−newtype Gen a = Gen { unGen :: State [Ident] a } deriving (Functor, Applicative, Monad, MonadState [Ident])
24−
25−runGen :: [Ident] -> Gen a -> a
26−runGen names = flip evalState names . unGen
27−
28−fresh :: Gen Ident
29−fresh = do
30− (s:ss) <- get
31− put ss
32− return s
src/Language/PureScript/CodeGen/Optimize.hsdeleted−232
@@ -1,232 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.CodeGen.Optimize (
16− optimize
17−) where
18−
19−import Data.Data
20−import Data.Maybe (fromMaybe)
21−import Data.Generics
22−
23−import Language.PureScript.Names
24−import Language.PureScript.CodeGen.JS.AST
25−import Language.PureScript.Options
26−
27−optimize :: Options -> JS -> JS
28−optimize opts =
29− collapseNestedBlocks
30− . tco opts
31− . magicDo opts
32− . removeUnusedVariables
33− . unThunk
34− . etaConvert
35− . inlineVariables
36−
37−replaceIdent :: (Data d) => Ident -> JS -> d -> d
38−replaceIdent var1 js = everywhere (mkT replace)
39− where
40− replace (JSVar var2) | var1 == var2 = js
41− replace other = other
42−
43−replaceIdents :: (Data d) => [(Ident, JS)] -> d -> d
44−replaceIdents vars = everywhere (mkT replace)
45− where
46− replace v@(JSVar var) = fromMaybe v $ lookup var vars
47− replace other = other
48−
49−isReassigned :: (Data d) => Ident -> d -> Bool
50−isReassigned var1 = everything (||) (mkQ False check)
51− where
52− check :: JS -> Bool
53− check (JSFunction _ args _) | var1 `elem` args = True
54− check _ = False
55−
56−isRebound :: (Data d) => JS -> d -> Bool
57−isRebound (JSVar var1) = everything (||) (mkQ False check)
58− where
59− check :: JS -> Bool
60− check (JSFunction _ args _) | var1 `elem` args = True
61− check _ = False
62−isRebound _ = const False
63−
64−isUsed :: (Data d) => Ident -> d -> Bool
65−isUsed var1 = everything (||) (mkQ False check)
66− where
67− check :: JS -> Bool
68− check (JSVar var2) | var1 == var2 = True
69− check (JSAssignment target _) | var1 == targetVariable target = True
70− check _ = False
71− targetVariable :: JSAssignment -> Ident
72− targetVariable (JSAssignVariable var) = var
73− targetVariable (JSAssignProperty _ tgt) = targetVariable tgt
74−
75−shouldInline :: JS -> Bool
76−shouldInline (JSVar _) = True
77−shouldInline (JSNumericLiteral _) = True
78−shouldInline (JSStringLiteral _) = True
79−shouldInline (JSBooleanLiteral _) = True
80−shouldInline (JSAccessor _ val) = shouldInline val
81−shouldInline (JSIndexer index val) = shouldInline index && shouldInline val
82−shouldInline _ = False
83−
84−inlineVariables :: JS -> JS
85−inlineVariables = everywhere (mkT removeFromBlock)
86− where
87− removeFromBlock :: JS -> JS
88− removeFromBlock (JSBlock sts) = JSBlock (go sts)
89− removeFromBlock js = js
90− go :: [JS] -> [JS]
91− go [] = []
92− go (JSVariableIntroduction var (Just js) : sts) | shouldInline js && not (isReassigned var sts) && not (isRebound js sts) = go (replaceIdent var js sts)
93− go (s:sts) = s : go sts
94−
95−removeUnusedVariables :: JS -> JS
96−removeUnusedVariables = everywhere (mkT removeFromBlock)
97− where
98− removeFromBlock :: JS -> JS
99− removeFromBlock (JSBlock sts) = JSBlock (go sts)
100− removeFromBlock js = js
101− go :: [JS] -> [JS]
102− go [] = []
103− go (JSVariableIntroduction var _ : sts) | not (isUsed var sts) = go sts
104− go (s:sts) = s : go sts
105−
106−etaConvert :: JS -> JS
107−etaConvert = everywhere (mkT convert)
108− where
109− convert :: JS -> JS
110− convert (JSBlock [JSReturn (JSApp (JSFunction Nothing idents block@(JSBlock body)) args)])
111− | all shouldInline args && not (or (map (flip isRebound block) args)) = JSBlock (replaceIdents (zip idents args) body)
112− convert js = js
113−
114−unThunk :: JS -> JS
115−unThunk = everywhere (mkT convert)
116− where
117− convert :: JS -> JS
118− convert (JSBlock [JSReturn (JSApp (JSFunction Nothing [] (JSBlock body)) [])]) = JSBlock body
119− convert js = js
120−
121−tco :: Options -> JS -> JS
122−tco opts | optionsTco opts = tco'
123− | otherwise = id
124−
125−tco' :: JS -> JS
126−tco' = everywhere (mkT convert)
127− where
128− tcoLabel :: String
129− tcoLabel = "tco"
130− tcoVar :: Ident -> Ident
131− tcoVar (Ident arg) = Ident $ "__tco_" ++ arg
132− tcoVar _ = error "Invalid name in tcoVar"
133− copyVar :: Ident -> Ident
134− copyVar (Ident arg) = Ident $ "__copy_" ++ arg
135− copyVar _ = error "Invalid name in copyVar"
136− convert :: JS -> JS
137− convert js@(JSVariableIntroduction name (Just fn@(JSFunction _ _ _))) =
138− let
139− (argss, body', replace) = collectAllFunctionArgs [] id fn
140− in case () of
141− _ | isTailCall name body' ->
142− let
143− allArgs = reverse $ concat argss
144− in
145− JSVariableIntroduction name (Just (replace (toLoop name allArgs body')))
146− | otherwise -> js
147− convert js = js
148− collectAllFunctionArgs :: [[Ident]] -> (JS -> JS) -> JS -> ([[Ident]], JS, JS -> JS)
149− collectAllFunctionArgs allArgs f (JSFunction ident args (JSBlock (body@(JSReturn _):_))) =
150− collectAllFunctionArgs (args : allArgs) (\b -> f (JSFunction ident (map copyVar args) (JSBlock [b]))) body
151− collectAllFunctionArgs allArgs f (JSFunction ident args body@(JSBlock _)) =
152− (args : allArgs, body, \b -> f (JSFunction ident (map copyVar args) b))
153− collectAllFunctionArgs allArgs f (JSReturn (JSFunction ident args (JSBlock [body]))) =
154− collectAllFunctionArgs (args : allArgs) (\b -> f (JSReturn (JSFunction ident (map copyVar args) (JSBlock [b])))) body
155− collectAllFunctionArgs allArgs f (JSReturn (JSFunction ident args body@(JSBlock _))) =
156− (args : allArgs, body, \b -> f (JSReturn (JSFunction ident (map copyVar args) b)))
157− collectAllFunctionArgs allArgs f body = (allArgs, body, f)
158− isTailCall :: Ident -> JS -> Bool
159− isTailCall ident js =
160− let
161− numSelfCalls = everything (+) (mkQ 0 countSelfCalls) js
162− numSelfCallsInTailPosition = everything (+) (mkQ 0 countSelfCallsInTailPosition) js
163− numSelfCallsUnderFunctions = everything (+) (mkQ 0 countSelfCallsUnderFunctions) js
164− in
165− numSelfCalls > 0
166− && numSelfCalls == numSelfCallsInTailPosition
167− && numSelfCallsUnderFunctions == 0
168− where
169− countSelfCalls :: JS -> Int
170− countSelfCalls (JSApp (JSVar ident') _) | ident == ident' = 1
171− countSelfCalls _ = 0
172− countSelfCallsInTailPosition :: JS -> Int
173− countSelfCallsInTailPosition (JSReturn ret) | isSelfCall ident ret = 1
174− countSelfCallsInTailPosition _ = 0
175− countSelfCallsUnderFunctions (JSFunction _ _ js') = everything (+) (mkQ 0 countSelfCalls) js'
176− countSelfCallsUnderFunctions _ = 0
177− toLoop :: Ident -> [Ident] -> JS -> JS
178− toLoop ident allArgs js = JSBlock $
179− map (\arg -> JSVariableIntroduction arg (Just (JSVar (copyVar arg)))) allArgs ++
180− [ JSLabel tcoLabel $ JSWhile (JSBooleanLiteral True) (JSBlock [ everywhere (mkT loopify) js ]) ]
181− where
182− loopify :: JS -> JS
183− loopify (JSReturn ret) | isSelfCall ident ret =
184− let
185− allArgumentValues = concat $ collectSelfCallArgs [] ret
186− in
187− JSBlock $ zipWith (\val arg ->
188− JSVariableIntroduction (tcoVar arg) (Just val)) allArgumentValues allArgs
189− ++ map (\arg ->
190− JSAssignment (JSAssignVariable arg) (JSVar (tcoVar arg))) allArgs
191− ++ [ JSContinue tcoLabel ]
192− loopify other = other
193− collectSelfCallArgs :: [[JS]] -> JS -> [[JS]]
194− collectSelfCallArgs allArgumentValues (JSApp fn args') = collectSelfCallArgs (args' : allArgumentValues) fn
195− collectSelfCallArgs allArgumentValues _ = allArgumentValues
196− isSelfCall :: Ident -> JS -> Bool
197− isSelfCall ident (JSApp (JSVar ident') _) | ident == ident' = True
198− isSelfCall ident (JSApp fn _) = isSelfCall ident fn
199− isSelfCall _ _ = False
200−
201−magicDo :: Options -> JS -> JS
202−magicDo opts | optionsMagicDo opts = magicDo'
203− | otherwise = id
204−
205−magicDo' :: JS -> JS
206−magicDo' = everywhere (mkT undo) . everywhere' (mkT convert)
207− where
208− fnName = Ident "__do"
209− convert :: JS -> JS
210− convert (JSApp (JSApp ret [val]) []) | isReturn ret = val
211− convert (JSApp (JSApp bind [m]) [JSFunction Nothing [Ident "_"] (JSBlock [JSReturn ret])]) | isBind bind =
212− JSFunction (Just fnName) [] $ JSBlock [ JSApp m [], JSReturn (JSApp ret []) ]
213− convert (JSApp (JSApp bind [m]) [JSFunction Nothing [arg] (JSBlock [JSReturn ret])]) | isBind bind =
214− JSFunction (Just fnName) [] $ JSBlock [ JSVariableIntroduction arg (Just (JSApp m [])), JSReturn (JSApp ret []) ]
215− convert other = other
216− isBind (JSAccessor "bind" (JSAccessor "eff" (JSVar (Ident "Eff")))) = True
217− isBind _ = False
218− isReturn (JSAccessor "ret" (JSAccessor "eff" (JSVar (Ident "Eff")))) = True
219− isReturn _ = False
220− undo :: JS -> JS
221− undo (JSReturn (JSApp (JSFunction (Just ident) [] body) [])) | ident == fnName = body
222− undo other = other
223−
224−collapseNestedBlocks :: JS -> JS
225−collapseNestedBlocks = everywhere (mkT collapse)
226− where
227− collapse :: JS -> JS
228− collapse (JSBlock sts) = JSBlock (concatMap go sts)
229− collapse js = js
230− go :: JS -> [JS]
231− go (JSBlock sts) = sts
232− go s = [s]
src/Language/PureScript/Declarations.hsdeleted−48
@@ -1,48 +0,0 @@
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−-- |
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−type Precedence = Integer
28−
29−data Associativity = Infixl | Infixr deriving (Show, D.Data, D.Typeable)
30−
31−data Fixity = Fixity Associativity Precedence deriving (Show, D.Data, D.Typeable)
32−
33−data Module = Module ProperName [Declaration] deriving (Show, D.Data, D.Typeable)
34−
35−data Declaration
36− = DataDeclaration ProperName [String] [(ProperName, Maybe Type)]
37− | DataBindingGroupDeclaration [(ProperName, [String], [(ProperName, Maybe Type)])]
38− | TypeSynonymDeclaration ProperName [String] Type
39− | TypeDeclaration Ident Type
40− | ValueDeclaration Ident [[Binder]] (Maybe Guard) Value
41− | BindingGroupDeclaration [(Ident, Value)]
42− | ExternDeclaration Ident (Maybe JS) Type
43− | ExternDataDeclaration ProperName Kind
44− | FixityDeclaration Fixity String
45− | ImportDeclaration ModuleName (Maybe [Either Ident ProperName])
46− | TypeClassDeclaration ProperName String [Declaration]
47− | TypeInstanceDeclaration [(Qualified ProperName, Type)] (Qualified ProperName) Type [Declaration]
48− deriving (Show, D.Data, D.Typeable)
src/Language/PureScript/Kinds.hsdeleted−27
@@ -1,27 +0,0 @@
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−import Language.PureScript.Unknown
21−
22−data Kind
23− = KUnknown (Unknown Kind)
24− | Star
25− | Bang
26− | Row Kind
27− | FunKind Kind Kind deriving (Show, Eq, Data, Typeable)
src/Language/PureScript/Names.hsdeleted−45
@@ -1,45 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE DeriveDataTypeable #-}
16−
17−module Language.PureScript.Names where
18−
19−import Data.Data
20−
21−data Ident = Ident String | Op String deriving (Eq, Ord, Data, Typeable)
22−
23−instance Show Ident where
24− show (Ident s) = s
25− show (Op op) = '(':op ++ ")"
26−
27−newtype ProperName = ProperName { runProperName :: String } deriving (Eq, Ord, Data, Typeable)
28−
29−instance Show ProperName where
30− show = runProperName
31−
32−data ModuleName = ModuleName ProperName deriving (Eq, Ord, Data, Typeable)
33−
34−instance Show ModuleName where
35− show (ModuleName name) = show name
36−
37−data Qualified a = Qualified (Maybe ModuleName) a deriving (Eq, Ord, Data, Typeable)
38−
39−instance (Show a) => Show (Qualified a) where
40− show (Qualified Nothing a) = show a
41− show (Qualified (Just (ModuleName name)) a) = show name ++ "." ++ show a
42−
43−qualify :: ModuleName -> Qualified a -> (ModuleName, a)
44−qualify m (Qualified Nothing a) = (m, a)
45−qualify _ (Qualified (Just m) a) = (m, a)
src/Language/PureScript/Options.hsdeleted−25
@@ -1,25 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Options where
16−
17−data Options = Options
18− { optionsTco :: Bool
19− , optionsPerformRuntimeTypeChecks :: Bool
20− , optionsMagicDo :: Bool
21− , optionsRunMain :: Bool
22− } deriving Show
23−
24−defaultOptions :: Options
25−defaultOptions = Options False False False False
src/Language/PureScript/Parser.hsdeleted−22
@@ -1,22 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Parser (module P) where
16−
17−import Language.PureScript.Parser.Common as P
18−import Language.PureScript.Parser.Types as P
19−import Language.PureScript.Parser.Values as P
20−import Language.PureScript.Parser.State as P
21−import Language.PureScript.Parser.Kinds as P
22−import Language.PureScript.Parser.Declarations as P
src/Language/PureScript/Parser/Common.hsdeleted−256
@@ -1,256 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE FlexibleContexts #-}
16−
17−module Language.PureScript.Parser.Common where
18−
19−import Data.Functor.Identity
20−import Control.Applicative
21−import Control.Monad
22−import Language.PureScript.Parser.State
23−import qualified Text.Parsec as P
24−import qualified Text.Parsec.Token as PT
25−
26−import Language.PureScript.Names
27−
28−reservedNames :: [String]
29−reservedNames = [ "case"
30− , "of"
31− , "data"
32− , "type"
33− , "var"
34− , "val"
35− , "while"
36− , "for"
37− , "foreach"
38− , "if"
39− , "then"
40− , "else"
41− , "return"
42− , "true"
43− , "false"
44− , "foreign"
45− , "import"
46− , "member"
47− , "forall"
48− , "do"
49− , "until"
50− , "in"
51− , "break"
52− , "catch"
53− , "continue"
54− , "debugger"
55− , "default"
56− , "delete"
57− , "finally"
58− , "function"
59− , "instanceof"
60− , "new"
61− , "switch"
62− , "this"
63− , "throw"
64− , "try"
65− , "typeof"
66− , "void"
67− , "with"
68− , "Number"
69− , "String"
70− , "Boolean"
71− , "infixl"
72− , "infixr"
73− , "module"
74− , "let"
75− , "class"
76− , "instance"
77− , "where" ]
78−
79−builtInOperators :: [String]
80−builtInOperators = [ "~", "-", "<=", ">=", "<", ">", "*", "/", "%", "++", "+", "<<", ">>>", ">>"
81− , "==", "!=", "&&", "||", "&", "^", "|", "!!", "!" ]
82−
83−reservedOpNames :: [String]
84−reservedOpNames = builtInOperators ++ [ "=>", "->", "=", ".", "\\" ]
85−
86−identStart :: P.Parsec String u Char
87−identStart = P.lower <|> P.oneOf "_"
88−
89−properNameStart :: P.Parsec String u Char
90−properNameStart = P.upper
91−
92−identLetter :: P.Parsec String u Char
93−identLetter = P.alphaNum <|> P.oneOf "_'"
94−
95−opStart :: P.Parsec String u Char
96−opStart = P.oneOf ":!#$%&*+./<=>?@\\^|-~"
97−
98−opLetter :: P.Parsec String u Char
99−opLetter = P.oneOf ":!#$%&*+./<=>?@\\^|-~"
100−
101−langDef :: PT.GenLanguageDef String u Identity
102−langDef = PT.LanguageDef
103− { PT.reservedNames = reservedNames
104− , PT.reservedOpNames = reservedOpNames
105− , PT.commentStart = "{-"
106− , PT.commentEnd = "-}"
107− , PT.commentLine = "--"
108− , PT.nestedComments = True
109− , PT.identStart = identStart
110− , PT.identLetter = identLetter
111− , PT.opStart = opStart
112− , PT.opLetter = opLetter
113− , PT.caseSensitive = True
114− }
115−
116−tokenParser :: PT.GenTokenParser String u Identity
117−tokenParser = PT.makeTokenParser langDef
118−
119−lexeme :: P.Parsec String u a -> P.Parsec String u a
120−lexeme = PT.lexeme tokenParser
121−
122−identifier :: P.Parsec String u String
123−identifier = PT.identifier tokenParser
124−
125−reserved :: String -> P.Parsec String u ()
126−reserved = PT.reserved tokenParser
127−
128−reservedOp :: String -> P.Parsec String u ()
129−reservedOp = PT.reservedOp tokenParser
130−
131−operator :: P.Parsec String u String
132−operator = PT.operator tokenParser
133−
134−stringLiteral :: P.Parsec String u String
135−stringLiteral = PT.stringLiteral tokenParser
136−
137−whiteSpace :: P.Parsec String u ()
138−whiteSpace = PT.whiteSpace tokenParser
139−
140−semi :: P.Parsec String u String
141−semi = PT.semi tokenParser
142−
143−colon :: P.Parsec String u String
144−colon = PT.colon tokenParser
145−
146−dot :: P.Parsec String u String
147−dot = PT.dot tokenParser
148−
149−comma :: P.Parsec String u String
150−comma = PT.comma tokenParser
151−
152−tick :: P.Parsec String u Char
153−tick = lexeme $ P.char '`'
154−
155−pipe :: P.Parsec String u Char
156−pipe = lexeme $ P.char '|'
157−
158−natural :: P.Parsec String u Integer
159−natural = PT.natural tokenParser
160−
161−squares :: P.Parsec String ParseState a -> P.Parsec String ParseState a
162−squares = P.between (lexeme $ P.char '[') (lexeme $ indented *> P.char ']') . (indented *>)
163−
164−parens :: P.Parsec String ParseState a -> P.Parsec String ParseState a
165−parens = P.between (lexeme $ P.char '(') (lexeme $ indented *> P.char ')') . (indented *>)
166−
167−braces :: P.Parsec String ParseState a -> P.Parsec String ParseState a
168−braces = P.between (lexeme $ P.char '{') (lexeme $ indented *> P.char '}') . (indented *>)
169−
170−angles :: P.Parsec String ParseState a -> P.Parsec String ParseState a
171−angles = P.between (lexeme $ P.char '<') (lexeme $ indented *> P.char '>') . (indented *>)
172−
173−sepBy :: P.Parsec String ParseState a -> P.Parsec String ParseState sep -> P.Parsec String ParseState [a]
174−sepBy p s = P.sepBy (indented *> p) (indented *> s)
175−
176−sepBy1 :: P.Parsec String ParseState a -> P.Parsec String ParseState sep -> P.Parsec String ParseState [a]
177−sepBy1 p s = P.sepBy1 (indented *> p) (indented *> s)
178−
179−semiSep :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
180−semiSep = flip sepBy semi
181−
182−semiSep1 :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
183−semiSep1 = flip sepBy1 semi
184−
185−commaSep :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
186−commaSep = flip sepBy comma
187−
188−commaSep1 :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
189−commaSep1 = flip sepBy1 comma
190−
191−properName :: P.Parsec String u ProperName
192−properName = lexeme $ ProperName <$> P.try ((:) <$> P.upper <*> many (PT.identLetter langDef) P.<?> "name")
193−
194−parseQualified :: P.Parsec String ParseState a -> P.Parsec String ParseState (Qualified a)
195−parseQualified parser = qual
196− where
197− qual = (Qualified <$> (Just . ModuleName <$> P.try (properName <* delimiter)) <*> parser)
198− <|> (Qualified Nothing <$> P.try parser)
199− delimiter = indented *> dot
200−
201−integerOrFloat :: P.Parsec String u (Either Integer Double)
202−integerOrFloat = (Left <$> P.try (PT.natural tokenParser) <|>
203− Right <$> P.try (PT.float tokenParser)) P.<?> "number"
204−
205−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
206−augment p q f = flip (maybe id $ flip f) <$> p <*> P.optionMaybe q
207−
208−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
209−fold first more combine = do
210− a <- first
211− bs <- P.many more
212− return $ foldl combine a bs
213−
214−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
215−buildPostfixParser fs first = do
216− a <- first
217− go a
218− where
219− go a = do
220− maybeA <- P.optionMaybe $ P.choice (map ($ a) fs)
221− case maybeA of
222− Nothing -> return a
223− Just a' -> go a'
224−
225−operatorOrBuiltIn :: P.Parsec String u String
226−operatorOrBuiltIn = P.try operator <|> P.choice (map (\s -> P.try (reservedOp s) >> return s) builtInOperators)
227−
228−parseIdent :: P.Parsec String ParseState Ident
229−parseIdent = (Ident <$> identifier) <|> (Op <$> parens operatorOrBuiltIn)
230−
231−parseIdentInfix :: P.Parsec String ParseState (Qualified Ident)
232−parseIdentInfix = (P.between tick tick (parseQualified (Ident <$> identifier))) <|> parseQualified (Op <$> operatorOrBuiltIn)
233−
234−mark :: P.Parsec String ParseState a -> P.Parsec String ParseState a
235−mark p = do
236− current <- indentationLevel <$> P.getState
237− pos <- P.sourceColumn <$> P.getPosition
238− P.modifyState $ \st -> st { indentationLevel = pos }
239− a <- p
240− P.modifyState $ \st -> st { indentationLevel = current }
241− return a
242−
243−checkIndentation :: (P.Column -> P.Column -> Bool) -> P.Parsec String ParseState ()
244−checkIndentation rel = do
245− col <- P.sourceColumn <$> P.getPosition
246− current <- indentationLevel <$> P.getState
247− guard (col `rel` current)
248−
249−indented :: P.Parsec String ParseState ()
250−indented = checkIndentation (>) P.<?> "indentation"
251−
252−same :: P.Parsec String ParseState ()
253−same = checkIndentation (==) P.<?> "no indentation"
254−
255−runIndentParser :: P.Parsec String ParseState a -> String -> Either P.ParseError a
256−runIndentParser p = P.runParser p (ParseState 0) ""
src/Language/PureScript/Parser/Declarations.hsdeleted−145
@@ -1,145 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Parser.Declarations (
16− parseDeclaration,
17− parseModule,
18− parseModules
19−) where
20−
21−import Data.Maybe (fromMaybe)
22−import Control.Applicative
23−import qualified Text.Parsec as P
24−
25−import Language.PureScript.Names
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.Parser.JS
33−import Language.PureScript.CodeGen.JS.AST
34−import Language.PureScript.Values
35−
36−parseDataDeclaration :: P.Parsec String ParseState Declaration
37−parseDataDeclaration = do
38− reserved "data"
39− name <- indented *> properName
40− tyArgs <- many (indented *> identifier)
41− _ <- lexeme $ indented *> P.char '='
42− ctors <- sepBy1 ((,) <$> properName <*> P.optionMaybe (indented *> parsePolyType)) pipe
43− return $ DataDeclaration name tyArgs ctors
44−
45−parseTypeDeclaration :: P.Parsec String ParseState Declaration
46−parseTypeDeclaration =
47− TypeDeclaration <$> P.try (parseIdent <* lexeme (indented *> P.string "::"))
48− <*> parsePolyType
49−
50−parseTypeSynonymDeclaration :: P.Parsec String ParseState Declaration
51−parseTypeSynonymDeclaration =
52− TypeSynonymDeclaration <$> (P.try (reserved "type") *> indented *> properName)
53− <*> many (indented *> identifier)
54− <*> (lexeme (indented *> P.char '=') *> parsePolyType)
55−
56−parseValueDeclaration :: P.Parsec String ParseState Declaration
57−parseValueDeclaration =
58− ValueDeclaration <$> parseIdent
59− <*> P.many parseTopLevelBinder
60− <*> P.optionMaybe parseGuard
61− <*> ((lexeme (indented *> P.char '=')) *> parseValue)
62−
63−parseTopLevelBinder :: P.Parsec String ParseState [Binder]
64−parseTopLevelBinder = return <$> P.try parseBinderNoParens <|> parens (commaSep parseBinder)
65−
66−parseExternDeclaration :: P.Parsec String ParseState Declaration
67−parseExternDeclaration = P.try (reserved "foreign") *> indented *> (reserved "import") *> indented *>
68− (ExternDataDeclaration <$> (P.try (reserved "data") *> indented *> properName)
69− <*> (lexeme (indented *> P.string "::") *> parseKind)
70− <|> ExternDeclaration <$> parseIdent
71− <*> P.optionMaybe (parseJSLiteral <$> stringLiteral)
72− <*> (lexeme (indented *> P.string "::") *> parsePolyType))
73−
74−parseJSLiteral :: String -> JS
75−parseJSLiteral s = either (const $ JSRaw s) id $ P.runParser parseJS () "Javascript" s
76−
77−parseAssociativity :: P.Parsec String ParseState Associativity
78−parseAssociativity =
79− (P.try (reserved "infixl") >> return Infixl) <|>
80− (P.try (reserved "infixr") >> return Infixr)
81−
82−parseFixity :: P.Parsec String ParseState Fixity
83−parseFixity = Fixity <$> parseAssociativity <*> (indented *> natural)
84−
85−parseFixityDeclaration :: P.Parsec String ParseState Declaration
86−parseFixityDeclaration = do
87− fixity <- parseFixity
88− indented
89− name <- operator
90− return $ FixityDeclaration fixity name
91−
92−parseImportDeclaration :: P.Parsec String ParseState Declaration
93−parseImportDeclaration = do
94− reserved "import"
95− indented
96− moduleName <- ModuleName <$> properName
97− idents <- P.optionMaybe $ parens $ commaSep1 (Left <$> parseIdent <|> Right <$> properName)
98− return $ ImportDeclaration moduleName idents
99−
100−parseTypeClassDeclaration :: P.Parsec String ParseState Declaration
101−parseTypeClassDeclaration = do
102− reserved "class"
103− className <- indented *> properName
104− ident <- indented *> identifier
105− indented *> reserved "where"
106− members <- mark (P.many (same *> parseTypeDeclaration))
107− return $ TypeClassDeclaration className ident members
108−
109−parseTypeInstanceDeclaration :: P.Parsec String ParseState Declaration
110−parseTypeInstanceDeclaration = do
111− reserved "instance"
112− deps <- P.optionMaybe $ do
113− deps <- parens (commaSep1 ((,) <$> parseQualified properName <*> parseType))
114− indented
115− reservedOp "=>"
116− return deps
117− className <- indented *> parseQualified properName
118− ty <- indented *> parseType
119− indented *> reserved "where"
120− members <- mark (P.many (same *> parseValueDeclaration))
121− return $ TypeInstanceDeclaration (fromMaybe [] deps) className ty members
122−
123−parseDeclaration :: P.Parsec String ParseState Declaration
124−parseDeclaration = P.choice
125− [ parseDataDeclaration
126− , parseTypeDeclaration
127− , parseTypeSynonymDeclaration
128− , parseValueDeclaration
129− , parseExternDeclaration
130− , parseFixityDeclaration
131− , parseImportDeclaration
132− , parseTypeClassDeclaration
133− , parseTypeInstanceDeclaration ] P.<?> "declaration"
134−
135−parseModule :: P.Parsec String ParseState Module
136−parseModule = do
137− reserved "module"
138− indented
139− name <- properName
140− _ <- lexeme $ P.string "where"
141− decls <- mark (P.many (same *> parseDeclaration))
142− return $ Module name decls
143−
144−parseModules :: P.Parsec String ParseState [Module]
145−parseModules = whiteSpace *> mark (P.many (same *> parseModule)) <* P.eof
src/Language/PureScript/Parser/JS.hsdeleted−169
@@ -1,169 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Language.PureScript.Parser.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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Parser.JS (
16− parseJS
17−) where
18−
19−import Language.PureScript.Values
20−import Language.PureScript.Names
21−import Language.PureScript.CodeGen.JS.AST
22−import qualified Language.PureScript.Parser.Common as C
23−import Control.Applicative
24−import Data.Functor.Identity
25−import qualified Text.Parsec as P
26−import qualified Text.Parsec.Token as P
27−import qualified Text.Parsec.Expr as P
28−
29−booleanLiteral :: P.Parsec String u Bool
30−booleanLiteral = (C.reserved "true" >> return True) P.<|> (C.reserved "false" >> return False)
31−
32−parseNumericLiteral :: P.Parsec String u JS
33−parseNumericLiteral = JSNumericLiteral <$> C.integerOrFloat
34−
35−parseStringLiteral :: P.Parsec String u JS
36−parseStringLiteral = JSStringLiteral <$> C.stringLiteral
37−
38−parseBooleanLiteral :: P.Parsec String u JS
39−parseBooleanLiteral = JSBooleanLiteral <$> booleanLiteral
40−
41−parseArrayLiteral :: P.Parsec String u JS
42−parseArrayLiteral = JSArrayLiteral <$> P.squares C.tokenParser (P.commaSep C.tokenParser parseJS)
43−
44−parseObjectLiteral :: P.Parsec String u JS
45−parseObjectLiteral = JSObjectLiteral <$> P.braces C.tokenParser (P.commaSep C.tokenParser parseIdentifierAndValue)
46−
47−parseIdentifierAndValue :: P.Parsec String u (String, JS)
48−parseIdentifierAndValue = (,) <$> (C.identifier <* C.colon)
49− <*> parseJS
50−
51−parseFunction :: P.Parsec String u JS
52−parseFunction = do
53− C.reserved "function"
54− name <- P.optionMaybe (Ident <$> C.identifier)
55− args <- P.parens C.tokenParser $ P.commaSep C.tokenParser (Ident <$> C.identifier)
56− body <- parseJS
57− return $ JSFunction name args body
58−
59−parseBlock :: P.Parsec String u JS
60−parseBlock = JSBlock <$> P.braces C.tokenParser (P.many parseJS)
61−
62−parseVar :: P.Parsec String u JS
63−parseVar = JSVar <$> Ident <$> C.identifier
64−
65−parseJSAtom :: P.Parsec String u JS
66−parseJSAtom = P.choice
67− [ P.try parseNumericLiteral
68− , P.try parseStringLiteral
69− , P.try parseBooleanLiteral
70− , parseArrayLiteral
71− , P.try parseObjectLiteral
72− , parseFunction
73− , parseBlock
74− , P.try parseVar
75− , parseVariableIntroduction
76− , P.try parseAssignment
77− , parseWhile
78− , parseIf
79− , parseReturn
80− , P.parens C.tokenParser parseJS ]
81−
82−parseAccessor :: JS -> P.Parsec String u JS
83−parseAccessor js = P.try $ flip JSAccessor js <$> (C.dot *> P.notFollowedBy C.opLetter *> C.identifier)
84−
85−parseIndexer :: JS -> P.Parsec String u JS
86−parseIndexer js = P.try $ flip JSIndexer js <$> (P.squares C.tokenParser parseJS)
87−
88−parseConditional :: JS -> P.Parsec String u JS
89−parseConditional js = P.try $ do
90− _ <- C.lexeme $ P.char '?'
91− tr <- parseJS
92− _ <- C.lexeme $ P.char ':'
93− fa <- parseJS
94− return $ JSConditional js tr fa
95−
96−binary :: BinaryOperator -> String -> P.Assoc -> P.Operator String u Identity JS
97−binary op s f = P.Infix (P.try $ C.reservedOp s >> return (JSBinary op)) f
98−
99−unary :: UnaryOperator -> String -> P.Operator String u Identity JS
100−unary op s = P.Prefix (P.try $ C.reservedOp s >> return (JSUnary op))
101−
102−parseJS :: P.Parsec String u JS
103−parseJS =
104− (P.buildExpressionParser operators
105− . C.buildPostfixParser postfixTable2
106− $ indexersAndAccessors) P.<?> "javascript"
107− where
108− indexersAndAccessors = C.buildPostfixParser postfixTable1 parseJSAtom
109− postfixTable1 = [ parseAccessor, parseIndexer, parseConditional ]
110− postfixTable2 = [ \v -> P.try $ JSApp v <$> (P.parens C.tokenParser (P.commaSep C.tokenParser parseJS)) ]
111− operators = [ [ binary LessThan "<" P.AssocLeft]
112− , [ binary LessThanOrEqualTo "<=" P.AssocLeft]
113− , [ binary GreaterThan ">" P.AssocLeft]
114− , [ binary GreaterThanOrEqualTo ">=" P.AssocLeft]
115− , [ unary Not "!" ]
116− , [ unary BitwiseNot "~" ]
117− , [ unary Negate "-" ]
118− , [ unary Positive "+" ]
119− , [ binary Multiply "*" P.AssocLeft]
120− , [ binary Divide "/" P.AssocLeft]
121− , [ binary Modulus "%" P.AssocLeft]
122− , [ binary Concat "+" P.AssocLeft]
123− , [ binary Add "+" P.AssocLeft]
124− , [ binary Subtract "-" P.AssocLeft]
125− , [ binary ShiftLeft "<<" P.AssocLeft]
126− , [ binary ShiftRight ">>" P.AssocLeft]
127− , [ binary ZeroFillShiftRight ">>>" P.AssocLeft]
128− , [ binary EqualTo "===" P.AssocLeft]
129− , [ binary NotEqualTo "!==" P.AssocLeft]
130− , [ binary BitwiseAnd "&" P.AssocLeft]
131− , [ binary BitwiseXor "^" P.AssocLeft]
132− , [ binary BitwiseOr "|" P.AssocLeft]
133− , [ binary And "&&" P.AssocRight]
134− , [ binary Or "||" P.AssocRight]
135− ]
136−
137−parseVariableIntroduction :: P.Parsec String u JS
138−parseVariableIntroduction = do
139− C.reserved "var"
140− name <- Ident <$> P.identifier C.tokenParser
141− value <- P.optionMaybe $ do
142− _ <- C.lexeme $ P.char '='
143− value <- parseJS
144− _ <- C.semi
145− return value
146− return $ JSVariableIntroduction name value
147−
148−parseAssignment :: P.Parsec String u JS
149−parseAssignment = do
150− tgt <- parseAssignmentTarget
151− _ <- C.lexeme $ P.char '='
152− value <- parseJS
153− _ <- C.semi
154− return $ JSAssignment tgt value
155−
156−parseAssignmentTarget :: P.Parsec String u JSAssignment
157−parseAssignmentTarget = C.buildPostfixParser [] (JSAssignVariable <$> Ident <$> P.identifier C.tokenParser)
158−
159−parseWhile :: P.Parsec String u JS
160−parseWhile = JSWhile <$> (C.reserved "while" *> P.parens C.tokenParser parseJS)
161− <*> parseJS
162−
163−parseIf :: P.Parsec String u JS
164−parseIf = JSIfElse <$> (C.reserved "if" *> P.parens C.tokenParser parseJS)
165− <*> parseJS
166− <*> P.optionMaybe (C.reserved "else" >> parseJS)
167−
168−parseReturn :: P.Parsec String u JS
169−parseReturn = JSReturn <$> (C.reserved "return" *> parseJS <* C.semi)
src/Language/PureScript/Parser/Kinds.hsdeleted−42
@@ -1,42 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Parser.Kinds (
16− parseKind
17−) where
18−
19−import Language.PureScript.Kinds
20−import Language.PureScript.Parser.State
21−import Language.PureScript.Parser.Common
22−import Control.Applicative
23−import qualified Text.Parsec as P
24−import qualified Text.Parsec.Expr as P
25−
26−parseStar :: P.Parsec String ParseState Kind
27−parseStar = const Star <$> lexeme (P.char '*')
28−
29−parseBang :: P.Parsec String ParseState Kind
30−parseBang = const Bang <$> lexeme (P.char '!')
31−
32−parseTypeAtom :: P.Parsec String ParseState Kind
33−parseTypeAtom = indented *> P.choice (map P.try
34− [ parseStar
35− , parseBang
36− , parens parseKind ])
37−
38−parseKind :: P.Parsec String ParseState Kind
39−parseKind = P.buildExpressionParser operators parseTypeAtom P.<?> "kind"
40− where
41− operators = [ [ P.Prefix (lexeme (P.char '#') >> return Row) ]
42− , [ P.Infix (lexeme (P.try (P.string "->")) >> return FunKind) P.AssocRight ] ]
src/Language/PureScript/Parser/State.hsdeleted−22
@@ -1,22 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Parser.State where
16−
17−import qualified Text.Parsec as P
18−
19−data ParseState = ParseState
20− { indentationLevel :: P.Column } deriving Show
21−
22−
src/Language/PureScript/Parser/Types.hsdeleted−119
@@ -1,119 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Parser.Types (
16− parseType,
17− parsePolyType,
18− parseRow
19−) where
20−
21−import Language.PureScript.Types
22−import Language.PureScript.Parser.State
23−import Language.PureScript.Parser.Common
24−import Control.Applicative
25−import qualified Text.Parsec as P
26−import qualified Text.Parsec.Expr as P
27−import Control.Monad (unless)
28−
29−parseNumber :: P.Parsec String ParseState Type
30−parseNumber = const Number <$> reserved "Number"
31−
32−parseString :: P.Parsec String ParseState Type
33−parseString = const String <$> reserved "String"
34−
35−parseBoolean :: P.Parsec String ParseState Type
36−parseBoolean = const Boolean <$> reserved "Boolean"
37−
38−parseArray :: P.Parsec String ParseState Type
39−parseArray = squares $ Array <$> parseType
40−
41−parseObject :: P.Parsec String ParseState Type
42−parseObject = braces $ Object <$> parseRow
43−
44−parseFunction :: P.Parsec String ParseState Type
45−parseFunction = do
46− args <- lexeme $ parens $ commaSep parsePolyType
47− _ <- lexeme $ P.string "->"
48− resultType <- parseType
49− return $ Function args resultType
50−
51−parseTypeVariable :: P.Parsec String ParseState Type
52−parseTypeVariable = TypeVar <$> identifier
53−
54−parseTypeConstructor :: P.Parsec String ParseState Type
55−parseTypeConstructor = TypeConstructor <$> parseQualified properName
56−
57−parseForAll :: P.Parsec String ParseState Type
58−parseForAll = (mkForAll <$> (P.try (reserved "forall") *> P.many1 (indented *> identifier) <* indented <* dot)
59− <*> parseConstrainedType)
60−
61−parseTypeAtom :: P.Parsec String ParseState Type
62−parseTypeAtom = indented *> P.choice (map P.try
63− [ parseNumber
64− , parseString
65− , parseBoolean
66− , parseArray
67− , parseObject
68− , parseFunction
69− , parseTypeVariable
70− , parseTypeConstructor
71− , parseForAll
72− , parens parseRow
73− , parens parseType ])
74−
75−parseConstrainedType :: P.Parsec String ParseState Type
76−parseConstrainedType = do
77− constraints <- P.optionMaybe . P.try $ do
78− constraints <- parens . commaSep1 $ do
79− className <- parseQualified properName
80− indented
81− ty <- parseType
82− return (className, ty)
83− _ <- lexeme $ P.string "=>"
84− return constraints
85− indented
86− ty <- parseType
87− return $ maybe ty (flip ConstrainedType ty) constraints
88−
89−parseAnyType :: P.Parsec String ParseState Type
90−parseAnyType = (P.buildExpressionParser operators . buildPostfixParser postfixTable $ parseTypeAtom) P.<?> "type"
91− where
92− postfixTable :: [Type -> P.Parsec String ParseState Type]
93− postfixTable = [ \x -> TypeApp x <$> P.try (indented *> parseTypeAtom) ]
94− operators = [ [ P.Infix (lexeme (P.try (P.string "->")) >> return (\t1 t2 -> Function [t1] t2)) P.AssocRight ] ]
95−
96−parseType :: P.Parsec String ParseState Type
97−parseType = do
98− ty <- parseAnyType
99− unless (isMonoType ty) $ P.unexpected "polymorphic type"
100− return ty
101−
102−parsePolyType :: P.Parsec String ParseState Type
103−parsePolyType = do
104− ty <- parseAnyType
105− unless (isPolyType ty) $ P.unexpected "polymorphic type"
106− return ty
107−
108−parseNameAndType :: P.Parsec String ParseState t -> P.Parsec String ParseState (String, t)
109−parseNameAndType p = (,) <$> (indented *> identifier <* indented <* lexeme (P.string "::")) <*> p
110−
111−parseRowEnding :: P.Parsec String ParseState Type
112−parseRowEnding = P.option REmpty (TypeVar <$> (lexeme (indented *> P.char '|') *> indented *> identifier))
113−
114−parseRow :: P.Parsec String ParseState Type
115−parseRow = (fromList <$> (commaSep $ parseNameAndType parsePolyType) <*> parseRowEnding) P.<?> "row"
116− where
117− fromList :: [(String, Type)] -> Type -> Type
118− fromList [] r = r
119− fromList ((name, t):ts) r = RCons name t (fromList ts r)
src/Language/PureScript/Parser/Values.hsdeleted−298
@@ -1,298 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Parser.Values (
16− parseValue,
17− parseGuard,
18− parseBinder,
19− parseBinderNoParens
20−) where
21−
22−import Language.PureScript.Values
23−import Language.PureScript.Parser.State
24−import qualified Language.PureScript.Parser.Common as C
25−import Control.Applicative
26−import qualified Text.Parsec as P
27−import Text.Parsec.Expr
28−import Language.PureScript.Parser.Types
29−
30−booleanLiteral :: P.Parsec String ParseState Bool
31−booleanLiteral = (C.reserved "true" >> return True) P.<|> (C.reserved "false" >> return False)
32−
33−parseNumericLiteral :: P.Parsec String ParseState Value
34−parseNumericLiteral = NumericLiteral <$> C.integerOrFloat
35−
36−parseStringLiteral :: P.Parsec String ParseState Value
37−parseStringLiteral = StringLiteral <$> C.stringLiteral
38−
39−parseBooleanLiteral :: P.Parsec String ParseState Value
40−parseBooleanLiteral = BooleanLiteral <$> booleanLiteral
41−
42−parseArrayLiteral :: P.Parsec String ParseState Value
43−parseArrayLiteral = ArrayLiteral <$> C.squares (C.commaSep parseValue)
44−
45−parseObjectLiteral :: P.Parsec String ParseState Value
46−parseObjectLiteral = ObjectLiteral <$> C.braces (C.commaSep parseIdentifierAndValue)
47−
48−parseIdentifierAndValue :: P.Parsec String ParseState (String, Value)
49−parseIdentifierAndValue = (,) <$> (C.indented *> C.identifier <* C.indented <* C.colon)
50− <*> (C.indented *> parseValue)
51−
52−parseAbs :: P.Parsec String ParseState Value
53−parseAbs = do
54− C.reservedOp "\\"
55− args <- P.many (C.indented *> (P.try singleArg <|> manyArgs))
56− C.indented *> C.reservedOp "->"
57− value <- parseValue
58− return $ toFunction args value
59− where
60− manyArgs :: P.Parsec String ParseState (Value -> Value)
61− manyArgs = do
62− args <- C.parens (C.commaSep C.parseIdent)
63− return $ Abs args
64− singleArg :: P.Parsec String ParseState (Value -> Value)
65− singleArg = Abs . return <$> C.parseIdent
66− toFunction :: [Value -> Value] -> Value -> Value
67− toFunction [] value = Abs [] value
68− toFunction args value = foldr (($)) value args
69−
70−parseVar :: P.Parsec String ParseState Value
71−parseVar = Var <$> C.parseQualified C.parseIdent
72−
73−parseConstructor :: P.Parsec String ParseState Value
74−parseConstructor = Constructor <$> C.parseQualified C.properName
75−
76−parseCase :: P.Parsec String ParseState Value
77−parseCase = Case <$> P.between (P.try (C.reserved "case")) (C.indented *> C.reserved "of") (return <$> parseValue)
78− <*> (C.indented *> C.mark (P.many (C.same *> C.mark parseCaseAlternative)))
79−
80−parseCaseAlternative :: P.Parsec String ParseState ([Binder], Maybe Guard, Value)
81−parseCaseAlternative = (,,) <$> (return <$> parseBinder)
82− <*> P.optionMaybe parseGuard
83− <*> (C.indented *> C.reservedOp "->" *> parseValue)
84− P.<?> "case alternative"
85−
86−parseIfThenElse :: P.Parsec String ParseState Value
87−parseIfThenElse = IfThenElse <$> (P.try (C.reserved "if") *> C.indented *> parseValue)
88− <*> (C.indented *> C.reserved "then" *> C.indented *> parseValue)
89− <*> (C.indented *> C.reserved "else" *> C.indented *> parseValue)
90−
91−parseBlock :: P.Parsec String ParseState Value
92−parseBlock = Block <$> parseManyStatements
93−
94−parseManyStatements :: P.Parsec String ParseState [Statement]
95−parseManyStatements = (do
96− _ <- C.lexeme $ P.char '{'
97− C.indented
98− sts <- C.mark (P.many (C.same *> C.mark parseStatement))
99− _ <- C.lexeme (P.char '}')
100− return sts) P.<?> "block"
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− , parseBlock
113− , parseCase
114− , parseIfThenElse
115− , Parens <$> C.parens parseValue ]
116−
117−parsePropertyUpdate :: P.Parsec String ParseState (String, Value)
118−parsePropertyUpdate = do
119− name <- C.lexeme C.identifier
120− _ <- C.lexeme $ C.indented *> P.char '='
121− value <- C.indented *> parseValue
122− return (name, value)
123−
124−parseAccessor :: Value -> P.Parsec String ParseState Value
125−parseAccessor (Constructor _) = P.unexpected "constructor"
126−parseAccessor obj = P.try $ Accessor <$> (C.indented *> C.dot *> P.notFollowedBy C.opLetter *> C.indented *> C.identifier) <*> pure obj
127−
128−parseDoNotationLet :: P.Parsec String ParseState DoNotationElement
129−parseDoNotationLet = DoNotationLet <$> (C.reserved "let" *> C.indented *> parseBinder)
130− <*> (C.indented *> C.reservedOp "=" *> parseValue)
131−
132−parseDoNotationBind :: P.Parsec String ParseState DoNotationElement
133−parseDoNotationBind = DoNotationBind <$> parseBinder <*> (C.indented *> C.reservedOp "<-" *> parseValue)
134−
135−parseDoNotationReturn :: P.Parsec String ParseState DoNotationElement
136−parseDoNotationReturn = DoNotationReturn <$> (C.reserved "return" *> C.indented *> parseValue)
137−
138−parseDoNotationElement :: P.Parsec String ParseState DoNotationElement
139−parseDoNotationElement = P.choice
140− [ P.try parseDoNotationBind
141− , parseDoNotationLet
142− , parseDoNotationReturn
143− , P.try (DoNotationValue <$> parseValue) ]
144−
145−parseManyDoNotationElements :: P.Parsec String ParseState [DoNotationElement]
146−parseManyDoNotationElements = do
147− C.indented
148− C.mark (P.many (C.same *> C.mark parseDoNotationElement))
149−
150−parseValue :: P.Parsec String ParseState Value
151−parseValue =
152− (buildExpressionParser operators
153− . C.buildPostfixParser postfixTable2
154− $ indexersAndAccessors) P.<?> "expression"
155− where
156− indexersAndAccessors = C.buildPostfixParser postfixTable1 parseValueAtom
157− postfixTable1 = [ parseAccessor
158− , \v -> P.try $ flip ObjectUpdate <$> (C.indented *> C.braces (C.commaSep1 (C.indented *> parsePropertyUpdate))) <*> pure v ]
159− postfixTable2 = [ \v -> P.try (C.indented *> indexersAndAccessors >>= \t2 -> return (\t1 -> App t1 [t2])) <*> pure v
160− , \v -> P.try $ flip App <$> (C.indented *> C.parens (C.commaSep parseValue)) <*> pure v
161− , \v -> flip TypedValue <$> (P.try (C.lexeme (C.indented *> P.string "::")) *> parsePolyType) <*> pure v
162− , \v -> P.try $ Do v <$> (C.indented *> C.reserved "do" *> parseManyDoNotationElements)
163− ]
164− operators = [ [ Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "!") >> return (Unary Not)
165− , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "~") >> return (Unary BitwiseNot)
166− , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "-") >> return (Unary Negate)
167− , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "+") >> return id ]
168− , [ Infix (C.lexeme (P.try (C.indented *> C.parseIdentInfix P.<?> "operator") >>= \ident ->
169− return (BinaryNoParens ident))) AssocRight ]
170− ]
171−
172−parseVariableIntroduction :: P.Parsec String ParseState Statement
173−parseVariableIntroduction = do
174− C.reserved "var"
175− name <- C.indented *> C.parseIdent
176− _ <- C.lexeme $ C.indented *> P.char '='
177− value <- parseValue
178− _ <- C.indented *> C.semi
179− return $ VariableIntroduction name value
180−
181−parseAssignment :: P.Parsec String ParseState Statement
182−parseAssignment = do
183− tgt <- P.try $ do
184− tgt <- C.parseIdent
185− _ <- C.lexeme $ C.indented *> P.char '='
186− return tgt
187− value <- parseValue
188− _ <- C.indented *> C.semi
189− return $ Assignment tgt value
190−
191−parseWhile :: P.Parsec String ParseState Statement
192−parseWhile = While <$> (C.reserved "while" *> C.indented *> C.parens parseValue)
193− <*> (C.indented *> parseManyStatements)
194−
195−parseFor :: P.Parsec String ParseState Statement
196−parseFor = For <$> (C.reserved "for" *> C.indented *> C.lexeme (P.char '(') *> C.indented *> C.parseIdent)
197− <*> (C.indented *> C.lexeme (P.string "<-") *> parseValue)
198− <*> (C.indented *> C.reserved "until" *> parseValue <* C.indented <* C.lexeme (P.char ')'))
199− <*> parseManyStatements
200−
201−parseIf :: P.Parsec String ParseState Statement
202−parseIf = If <$> parseIfStatement
203−
204−parseIfStatement :: P.Parsec String ParseState IfStatement
205−parseIfStatement =
206− IfStatement <$> (C.reserved "if" *> C.indented *> C.parens parseValue)
207− <*> parseManyStatements
208− <*> P.optionMaybe parseElseStatement
209−
210−parseElseStatement :: P.Parsec String ParseState ElseStatement
211−parseElseStatement = C.reserved "else" >> (ElseIf <$> parseIfStatement
212− <|> Else <$> parseManyStatements)
213−
214−parseReturn :: P.Parsec String ParseState Statement
215−parseReturn = Return <$> (C.reserved "return" *> parseValue <* C.indented <* C.semi)
216−
217−parseStatement :: P.Parsec String ParseState Statement
218−parseStatement = P.choice
219− [ parseVariableIntroduction
220− , parseAssignment
221− , parseWhile
222− , parseFor
223− , parseIf
224− , parseReturn ] P.<?> "statement"
225−
226−parseStringBinder :: P.Parsec String ParseState Binder
227−parseStringBinder = StringBinder <$> C.stringLiteral
228−
229−parseBooleanBinder :: P.Parsec String ParseState Binder
230−parseBooleanBinder = BooleanBinder <$> booleanLiteral
231−
232−parseNumberBinder :: P.Parsec String ParseState Binder
233−parseNumberBinder = NumberBinder <$> C.integerOrFloat
234−
235−parseVarBinder :: P.Parsec String ParseState Binder
236−parseVarBinder = VarBinder <$> C.parseIdent
237−
238−parseNullaryBinder :: P.Parsec String ParseState Binder
239−parseNullaryBinder = NullaryBinder <$> C.lexeme (C.parseQualified C.properName)
240−
241−parseUnaryBinder :: P.Parsec String ParseState Binder
242−parseUnaryBinder = UnaryBinder <$> C.lexeme (C.parseQualified C.properName) <*> (C.indented *> parseBinder)
243−
244−parseObjectBinder :: P.Parsec String ParseState Binder
245−parseObjectBinder = ObjectBinder <$> C.braces (C.commaSep (C.indented *> parseIdentifierAndBinder))
246−
247−parseArrayBinder :: P.Parsec String ParseState Binder
248−parseArrayBinder = C.squares $ ArrayBinder <$> (C.commaSep (C.indented *> parseBinder))
249−
250−parseNamedBinder :: P.Parsec String ParseState Binder
251−parseNamedBinder = NamedBinder <$> (C.parseIdent <* C.indented <* C.lexeme (P.char '@'))
252− <*> (C.indented *> parseBinder)
253−
254−parseNullBinder :: P.Parsec String ParseState Binder
255−parseNullBinder = C.lexeme (P.char '_') *> P.notFollowedBy C.identLetter *> return NullBinder
256−
257−parseIdentifierAndBinder :: P.Parsec String ParseState (String, Binder)
258−parseIdentifierAndBinder = do
259− name <- C.lexeme C.identifier
260− _ <- C.lexeme $ C.indented *> P.char '='
261− binder <- C.indented *> parseBinder
262− return (name, binder)
263−
264−parseBinderAtom :: P.Parsec String ParseState Binder
265−parseBinderAtom = P.choice (map P.try
266− [ parseNullBinder
267− , parseStringBinder
268− , parseBooleanBinder
269− , parseNumberBinder
270− , parseNamedBinder
271− , parseVarBinder
272− , parseUnaryBinder
273− , parseNullaryBinder
274− , parseObjectBinder
275− , parseArrayBinder
276− , C.parens parseBinder ]) P.<?> "binder"
277−
278−parseBinder :: P.Parsec String ParseState Binder
279−parseBinder = (buildExpressionParser operators parseBinderAtom) P.<?> "expression"
280− where
281− operators = [ [ Infix ( C.lexeme (P.try $ C.indented *> C.reservedOp ":") >> return ConsBinder) AssocRight ] ]
282−
283−parseBinderNoParens :: P.Parsec String ParseState Binder
284−parseBinderNoParens = P.choice (map P.try
285− [ parseNullBinder
286− , parseStringBinder
287− , parseBooleanBinder
288− , parseNumberBinder
289− , parseNamedBinder
290− , parseVarBinder
291− , parseNullaryBinder
292− , parseObjectBinder
293− , parseArrayBinder
294− , C.parens parseBinder ]) P.<?> "binder"
295−
296−parseGuard :: P.Parsec String ParseState Guard
297−parseGuard = C.indented *> C.pipe *> C.indented *> parseValue
298−
src/Language/PureScript/Pretty.hsdeleted−23
@@ -1,23 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Pretty (module P) where
16−
17−import Language.PureScript.Pretty.Kinds as P
18−import Language.PureScript.Pretty.Values as P
19−import Language.PureScript.Pretty.Types as P
20−import Language.PureScript.Pretty.JS as P
21−
22−
23−
src/Language/PureScript/Pretty/Common.hsdeleted−79
@@ -1,79 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE GeneralizedNewtypeDeriving, GADTs #-}
16−
17−module Language.PureScript.Pretty.Common where
18−
19−import Data.Char
20−import Control.Monad.State
21−import qualified Control.Category as C
22−import Control.Category ((>>>))
23−import qualified Control.Arrow as A
24−import Control.Arrow ((***), (<+>))
25−
26−import Language.PureScript.Names
27−
28−identToJs :: Ident -> String
29−identToJs (Ident name) = name
30−identToJs (Op op) = concatMap opCharToString op
31− where
32− opCharToString :: Char -> String
33− opCharToString = (:) '$'. show . ord
34−
35−newtype Pattern u a b = Pattern { runPattern :: A.Kleisli (StateT u Maybe) a b } deriving (C.Category, A.Arrow, A.ArrowZero, A.ArrowPlus)
36−
37−instance Functor (Pattern u a) where
38− fmap f (Pattern p) = Pattern $ A.Kleisli $ fmap f . A.runKleisli p
39−
40−pattern :: Pattern u a b -> u -> a -> Maybe b
41−pattern p u = flip evalStateT u . A.runKleisli (runPattern p)
42−
43−mkPattern :: (a -> Maybe b) -> Pattern u a b
44−mkPattern f = Pattern $ A.Kleisli (lift . f)
45−
46−mkPattern' :: (a -> StateT u Maybe b) -> Pattern u a b
47−mkPattern' = Pattern . A.Kleisli
48−
49−parens :: String -> String
50−parens s = ('(':s) ++ ")"
51−
52−chainl :: Pattern u a (a, a) -> (r -> r -> r) -> Pattern u a r -> Pattern u a r
53−chainl g f p = fix $ \c -> g >>> ((c <+> p) *** p) >>> A.arr (uncurry f)
54−
55−chainr :: Pattern u a (a, a) -> (r -> r -> r) -> Pattern u a r -> Pattern u a r
56−chainr g f p = fix $ \c -> g >>> (p *** (c <+> p)) >>> A.arr (uncurry f)
57−
58−wrap :: Pattern u a (s, a) -> (s -> r -> r) -> Pattern u a r -> Pattern u a r
59−wrap g f p = fix $ \c -> g >>> (C.id *** (c <+> p)) >>> A.arr (uncurry f)
60−
61−split :: Pattern u a (s, t) -> (s -> t -> r) -> Pattern u a r
62−split s f = s >>> A.arr (uncurry f)
63−
64−data OperatorTable u a r = OperatorTable { runOperatorTable :: [ [Operator u a r] ] }
65−
66−data Operator u a r where
67− AssocL :: Pattern u a (a, a) -> (r -> r -> r) -> Operator u a r
68− AssocR :: Pattern u a (a, a) -> (r -> r -> r) -> Operator u a r
69− Wrap :: Pattern u a (s, a) -> (s -> r -> r) -> Operator u a r
70− Split :: Pattern u a (s, t) -> (s -> t -> r) -> Operator u a r
71−
72−buildPrettyPrinter :: OperatorTable u a r -> Pattern u a r -> Pattern u a r
73−buildPrettyPrinter table p = foldl (\p' ops -> foldl1 (<+>) (flip map ops $ \op ->
74− case op of
75− AssocL pat g -> chainl pat g p'
76− AssocR pat g -> chainr pat g p'
77− Wrap pat g -> wrap pat g p'
78− Split pat g -> split pat g
79− ) <+> p') p $ runOperatorTable table
src/Language/PureScript/Pretty/JS.hsdeleted−239
@@ -1,239 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Pretty.JS (
16− prettyPrintJS
17−) where
18−
19−import Language.PureScript.Names
20−import Language.PureScript.Values
21−import Language.PureScript.Pretty.Common
22−import Language.PureScript.CodeGen.JS.AST
23−
24−import Data.List
25−import Data.Maybe (fromMaybe)
26−import qualified Control.Arrow as A
27−import Control.Arrow ((<+>))
28−import Control.Applicative
29−import Control.Monad.State
30−
31−newtype PrinterState = PrinterState { indent :: Int } deriving (Show, Eq, Ord)
32−
33−blockIndent :: Int
34−blockIndent = 4
35−
36−withIndent :: StateT PrinterState Maybe String -> StateT PrinterState Maybe String
37−withIndent action = do
38− modify $ \st -> st { indent = indent st + blockIndent }
39− result <- action
40− modify $ \st -> st { indent = indent st - blockIndent }
41− return result
42−
43−currentIndent :: StateT PrinterState Maybe String
44−currentIndent = do
45− current <- get
46− return $ replicate (indent current) ' '
47−
48−literals :: Pattern PrinterState JS String
49−literals = mkPattern' match
50− where
51− match :: JS -> StateT PrinterState Maybe String
52− match (JSNumericLiteral n) = return $ either show show n
53− match (JSStringLiteral s) = return $ show s
54− match (JSBooleanLiteral True) = return "true"
55− match (JSBooleanLiteral False) = return "false"
56− match (JSArrayLiteral xs) = fmap concat $ sequence
57− [ return "[ "
58− , fmap (intercalate ", ") $ forM xs prettyPrintJS'
59− , return " ]"
60− ]
61− match (JSObjectLiteral ps) = fmap concat $ sequence
62− [ return "{\n"
63− , withIndent $ do
64− jss <- forM ps $ \(key, value) -> fmap ((key ++ ": ") ++) . prettyPrintJS' $ value
65− indentString <- currentIndent
66− return $ intercalate ", \n" $ map (indentString ++) jss
67− , return "\n"
68− , currentIndent
69− , return "}"
70− ]
71− match (JSBlock sts) = fmap concat $ sequence
72− [ return "{\n"
73− , withIndent $ do
74− jss <- forM sts prettyPrintJS'
75− indentString <- currentIndent
76− return $ intercalate "\n" $ map (++ ";") $ map (indentString ++) jss
77− , return "\n"
78− , currentIndent
79− , return "}"
80− ]
81− match (JSVar ident) = return (identToJs ident)
82− match (JSVariableIntroduction ident value) = fmap concat $ sequence
83− [ return "var "
84− , return $ identToJs ident
85− , maybe (return "") (fmap (" = " ++) . prettyPrintJS') value
86− ]
87− match (JSAssignment target value) = fmap concat $ sequence
88− [ return $ targetToJs target
89− , return " = "
90− , prettyPrintJS' value
91− ]
92− match (JSWhile cond sts) = fmap concat $ sequence
93− [ return "while ("
94− , prettyPrintJS' cond
95− , return ") "
96− , prettyPrintJS' sts
97− ]
98− match (JSFor ident start end sts) = fmap concat $ sequence
99− [ return $ "for (" ++ identToJs ident ++ " = "
100− , prettyPrintJS' start
101− , return $ "; " ++ identToJs ident ++ " < "
102− , prettyPrintJS' end
103− , return $ "; " ++ identToJs ident ++ "++) "
104− , prettyPrintJS' sts
105− ]
106− match (JSIfElse cond thens elses) = fmap concat $ sequence
107− [ return "if ("
108− , prettyPrintJS' cond
109− , return ") "
110− , prettyPrintJS' thens
111− , maybe (return "") (fmap (" else " ++) . prettyPrintJS') elses
112− ]
113− match (JSReturn value) = fmap concat $ sequence
114− [ return "return "
115− , prettyPrintJS' value
116− ]
117− match (JSThrow value) = fmap concat $ sequence
118− [ return "throw "
119− , prettyPrintJS' value
120− ]
121− match (JSBreak lbl) = return $ "break " ++ lbl
122− match (JSContinue lbl) = return $ "continue " ++ lbl
123− match (JSLabel lbl js) = fmap concat $ sequence
124− [ return $ lbl ++ ": "
125− , prettyPrintJS' js
126− ]
127− match (JSRaw js) = return js
128− match _ = mzero
129−
130−targetToJs :: JSAssignment -> String
131−targetToJs (JSAssignVariable ident) = identToJs ident
132−targetToJs (JSAssignProperty prop target) = targetToJs target ++ "." ++ prop
133−
134−conditional :: Pattern PrinterState JS ((JS, JS), JS)
135−conditional = mkPattern match
136− where
137− match (JSConditional cond th el) = Just ((th, el), cond)
138− match _ = Nothing
139−
140−accessor :: Pattern PrinterState JS (String, JS)
141−accessor = mkPattern match
142− where
143− match (JSAccessor prop val) = Just (prop, val)
144− match _ = Nothing
145−
146−indexer :: Pattern PrinterState JS (String, JS)
147−indexer = mkPattern' match
148− where
149− match (JSIndexer index val) = (,) <$> prettyPrintJS' index <*> pure val
150− match _ = mzero
151−
152−lam :: Pattern PrinterState JS ((Maybe Ident, [Ident]), JS)
153−lam = mkPattern match
154− where
155− match (JSFunction name args ret) = Just ((name, args), ret)
156− match _ = Nothing
157−
158−app :: Pattern PrinterState JS (String, JS)
159−app = mkPattern' match
160− where
161− match (JSApp val args) = do
162− jss <- mapM prettyPrintJS' args
163− return (intercalate ", " jss, val)
164− match _ = mzero
165−
166−typeOf :: Pattern PrinterState JS ((), JS)
167−typeOf = mkPattern match
168− where
169− match (JSTypeOf val) = Just ((), val)
170− match _ = Nothing
171−
172−unary :: UnaryOperator -> String -> Operator PrinterState JS String
173−unary op str = Wrap match (++)
174− where
175− match :: Pattern PrinterState JS (String, JS)
176− match = mkPattern match'
177− where
178− match' (JSUnary op' val) | op' == op = Just (str, val)
179− match' _ = Nothing
180−
181−binary :: BinaryOperator -> String -> Operator PrinterState JS String
182−binary op str = AssocR match (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)
183− where
184− match :: Pattern PrinterState JS (JS, JS)
185− match = mkPattern match'
186− where
187− match' (JSBinary op' v1 v2) | op' == op = Just (v1, v2)
188− match' _ = Nothing
189−
190−prettyPrintJS1 :: JS -> String
191−prettyPrintJS1 = fromMaybe (error "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyPrintJS'
192−
193−prettyPrintJS :: [JS] -> String
194−prettyPrintJS sts = fromMaybe (error "Incomplete pattern") . flip evalStateT (PrinterState 0) $ do
195− jss <- forM sts prettyPrintJS'
196− indentString <- currentIndent
197− return $ intercalate "\n" $ map (++ ";") $ map (indentString ++) jss
198−
199−prettyPrintJS' :: JS -> StateT PrinterState Maybe String
200−prettyPrintJS' = A.runKleisli $ runPattern matchValue
201− where
202− matchValue :: Pattern PrinterState JS String
203− matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)
204− operators :: OperatorTable PrinterState JS String
205− operators =
206− OperatorTable [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ]
207− , [ Wrap indexer $ \index val -> val ++ "[" ++ index ++ "]" ]
208− , [ Wrap app $ \args val -> val ++ "(" ++ args ++ ")" ]
209− , [ Wrap lam $ \(name, args) ret -> "function "
210− ++ maybe "" identToJs name
211− ++ "(" ++ intercalate ", " (map identToJs args) ++ ") "
212− ++ ret ]
213− , [ Wrap conditional $ \(th, el) cond -> cond ++ " ? " ++ prettyPrintJS1 th ++ " : " ++ prettyPrintJS1 el ]
214− , [ binary LessThan "<" ]
215− , [ binary LessThanOrEqualTo "<=" ]
216− , [ binary GreaterThan ">" ]
217− , [ binary GreaterThanOrEqualTo ">=" ]
218− , [ Wrap typeOf $ \_ s -> "typeof " ++ s ]
219− , [ unary Not "!" ]
220− , [ unary BitwiseNot "~" ]
221− , [ unary Negate "-" ]
222− , [ unary Positive "+" ]
223− , [ binary Multiply "*" ]
224− , [ binary Divide "/" ]
225− , [ binary Modulus "%" ]
226− , [ binary Concat "+" ]
227− , [ binary Add "+" ]
228− , [ binary Subtract "-" ]
229− , [ binary ShiftLeft "<<" ]
230− , [ binary ShiftRight ">>" ]
231− , [ binary ZeroFillShiftRight ">>>" ]
232− , [ binary EqualTo "===" ]
233− , [ binary NotEqualTo "!==" ]
234− , [ binary BitwiseAnd "&" ]
235− , [ binary BitwiseXor "^" ]
236− , [ binary BitwiseOr "|" ]
237− , [ binary And "&&" ]
238− , [ binary Or "||" ]
239− ]
src/Language/PureScript/Pretty/Kinds.hsdeleted−54
@@ -1,54 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Pretty.Kinds (
16− prettyPrintKind
17−) where
18−
19−import Data.Maybe (fromMaybe)
20−
21−import Language.PureScript.Kinds
22−import Language.PureScript.Pretty.Common
23−import Language.PureScript.Unknown
24−import Control.Arrow (ArrowPlus(..))
25−
26−typeLiterals :: Pattern () Kind String
27−typeLiterals = mkPattern match
28− where
29− match Star = Just "*"
30− match Bang = Just "!"
31− match (KUnknown (Unknown u)) = Just $ 'u' : show u
32− match _ = Nothing
33−
34−matchRow :: Pattern () Kind ((), Kind)
35−matchRow = mkPattern match
36− where
37− match (Row k) = Just ((), k)
38− match _ = Nothing
39−
40−funKind :: Pattern () Kind (Kind, Kind)
41−funKind = mkPattern match
42− where
43− match (FunKind arg ret) = Just (arg, ret)
44− match _ = Nothing
45−
46−prettyPrintKind :: Kind -> String
47−prettyPrintKind = fromMaybe (error "Incomplete pattern") . pattern matchKind ()
48− where
49− matchKind :: Pattern () Kind String
50− matchKind = buildPrettyPrinter operators (typeLiterals <+> fmap parens matchKind)
51− operators :: OperatorTable () Kind String
52− operators =
53− OperatorTable [ [ Wrap matchRow $ \_ k -> "# " ++ k]
54− , [ AssocR funKind $ \arg ret -> arg ++ " -> " ++ ret ] ]
src/Language/PureScript/Pretty/Types.hsdeleted−91
@@ -1,91 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Pretty.Types (
16− prettyPrintType,
17− prettyPrintRow
18−) where
19−
20−import Data.Maybe (fromMaybe)
21−import Data.List (intercalate)
22−import Control.Arrow ((<+>))
23−
24−import Language.PureScript.Types
25−import Language.PureScript.Pretty.Common
26−import Language.PureScript.Unknown
27−
28−typeLiterals :: Pattern () Type String
29−typeLiterals = mkPattern match
30− where
31− match Number = Just "Number"
32− match String = Just "String"
33− match Boolean = Just "Boolean"
34− match (Array ty) = Just $ "[" ++ prettyPrintType ty ++ "]"
35− match (Object row) = Just $ "{ " ++ prettyPrintType row ++ " }"
36− match (TypeVar var) = Just var
37− match (TypeConstructor ctor) = Just $ show ctor
38− match (TUnknown (Unknown u)) = Just $ 'u' : show u
39− match (Skolem s) = Just $ 's' : show s
40− match (ConstrainedType deps ty) = Just $ "(" ++ intercalate "," (map (\(pn, ty') -> show pn ++ " (" ++ prettyPrintType ty' ++ ")") deps) ++ ") => " ++ prettyPrintType ty
41− match (SaturatedTypeSynonym name args) = Just $ show name ++ "<" ++ intercalate "," (map prettyPrintType args) ++ ">"
42− match (ForAll ident ty) = Just $ "forall " ++ ident ++ ". " ++ prettyPrintType ty
43− match REmpty = Just $ prettyPrintRow REmpty
44− match row@(RCons _ _ _) = Just $ prettyPrintRow row
45− match _ = Nothing
46−
47−prettyPrintRow :: Type -> String
48−prettyPrintRow = (\(tys, rest) -> intercalate ", " (map (uncurry nameAndTypeToPs) tys) ++ tailToPs rest) . toList []
49− where
50− nameAndTypeToPs :: String -> Type -> String
51− nameAndTypeToPs name ty = name ++ " :: " ++ prettyPrintType ty
52− tailToPs :: Type -> String
53− tailToPs REmpty = ""
54− tailToPs (TUnknown (Unknown u)) = " | u" ++ show u
55− tailToPs (TypeVar var) = " | " ++ var
56− tailToPs (Skolem s) = " | s" ++ show s
57− tailToPs _ = error "Invalid row tail"
58− toList :: [(String, Type)] -> Type -> ([(String, Type)], Type)
59− toList tys (RCons name ty row) = toList ((name, ty):tys) row
60− toList tys r = (tys, r)
61−
62−typeApp :: Pattern () Type (Type, Type)
63−typeApp = mkPattern match
64− where
65− match (TypeApp f x) = Just (f, x)
66− match _ = Nothing
67−
68−singleArgumentFunction :: Pattern () Type (Type, Type)
69−singleArgumentFunction = mkPattern match
70− where
71− match (Function [arg] ret) = Just (arg, ret)
72− match _ = Nothing
73−
74−function :: Pattern () Type ([Type], Type)
75−function = mkPattern match
76− where
77− match (Function args ret) = Just (args, ret)
78− match _ = Nothing
79−
80−prettyPrintType :: Type -> String
81−prettyPrintType = fromMaybe (error "Incomplete pattern") . pattern matchType ()
82− where
83− matchType :: Pattern () Type String
84− matchType = buildPrettyPrinter operators (typeLiterals <+> fmap parens matchType)
85− operators :: OperatorTable () Type String
86− operators =
87− OperatorTable [ [ AssocL typeApp $ \f x -> f ++ " " ++ x ]
88− , [ AssocR singleArgumentFunction $ \arg ret -> arg ++ " -> " ++ ret
89− , Wrap function $ \args ret -> "(" ++ intercalate ", " (map prettyPrintType args) ++ ") -> " ++ ret
90− ]
91− ]
src/Language/PureScript/Pretty/Values.hsdeleted−221
@@ -1,221 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Pretty.Values (
16− prettyPrintValue,
17− prettyPrintBinder
18−) where
19−
20−import Data.Maybe (fromMaybe)
21−import Data.List (intercalate)
22−import Control.Arrow ((<+>))
23−
24−import Language.PureScript.Types
25−import Language.PureScript.Values
26−import Language.PureScript.Pretty.Common
27−import Language.PureScript.Pretty.Types
28−
29−literals :: Pattern () Value String
30−literals = mkPattern match
31− where
32− match (NumericLiteral n) = Just $ either show show n
33− match (StringLiteral s) = Just $ show s
34− match (BooleanLiteral True) = Just "true"
35− match (BooleanLiteral False) = Just "false"
36− match (ArrayLiteral xs) = Just $ "[" ++ intercalate ", " (map prettyPrintValue xs) ++ "]"
37− match (ObjectLiteral ps) = Just $ "{" ++ intercalate ", " (map (uncurry prettyPrintObjectProperty) ps) ++ "}"
38− match (Constructor name) = Just $ show name
39− match (Block sts) = Just $ "do { " ++ intercalate " ; " (map prettyPrintStatement sts) ++ " }"
40− match (Case values binders) = Just $ "case " ++ intercalate " " (map prettyPrintValue values) ++
41− " of { " ++ intercalate " ; " (map prettyPrintCaseAlternative binders) ++ " }"
42− match (Var ident) = Just $ show ident
43− match (TypeClassDictionary _ _) = error "Type class dictionary was not replaced"
44− match _ = Nothing
45−
46−prettyPrintCaseAlternative :: ([Binder], Maybe Guard, Value) -> String
47−prettyPrintCaseAlternative (binders, grd, val) = "(" ++ intercalate ", " (map prettyPrintBinder binders) ++ ") " ++
48− (maybe "" (("| " ++) . prettyPrintValue) grd) ++ " -> " ++ prettyPrintValue val
49−
50−ifThenElse :: Pattern () Value ((Value, Value), Value)
51−ifThenElse = mkPattern match
52− where
53− match (IfThenElse cond th el) = Just ((th, el), cond)
54− match _ = Nothing
55−
56−accessor :: Pattern () Value (String, Value)
57−accessor = mkPattern match
58− where
59− match (Accessor prop val) = Just (prop, val)
60− match _ = Nothing
61−
62−indexer :: Pattern () Value (Value, Value)
63−indexer = mkPattern match
64− where
65− match (Indexer index val) = Just (index, val)
66− match _ = Nothing
67−
68−objectUpdate :: Pattern () Value ([String], Value)
69−objectUpdate = mkPattern match
70− where
71− match (ObjectUpdate o ps) = Just (flip map ps $ \(key, val) -> key ++ " = " ++ prettyPrintValue val, o)
72− match _ = Nothing
73−
74−app :: Pattern () Value (String, Value)
75−app = mkPattern match
76− where
77− match (App val args) = Just (intercalate "," (map prettyPrintValue args), val)
78− match _ = Nothing
79−
80−lam :: Pattern () Value ([String], Value)
81−lam = mkPattern match
82− where
83− match (Abs args val) = Just (map show args, val)
84− match _ = Nothing
85−
86−typed :: Pattern () Value (Type, Value)
87−typed = mkPattern match
88− where
89− match (TypedValue val ty) = Just (ty, val)
90− match _ = Nothing
91−
92−unary :: UnaryOperator -> String -> Operator () Value String
93−unary op str = Wrap match (++)
94− where
95− match :: Pattern () Value (String, Value)
96− match = mkPattern match'
97− where
98− match' (Unary op' val) | op' == op = Just (str, val)
99− match' _ = Nothing
100−
101−binary :: BinaryOperator -> String -> Operator () Value String
102−binary op str = AssocR match (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)
103− where
104− match :: Pattern () Value (Value, Value)
105− match = mkPattern match'
106− where
107− match' (Binary op' v1 v2) | op' == op = Just (v1, v2)
108− match' _ = Nothing
109−
110−_do :: Pattern () Value ([DoNotationElement], Value)
111−_do = mkPattern match
112− where
113− match (Do val els) = Just (els, val)
114− match _ = Nothing
115−
116−prettyPrintDoNotationElement :: DoNotationElement -> String
117−prettyPrintDoNotationElement (DoNotationValue val) = prettyPrintValue val
118−prettyPrintDoNotationElement (DoNotationBind binder val) = prettyPrintBinder binder ++ " <- " ++ prettyPrintValue val
119−prettyPrintDoNotationElement (DoNotationLet binder val) = "let " ++ prettyPrintBinder binder ++ " = " ++ prettyPrintValue val
120−prettyPrintDoNotationElement (DoNotationReturn val) = "return " ++ prettyPrintValue val
121−
122−prettyPrintValue :: Value -> String
123−prettyPrintValue = fromMaybe (error "Incomplete pattern") . pattern matchValue ()
124− where
125− matchValue :: Pattern () Value String
126− matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)
127− operators :: OperatorTable () Value String
128− operators =
129− OperatorTable [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ]
130− , [ Wrap objectUpdate $ \ps val -> val ++ "{ " ++ intercalate ", " ps ++ " }" ]
131− , [ Wrap app $ \args val -> val ++ "(" ++ args ++ ")" ]
132− , [ Wrap _do $ \els val -> val ++ " do { " ++ intercalate "; " (map prettyPrintDoNotationElement els) ++ " }" ]
133− , [ Split lam $ \args val -> "\\" ++ intercalate ", " args ++ " -> " ++ prettyPrintValue val ]
134− , [ Wrap ifThenElse $ \(th, el) cond -> cond ++ " ? " ++ prettyPrintValue th ++ " : " ++ prettyPrintValue el ]
135− , [ Wrap typed $ \ty val -> val ++ " :: " ++ prettyPrintType ty ]
136− , [ AssocR indexer (\index val -> val ++ " !! " ++ index) ]
137− , [ binary LessThan "<" ]
138− , [ binary LessThanOrEqualTo "<=" ]
139− , [ binary GreaterThan ">" ]
140− , [ binary GreaterThanOrEqualTo ">=" ]
141− , [ unary Not "!" ]
142− , [ unary BitwiseNot "~" ]
143− , [ unary Negate "-" ]
144− , [ unary Positive "+" ]
145− , [ binary Multiply "*" ]
146− , [ binary Divide "/" ]
147− , [ binary Modulus "%" ]
148− , [ binary Concat "++" ]
149− , [ binary Add "+" ]
150− , [ binary Subtract "-" ]
151− , [ binary ShiftLeft "<<" ]
152− , [ binary ShiftRight ">>" ]
153− , [ binary ZeroFillShiftRight ">>>" ]
154− , [ binary EqualTo "==" ]
155− , [ binary NotEqualTo "!=" ]
156− , [ binary BitwiseAnd "&" ]
157− , [ binary BitwiseXor "^" ]
158− , [ binary BitwiseOr "|" ]
159− , [ binary And "&&" ]
160− , [ binary Or "||" ]
161− ]
162−
163−prettyPrintBinderAtom :: Pattern () Binder String
164−prettyPrintBinderAtom = mkPattern match
165− where
166− match :: Binder -> Maybe String
167− match NullBinder = Just "_"
168− match (StringBinder str) = Just $ show str
169− match (NumberBinder num) = Just $ either show show num
170− match (BooleanBinder True) = Just "true"
171− match (BooleanBinder False) = Just "false"
172− match (VarBinder ident) = Just $ show ident
173− match (NullaryBinder ctor) = Just $ show ctor
174− match (UnaryBinder ctor b) = Just $ show ctor ++ " " ++ prettyPrintBinder b
175− match (ObjectBinder bs) = Just $ "{ " ++ intercalate ", " (map (uncurry prettyPrintObjectPropertyBinder) bs) ++ " }"
176− match (ArrayBinder bs) = Just $ "[ " ++ intercalate ", " (map prettyPrintBinder bs) ++ " ]"
177− match (NamedBinder ident binder) = Just $ show ident ++ "@" ++ prettyPrintBinder binder
178− match _ = Nothing
179−
180−prettyPrintBinder :: Binder -> String
181−prettyPrintBinder = fromMaybe (error "Incomplete pattern") . pattern matchBinder ()
182− where
183− matchBinder :: Pattern () Binder String
184− matchBinder = buildPrettyPrinter operators (prettyPrintBinderAtom <+> fmap parens matchBinder)
185− operators :: OperatorTable () Binder String
186− operators =
187− OperatorTable [ [ AssocR matchConsBinder (\b1 b2 -> b1 ++ " : " ++ b2) ] ]
188−
189−matchConsBinder :: Pattern () Binder (Binder, Binder)
190−matchConsBinder = mkPattern match'
191− where
192− match' (ConsBinder b1 b2) = Just (b1, b2)
193− match' _ = Nothing
194−
195−prettyPrintObjectPropertyBinder :: String -> Binder -> String
196−prettyPrintObjectPropertyBinder key binder = key ++ ": " ++ prettyPrintBinder binder
197−
198−prettyPrintObjectProperty :: String -> Value -> String
199−prettyPrintObjectProperty key value = key ++ ": " ++ prettyPrintValue value
200−
201−prettyPrintStatement :: Statement -> String
202−prettyPrintStatement (VariableIntroduction ident value) = "var " ++ show ident ++ " = " ++ prettyPrintValue value
203−prettyPrintStatement (Assignment target value) = show target ++ " = " ++ prettyPrintValue value
204−prettyPrintStatement (While cond sts) = "while " ++ prettyPrintValue cond ++ ": {" ++ intercalate ";" (map prettyPrintStatement sts) ++ " }"
205−prettyPrintStatement (For ident start end sts) = "for " ++ show ident
206− ++ " <- " ++ prettyPrintValue start
207− ++ " until " ++ prettyPrintValue end ++ ": {"
208− ++ intercalate "; " (map prettyPrintStatement sts) ++ " }"
209−prettyPrintStatement (If ifst) = prettyPrintIfStatement ifst
210−prettyPrintStatement (Return value) = "return " ++ prettyPrintValue value
211−
212−prettyPrintIfStatement :: IfStatement -> String
213−prettyPrintIfStatement (IfStatement cond thens elst) =
214− "if "
215− ++ prettyPrintValue cond ++ ": {"
216− ++ intercalate "; " (map prettyPrintStatement thens) ++ " }"
217− ++ maybe "" prettyPrintElseStatement elst
218−
219−prettyPrintElseStatement :: ElseStatement -> String
220−prettyPrintElseStatement (Else sts) = "else: {" ++ intercalate "; " (map prettyPrintStatement sts) ++ " }"
221−prettyPrintElseStatement (ElseIf ifst) = "else " ++ prettyPrintIfStatement ifst
src/Language/PureScript/Scope.hsdeleted−56
@@ -1,56 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Scope (
16− usedNames,
17− unusedNames
18−) where
19−
20−import Data.Data
21−import Data.List ((\\), nub)
22−import Data.Generics (extQ, mkQ, everything)
23−
24−import Language.PureScript.Values
25−import Language.PureScript.Names
26−import Language.PureScript.CodeGen.JS.AST
27−
28−usedNames :: (Data d) => d -> [Ident]
29−usedNames val = nub $ everything (++) (mkQ [] namesV `extQ` namesS `extQ` namesB `extQ` namesJS) val
30− where
31− namesV :: Value -> [Ident]
32− namesV (Abs args _) = args
33− namesV (Var (Qualified Nothing name)) = [name]
34− namesV _ = []
35− namesS :: Statement -> [Ident]
36− namesS (VariableIntroduction name _) = [name]
37− namesS (For name _ _ _) = [name]
38− namesS _ = []
39− namesB :: Binder -> [Ident]
40− namesB (VarBinder name) = [name]
41− namesB _ = []
42− namesJS :: JS -> [Ident]
43− namesJS (JSVar name) = [name]
44− namesJS (JSFunction (Just name) args _) = name : args
45− namesJS (JSFunction Nothing args _) = args
46− namesJS (JSVariableIntroduction name _) = [name]
47− namesJS (JSFor name _ _ _) = [name]
48− namesJS _ = []
49−
50−unusedNames :: (Data d) => d -> [Ident]
51−unusedNames val =
52− let
53− allNames = usedNames val
54− varNames = map (Ident . ('_' :) . show) ([1..] :: [Int])
55− in
56− varNames \\ allNames
src/Language/PureScript/Sugar.hsdeleted−34
@@ -1,34 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Sugar (desugar, module S) where
16−
17−import Control.Monad
18−
19−import Language.PureScript.Declarations
20−
21−import Language.PureScript.Sugar.Operators as S
22−import Language.PureScript.Sugar.DoNotation as S
23−import Language.PureScript.Sugar.CaseDeclarations as S
24−import Language.PureScript.Sugar.TypeDeclarations as S
25−import Language.PureScript.Sugar.BindingGroups as S
26−import Language.PureScript.Sugar.TypeClasses as S
27−
28−desugar :: [Module] -> Either String [Module]
29−desugar = desugarTypeClasses
30− >=> rebracket
31− >=> desugarDo
32− >=> desugarCasesModule
33− >=> desugarTypeDeclarationsModule
34− >=> return . createBindingGroupsModule
src/Language/PureScript/Sugar/BindingGroups.hsdeleted−98
@@ -1,98 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Sugar.BindingGroups (
16− createBindingGroups,
17− createBindingGroupsModule
18−) where
19−
20−import Data.Data
21−import Data.Graph
22−import Data.Generics
23−import Data.List (nub, intersect)
24−
25−import Language.PureScript.Declarations
26−import Language.PureScript.Names
27−import Language.PureScript.Values
28−import Language.PureScript.Types
29−
30−createBindingGroupsModule :: [Module] -> [Module]
31−createBindingGroupsModule = map $ \(Module name ds) -> Module name (createBindingGroups ds)
32−
33−createBindingGroups :: [Declaration] -> [Declaration]
34−createBindingGroups ds =
35− let
36− values = filter isValueDecl ds
37− dataDecls = filter isDataDecl ds
38− nonValues = filter (\d -> not (isValueDecl d) && not (isDataDecl d)) ds
39− allProperNames = map getProperName dataDecls
40− dataVerts = map (\d -> (d, getProperName d, usedProperNames d `intersect` allProperNames)) dataDecls
41− dataBindingGroupDecls = map toDataBindingGroup $ stronglyConnComp dataVerts
42− allIdents = map getIdent values
43− valueVerts = map (\d -> (d, getIdent d, usedIdents d `intersect` allIdents)) values
44− bindingGroupDecls = map toBindingGroup $ stronglyConnComp valueVerts
45− in
46− dataBindingGroupDecls ++ nonValues ++ bindingGroupDecls
47−
48−usedIdents :: (Data d) => d -> [Ident]
49−usedIdents = nub . everything (++) (mkQ [] namesV `extQ` namesS)
50− where
51− namesV :: Value -> [Ident]
52− namesV (Var (Qualified Nothing name)) = [name]
53− namesV _ = []
54− namesS :: Statement -> [Ident]
55− namesS (VariableIntroduction name _) = [name]
56− namesS _ = []
57−
58−usedProperNames :: (Data d) => d -> [ProperName]
59−usedProperNames = nub . everything (++) (mkQ [] names)
60− where
61− names :: Type -> [ProperName]
62− names (TypeConstructor (Qualified Nothing name)) = [name]
63− names _ = []
64−
65−isValueDecl :: Declaration -> Bool
66−isValueDecl (ValueDeclaration _ _ _ _) = True
67−isValueDecl _ = False
68−
69−isDataDecl :: Declaration -> Bool
70−isDataDecl (DataDeclaration _ _ _) = True
71−isDataDecl _ = False
72−
73−getIdent :: Declaration -> Ident
74−getIdent (ValueDeclaration ident _ _ _) = ident
75−getIdent _ = error "Expected ValueDeclaration"
76−
77−getProperName :: Declaration -> ProperName
78−getProperName (DataDeclaration pn _ _) = pn
79−getProperName _ = error "Expected DataDeclaration"
80−
81−toBindingGroup :: SCC Declaration -> Declaration
82−toBindingGroup (AcyclicSCC d) = d
83−toBindingGroup (CyclicSCC [d]) = d
84−toBindingGroup (CyclicSCC ds') = BindingGroupDeclaration $ map fromValueDecl ds'
85−
86−toDataBindingGroup :: SCC Declaration -> Declaration
87−toDataBindingGroup (AcyclicSCC d) = d
88−toDataBindingGroup (CyclicSCC [d]) = d
89−toDataBindingGroup (CyclicSCC ds') = DataBindingGroupDeclaration $ map fromDataDecl ds'
90−
91−fromValueDecl :: Declaration -> (Ident, Value)
92−fromValueDecl (ValueDeclaration ident [] Nothing val) = (ident, val)
93−fromValueDecl (ValueDeclaration _ _ _ _) = error "Binders should have been desugared"
94−fromValueDecl _ = error "Expected ValueDeclaration"
95−
96−fromDataDecl :: Declaration -> (ProperName, [String], [(ProperName, Maybe Type)])
97−fromDataDecl (DataDeclaration pn args ctors) = (pn, args, ctors)
98−fromDataDecl _ = error "Expected DataDeclaration"
src/Language/PureScript/Sugar/CaseDeclarations.hsdeleted−67
@@ -1,67 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Sugar.CaseDeclarations (
16− desugarCases,
17− desugarCasesModule
18−) where
19−
20−import Data.List (groupBy)
21−import Control.Applicative ((<$>))
22−import Control.Monad (forM, join, unless)
23−import Control.Monad.Error.Class
24−
25−import Language.PureScript.Names
26−import Language.PureScript.Values
27−import Language.PureScript.Declarations
28−import Language.PureScript.Scope
29−
30−desugarCasesModule :: [Module] -> Either String [Module]
31−desugarCasesModule ms = forM ms $ \(Module name ds) -> Module name <$> desugarCases ds
32−
33−desugarCases :: [Declaration] -> Either String [Declaration]
34−desugarCases = fmap join . mapM toDecls . groupBy inSameGroup
35−
36−inSameGroup :: Declaration -> Declaration -> Bool
37−inSameGroup (ValueDeclaration ident1 _ _ _) (ValueDeclaration ident2 _ _ _) = ident1 == ident2
38−inSameGroup _ _ = False
39−
40−toDecls :: [Declaration] -> Either String [Declaration]
41−toDecls d@[ValueDeclaration _ [] Nothing _] = return d
42−toDecls ds@(ValueDeclaration ident bs _ _ : _) = do
43− let tuples = map toTuple ds
44− unless (all ((== map length bs) . map length . fst) tuples) $
45− throwError $ "Argument list lengths differ in declaration " ++ show ident
46− return [makeCaseDeclaration ident tuples]
47−toDecls ds = return ds
48−
49−toTuple :: Declaration -> ([[Binder]], (Maybe Guard, Value))
50−toTuple (ValueDeclaration _ bs g val) = (bs, (g, val))
51−toTuple _ = error "Not a value declaration"
52−
53−makeCaseDeclaration :: Ident -> [([[Binder]], (Maybe Guard, Value))] -> Declaration
54−makeCaseDeclaration ident alternatives =
55− let
56− argPattern = map length . fst . head $ alternatives
57− args = take (sum argPattern) $ unusedNames (ident, alternatives)
58− vars = map (\arg -> Var (Qualified Nothing arg)) args
59− binders = [ (join bs, g, val) | (bs, (g, val)) <- alternatives ]
60− value = foldr (\args' ret -> Abs args' ret) (Case vars binders) (rearrange argPattern args)
61− in
62− ValueDeclaration ident [] Nothing value
63−
64−rearrange :: [Int] -> [a] -> [[a]]
65−rearrange [] _ = []
66−rearrange (n:ns) xs = take n xs : rearrange ns (drop n xs)
67−
src/Language/PureScript/Sugar/DoNotation.hsdeleted−52
@@ -1,52 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Sugar.DoNotation (
16− desugarDo
17−) where
18−
19−import Data.Data
20−import Data.Generics
21−
22−import Language.PureScript.Values
23−import Language.PureScript.Names
24−import Language.PureScript.Scope
25−
26−desugarDo :: (Data d) => d -> Either String d
27−desugarDo = everywhereM (mkM replace)
28− where
29− replace :: Value -> Either String Value
30− replace (Do monad els) = go monad els
31− replace other = return other
32− go :: Value -> [DoNotationElement] -> Either String Value
33− go _ [] = error "The impossible happened in desugarDo"
34− go monad [DoNotationReturn val] = return $ App (Accessor "ret" monad) [val]
35− go _ (DoNotationReturn _ : _) = Left "Return statement must be the last statement in a do block"
36− go _ [DoNotationValue val] = return val
37− go monad (DoNotationValue val : rest) = do
38− rest' <- go monad rest
39− return $ App (App (Accessor "bind" monad) [val]) [Abs [Ident "_"] rest']
40− go _ [DoNotationBind _ _] = Left "Bind statement cannot be the last statement in a do block"
41− go monad (DoNotationBind NullBinder val : rest) = go monad (DoNotationValue val : rest)
42− go monad (DoNotationBind (VarBinder ident) val : rest) = do
43− rest' <- go monad rest
44− return $ App (App (Accessor "bind" monad) [val]) [Abs [ident] rest']
45− go monad (DoNotationBind binder val : rest) = do
46− rest' <- go monad rest
47− let ident = head $ unusedNames rest'
48− return $ App (App (Accessor "bind" monad) [val]) [Abs [ident] (Case [Var (Qualified Nothing ident)] [([binder], Nothing, rest')])]
49− go _ [DoNotationLet _ _] = Left "Let statement cannot be the last statement in a do block"
50− go monad (DoNotationLet binder val : rest) = do
51− rest' <- go monad rest
52− return $ Case [val] [([binder], Nothing, rest')]
src/Language/PureScript/Sugar/Operators.hsdeleted−132
@@ -1,132 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE Rank2Types #-}
16−
17−module Language.PureScript.Sugar.Operators (
18− rebracket
19−) where
20−
21−import Language.PureScript.Names
22−import Language.PureScript.Declarations
23−import Language.PureScript.Values
24−
25−import Data.Function (on)
26−import Data.List (groupBy, sortBy)
27−import qualified Data.Map as M
28−import qualified Data.Generics as G
29−import qualified Data.Generics.Extras as G
30−import Control.Monad.State
31−import Control.Applicative
32−import qualified Text.Parsec as P
33−import qualified Text.Parsec.Pos as P
34−import qualified Text.Parsec.Expr as P
35−
36−rebracket :: [Module] -> Either String [Module]
37−rebracket = go M.empty []
38− where
39− go _ rb [] = return . reverse $ rb
40− go m rb (Module name ds : ms) = do
41− m' <- M.union m <$> collectFixities m (ModuleName name) ds
42− let opTable = customOperatorTable m'
43− ds' <- G.everywhereM' (G.mkM (matchOperators (ModuleName name) opTable)) ds
44− go m' (Module name (G.everywhere (G.mkT removeParens) ds') : rb) ms
45−
46−removeParens :: Value -> Value
47−removeParens (Parens val) = val
48−removeParens val = val
49−
50−customOperatorTable :: M.Map (Qualified Ident) Fixity -> [[(Qualified Ident, Value -> Value -> Value, Associativity)]]
51−customOperatorTable fixities =
52− let
53− applyUserOp name t1 t2 = App (App (Var name) [t1]) [t2]
54− userOps = map (\(name, Fixity a p) -> (name, applyUserOp name, p, a)) . M.toList $ fixities
55− sorted = sortBy (compare `on` (\(_, _, p, _) -> p)) (userOps ++ builtIns)
56− groups = groupBy ((==) `on` (\(_, _, p, _) -> p)) sorted
57− in
58− map (map (\(name, f, _, a) -> (name, f, a))) groups
59−
60−type Chain = [Either Value (Qualified Ident)]
61−
62−matchOperators :: ModuleName -> [[(Qualified Ident, Value -> Value -> Value, Associativity)]] -> Value -> Either String Value
63−matchOperators moduleName ops val = G.everywhereM' (G.mkM parseChains) val
64− where
65− parseChains :: Value -> Either String Value
66− parseChains b@(BinaryNoParens _ _ _) = bracketChain (extendChain b)
67− parseChains other = return other
68− extendChain :: Value -> Chain
69− extendChain (BinaryNoParens name l r) = Left l : Right name : extendChain r
70− extendChain other = [Left other]
71− bracketChain :: Chain -> Either String Value
72− bracketChain = either (Left . show) Right . P.parse (P.buildExpressionParser opTable parseValue <* P.eof) "operator expression"
73− opTable = map (map (\(name, f, a) -> P.Infix (P.try (matchOp moduleName name) >> return f) (toAssoc a))) ops
74− ++ [[P.Infix (P.try (parseOp >>= \ident -> return (\t1 t2 -> App (App (Var ident) [t1]) [t2]))) P.AssocLeft]]
75−
76−toAssoc :: Associativity -> P.Assoc
77−toAssoc Infixl = P.AssocLeft
78−toAssoc Infixr = P.AssocRight
79−
80−parseValue :: P.Parsec Chain () Value
81−parseValue = P.token show (const (P.initialPos "")) (either Just (const Nothing)) P.<?> "expression"
82−
83−parseOp :: P.Parsec Chain () (Qualified Ident)
84−parseOp = P.token show (const (P.initialPos "")) (either (const Nothing) Just) P.<?> "operator"
85−
86−matchOp :: ModuleName -> Qualified Ident -> P.Parsec Chain () ()
87−matchOp moduleName op = do
88− ident <- parseOp
89− guard (qualify moduleName ident == qualify moduleName op)
90−
91−collectFixities :: M.Map (Qualified Ident) Fixity -> ModuleName -> [Declaration] -> Either String (M.Map (Qualified Ident) Fixity)
92−collectFixities m _ [] = return m
93−collectFixities m moduleName (FixityDeclaration fixity name : rest) = do
94− let qual = Qualified (Just moduleName) (Op name)
95− when (qual `M.member` m) (Left $ "redefined fixity for " ++ show name)
96− collectFixities (M.insert qual fixity m) moduleName rest
97−collectFixities m moduleName (ImportDeclaration importedModule _ : rest) = do
98− let fs = [ (i, fixity) | (Qualified mn i, fixity) <- M.toList m, mn == Just importedModule ]
99− forM_ fs $ \(name, _) -> do
100− let qual = Qualified (Just moduleName) name
101− when (qual `M.member` m) (Left $ "redefined fixity for " ++ show name)
102− let m' = M.fromList (map (\(i, fixity) -> (Qualified (Just moduleName) i, fixity)) fs)
103− collectFixities (M.union m' m) moduleName rest
104−collectFixities m moduleName (_:ds) = collectFixities m moduleName ds
105−
106−globalOp :: String -> Qualified Ident
107−globalOp = Qualified Nothing . Op
108−
109−builtIns :: [(Qualified Ident, Value -> Value -> Value, Precedence, Associativity)]
110−builtIns = [ (globalOp "<", Binary LessThan, 3, Infixl)
111− , (globalOp "<=", Binary LessThanOrEqualTo, 3, Infixl)
112− , (globalOp ">", Binary GreaterThan, 3, Infixl)
113− , (globalOp ">=", Binary GreaterThanOrEqualTo, 3, Infixl)
114− , (globalOp "!!", flip Indexer, 4, Infixl)
115− , (globalOp "*", Binary Multiply, 5, Infixl)
116− , (globalOp "/", Binary Divide, 5, Infixl)
117− , (globalOp "%", Binary Modulus, 5, Infixl)
118− , (globalOp "++", Binary Concat, 6, Infixr)
119− , (globalOp "+", Binary Add, 7, Infixl)
120− , (globalOp "-", Binary Subtract, 7, Infixl)
121− , (globalOp "<<", Binary ShiftLeft, 8, Infixl)
122− , (globalOp ">>", Binary ShiftRight, 8, Infixl)
123− , (globalOp ">>>", Binary ZeroFillShiftRight, 8, Infixl)
124− , (globalOp "==", Binary EqualTo, 9, Infixl)
125− , (globalOp "!=", Binary NotEqualTo, 9, Infixl)
126− , (globalOp "&", Binary BitwiseAnd, 10, Infixl)
127− , (globalOp "^", Binary BitwiseXor, 10, Infixl)
128− , (globalOp "|", Binary BitwiseOr, 10, Infixl)
129− , (globalOp "&&", Binary And, 11, Infixr)
130− , (globalOp "||", Binary Or, 11, Infixr)
131− ]
132−
src/Language/PureScript/Sugar/TypeClasses.hsdeleted−133
@@ -1,133 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Sugar.TypeClasses (
16− desugarTypeClasses,
17− mkDictionaryValueName,
18− mkDictionaryEntryName
19−) where
20−
21−import Language.PureScript.Declarations
22−import Language.PureScript.Names
23−import Language.PureScript.Types
24−import Language.PureScript.Values
25−import Language.PureScript.CodeGen.JS.AST
26−import Language.PureScript.Sugar.CaseDeclarations
27−
28−import qualified Data.Map as M
29−
30−import Control.Applicative
31−import Control.Monad.State
32−import Data.Maybe (fromMaybe)
33−import Data.List (nub)
34−import Data.Generics (mkQ, everything)
35−
36−type MemberMap = M.Map (ModuleName, ProperName) (String, [(String, Type)])
37−
38−type Desugar = StateT MemberMap (Either String)
39−
40−desugarTypeClasses :: [Module] -> Either String [Module]
41−desugarTypeClasses = flip evalStateT M.empty . mapM desugarModule
42−
43−desugarModule :: Module -> Desugar Module
44−desugarModule (Module name decls) = Module name <$> concat <$> mapM (desugarDecl (ModuleName name)) decls
45−
46−desugarDecl :: ModuleName -> Declaration -> Desugar [Declaration]
47−desugarDecl mn d@(TypeClassDeclaration name arg members) = do
48− let tys = map memberToNameAndType members
49− modify (M.insert (mn, name) (arg, tys))
50− return $ d : typeClassDictionaryDeclaration name arg members : map (typeClassMemberToDictionaryAccessor name arg) members
51−desugarDecl mn d@(TypeInstanceDeclaration deps name ty members) = do
52− desugared <- lift $ desugarCases members
53− entries <- mapM (typeInstanceDictionaryEntryDeclaration mn deps name ty) desugared
54− dictDecl <- typeInstanceDictionaryDeclaration mn deps name ty desugared
55− return $ d : dictDecl : entries
56−desugarDecl _ other = return [other]
57−
58−memberToNameAndType :: Declaration -> (String, Type)
59−memberToNameAndType (TypeDeclaration ident ty) = (identToString ident, ty)
60−memberToNameAndType _ = error "Invalid declaration in type class definition"
61−
62−typeClassDictionaryDeclaration :: ProperName -> String -> [Declaration] -> Declaration
63−typeClassDictionaryDeclaration name arg members =
64− TypeSynonymDeclaration name [arg] (Object $ rowFromList (map memberToNameAndType members, REmpty))
65−
66−typeClassMemberToDictionaryAccessor :: ProperName -> String -> Declaration -> Declaration
67−typeClassMemberToDictionaryAccessor name arg (TypeDeclaration ident ty) =
68− ExternDeclaration ident
69− (Just (JSFunction (Just ident) [Ident "dict"] (JSBlock [JSReturn (JSAccessor arg (JSVar (Ident "dict")))])))
70− (ForAll arg (ConstrainedType [(Qualified Nothing name, TypeVar arg)] ty))
71−typeClassMemberToDictionaryAccessor _ _ _ = error "Invalid declaration in type class definition"
72−
73−typeInstanceDictionaryDeclaration :: ModuleName -> [(Qualified ProperName, Type)] -> Qualified ProperName -> Type -> [Declaration] -> Desugar Declaration
74−typeInstanceDictionaryDeclaration mn deps name ty decls = do
75− entryName <- lift $ mkDictionaryValueName mn name ty
76− memberNames <- mapM memberToNameAndValue decls
77− return $ ExternDeclaration entryName
78− (Just (JSFunction (Just entryName)
79− (map (\n -> Ident ('_' : show n)) [1..length deps])
80− (JSBlock [JSReturn (JSObjectLiteral memberNames)])))
81− (quantify (Function (map (\(pn, ty') -> TypeApp (TypeConstructor pn) ty') deps) (TypeApp (TypeConstructor name) ty)))
82− where
83− memberToNameAndValue :: Declaration -> Desugar (String, JS)
84− memberToNameAndValue (ValueDeclaration ident _ _ _) = do
85− memberName <- mkDictionaryEntryName mn name ty ident
86− return (identToString ident, JSApp (JSVar memberName) (map (\n -> JSVar (Ident ('_' : show n))) [1..length deps]))
87− memberToNameAndValue _ = error "Invalid declaration in type instance definition"
88−
89−typeInstanceDictionaryEntryDeclaration :: ModuleName -> [(Qualified ProperName, Type)] -> Qualified ProperName -> Type -> Declaration -> Desugar Declaration
90−typeInstanceDictionaryEntryDeclaration mn deps name ty (ValueDeclaration ident [] _ val) = do
91− m <- get
92− let valTy = fromMaybe (error "Type class instance dictionary member is missing in typeInstanceDictionaryEntryDeclaration") $
93− do (arg, members) <- M.lookup (qualify mn name) m
94− ty' <- lookup (identToString ident) members
95− return $ replaceTypeVars arg ty ty'
96− entryName <- mkDictionaryEntryName mn name ty ident
97− return $ ValueDeclaration entryName [] Nothing
98− (TypedValue val (quantify (if null deps then valTy else ConstrainedType deps valTy)))
99−typeInstanceDictionaryEntryDeclaration _ _ _ _ _ = error "Invalid declaration in type instance definition"
100−
101−identToString :: Ident -> String
102−identToString (Ident s) = s
103−identToString (Op _) = error "TODO: Unsupported type class instance name"
104−
105−qualifiedToString :: ModuleName -> Qualified ProperName -> String
106−qualifiedToString mn (Qualified Nothing pn) = qualifiedToString mn (Qualified (Just mn) pn)
107−qualifiedToString _ (Qualified (Just (ModuleName mn)) pn) = runProperName mn ++ "_" ++ runProperName pn
108−
109−quantify :: Type -> Type
110−quantify ty' = foldr ForAll ty' tyVars
111− where
112− tyVars = nub $ everything (++) (mkQ [] collect) ty'
113− collect (TypeVar v) = [v]
114− collect _ = []
115−
116−mkDictionaryValueName :: ModuleName -> Qualified ProperName -> Type -> Either String Ident
117−mkDictionaryValueName mn cl ty = do
118− tyStr <- typeToString mn ty
119− return $ Ident $ "__" ++ qualifiedToString mn cl ++ "_" ++ tyStr
120−
121−typeToString :: ModuleName -> Type -> Either String String
122−typeToString _ String = return "string"
123−typeToString _ Number = return "number"
124−typeToString _ Boolean = return "boolean"
125−typeToString _ (Array (TypeVar _)) = return "array"
126−typeToString mn (TypeConstructor ty') = return $ qualifiedToString mn ty'
127−typeToString mn (TypeApp ty' (TypeVar _)) = typeToString mn ty'
128−typeToString _ _ = Left "Type class instance must be of the form T a1 ... an"
129−
130−mkDictionaryEntryName :: ModuleName -> Qualified ProperName -> Type -> Ident -> Desugar Ident
131−mkDictionaryEntryName mn name ty ident = do
132− Ident dictName <- lift $ mkDictionaryValueName mn name ty
133− return $ Ident $ dictName ++ "_" ++ identToString ident
src/Language/PureScript/Sugar/TypeDeclarations.hsdeleted−35
@@ -1,35 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.Sugar.TypeDeclarations (
16− desugarTypeDeclarations,
17− desugarTypeDeclarationsModule
18−) where
19−
20−import Control.Applicative
21−import Control.Monad.Error.Class
22−import Control.Monad (forM)
23−
24−import Language.PureScript.Declarations
25−import Language.PureScript.Values
26−
27−desugarTypeDeclarationsModule :: [Module] -> Either String [Module]
28−desugarTypeDeclarationsModule ms = forM ms $ \(Module name ds) -> Module name <$> desugarTypeDeclarations ds
29−
30−desugarTypeDeclarations :: [Declaration] -> Either String [Declaration]
31−desugarTypeDeclarations (TypeDeclaration name ty : ValueDeclaration name' [] Nothing val : rest) | name == name' =
32− desugarTypeDeclarations (ValueDeclaration name [] Nothing (TypedValue val ty) : rest)
33−desugarTypeDeclarations (TypeDeclaration name _ : _) = throwError $ "Orphan type declaration for " ++ show name
34−desugarTypeDeclarations (d:ds) = (:) d <$> desugarTypeDeclarations ds
35−desugarTypeDeclarations [] = return []
src/Language/PureScript/TypeChecker.hsdeleted−216
@@ -1,216 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE FlexibleInstances #-}
16−
17−module Language.PureScript.TypeChecker (
18− module T,
19− typeCheckAll
20−) where
21−
22−import Language.PureScript.TypeChecker.Monad as T
23−import Language.PureScript.TypeChecker.Kinds as T
24−import Language.PureScript.TypeChecker.Types as T
25−import Language.PureScript.TypeChecker.Synonyms as T
26−
27−import Data.Data
28−import Data.Generics (mkT, everywhere)
29−import Data.Maybe
30−import qualified Data.Map as M
31−import Control.Monad.State
32−import Control.Monad.Error
33−import Data.Either (rights, lefts)
34−
35−import Language.PureScript.Types
36−import Language.PureScript.Names
37−import Language.PureScript.Kinds
38−import Language.PureScript.Declarations
39−import Language.PureScript.Sugar.TypeClasses
40−
41−addDataType :: ModuleName -> ProperName -> [String] -> [(ProperName, Maybe Type)] -> Kind -> Check ()
42−addDataType moduleName name args dctors ctorKind = do
43− env <- getEnv
44− putEnv $ env { types = M.insert (moduleName, name) (ctorKind, Data) (types env) }
45− forM_ dctors $ \(dctor, maybeTy) ->
46− rethrow (("Error in data constructor " ++ show name ++ ":\n") ++) $
47− addDataConstructor moduleName name args dctor maybeTy
48−
49−addDataConstructor :: ModuleName -> ProperName -> [String] -> ProperName -> Maybe Type -> Check ()
50−addDataConstructor moduleName name args dctor maybeTy = do
51− env <- getEnv
52− dataConstructorIsNotDefined moduleName dctor
53− let retTy = foldl TypeApp (TypeConstructor (Qualified (Just moduleName) name)) (map TypeVar args)
54− let dctorTy = maybe retTy (\ty -> Function [ty] retTy) maybeTy
55− let polyType = mkForAll args dctorTy
56− putEnv $ env { dataConstructors = M.insert (moduleName, dctor) (qualifyAllUnqualifiedNames moduleName env polyType, DataConstructor) (dataConstructors env) }
57−
58−addTypeSynonym :: ModuleName -> ProperName -> [String] -> Type -> Kind -> Check ()
59−addTypeSynonym moduleName name args ty kind = do
60− env <- getEnv
61− putEnv $ env { types = M.insert (moduleName, name) (kind, TypeSynonym) (types env)
62− , typeSynonyms = M.insert (moduleName, name) (args, qualifyAllUnqualifiedNames moduleName env ty) (typeSynonyms env) }
63−
64−typeIsNotDefined :: ModuleName -> ProperName -> Check ()
65−typeIsNotDefined moduleName name = do
66− env <- getEnv
67− guardWith (show name ++ " is already defined") $
68− not $ M.member (moduleName, name) (types env)
69−
70−dataConstructorIsNotDefined :: ModuleName -> ProperName -> Check ()
71−dataConstructorIsNotDefined moduleName dctor = do
72− env <- getEnv
73− guardWith (show dctor ++ " is already defined") $
74− not $ M.member (moduleName, dctor) (dataConstructors env)
75−
76−valueIsNotDefined :: ModuleName -> Ident -> Check ()
77−valueIsNotDefined moduleName name = do
78− env <- getEnv
79− case M.lookup (moduleName, name) (names env) of
80− Just _ -> throwError $ show name ++ " is already defined"
81− Nothing -> return ()
82−
83−addValue :: ModuleName -> Ident -> Type -> Check ()
84−addValue moduleName name ty = do
85− env <- getEnv
86− putEnv (env { names = M.insert (moduleName, name) (qualifyAllUnqualifiedNames moduleName env ty, Value) (names env) })
87−
88−typeCheckAll :: ModuleName -> [Declaration] -> Check [Declaration]
89−typeCheckAll _ [] = return []
90−typeCheckAll moduleName (d@(DataDeclaration name args dctors) : rest) = do
91− rethrow (("Error in type constructor " ++ show name ++ ":\n") ++) $ do
92− typeIsNotDefined moduleName name
93− ctorKind <- kindsOf moduleName name args (mapMaybe snd dctors)
94− addDataType moduleName name args dctors ctorKind
95− ds <- typeCheckAll moduleName rest
96− return $ d : ds
97−typeCheckAll moduleName (d@(DataBindingGroupDeclaration tys) : rest) = do
98− rethrow (("Error in data binding group " ++ show (map (\(name, _, _) -> name) tys) ++ ":\n") ++) $ do
99− forM_ tys $ \(name, _, _) ->
100− typeIsNotDefined moduleName name
101− ks <- kindsOfAll moduleName (map (\(name, args, dctors) -> (name, args, mapMaybe snd dctors)) tys)
102− forM_ (zip tys ks) $ \((name, args, dctors), ctorKind) ->
103− addDataType moduleName name args dctors ctorKind
104− ds <- typeCheckAll moduleName rest
105− return $ d : ds
106−typeCheckAll moduleName (d@(TypeSynonymDeclaration name args ty) : rest) = do
107− rethrow (("Error in type synonym " ++ show name ++ ":\n") ++) $ do
108− typeIsNotDefined moduleName name
109− kind <- kindsOf moduleName name args [ty]
110− addTypeSynonym moduleName name args ty kind
111− ds <- typeCheckAll moduleName rest
112− return $ d : ds
113−typeCheckAll _ (TypeDeclaration _ _ : _) = error "Type declarations should have been removed"
114−typeCheckAll moduleName (ValueDeclaration name [] Nothing val : rest) = do
115− d <- rethrow (("Error in declaration " ++ show name ++ ":\n") ++) $ do
116− valueIsNotDefined moduleName name
117− [(_, (val', ty))] <- typesOf moduleName [(name, val)]
118− addValue moduleName name ty
119− return $ ValueDeclaration name [] Nothing val'
120− ds <- typeCheckAll moduleName rest
121− return $ d : ds
122−typeCheckAll _ (ValueDeclaration _ _ _ _ : _) = error "Binders were not desugared"
123−typeCheckAll moduleName (BindingGroupDeclaration vals : rest) = do
124− d <- rethrow (("Error in binding group " ++ show (map fst vals) ++ ":\n") ++) $ do
125− forM_ (map fst vals) $ \name ->
126− valueIsNotDefined moduleName name
127− tys <- typesOf moduleName vals
128− vals' <- forM (zip (map fst vals) (map snd tys)) $ \(name, (val, ty)) -> do
129− addValue moduleName name ty
130− return (name, val)
131− return $ BindingGroupDeclaration vals'
132− ds <- typeCheckAll moduleName rest
133− return $ d : ds
134−typeCheckAll moduleName (d@(ExternDataDeclaration name kind) : rest) = do
135− env <- getEnv
136− guardWith (show name ++ " is already defined") $ not $ M.member (moduleName, name) (types env)
137− putEnv $ env { types = M.insert (moduleName, name) (kind, TypeSynonym) (types env) }
138− ds <- typeCheckAll moduleName rest
139− return $ d : ds
140−typeCheckAll moduleName (d@(ExternDeclaration name _ ty) : rest) = do
141− rethrow (("Error in foreign import declaration " ++ show name ++ ":\n") ++) $ do
142− env <- getEnv
143− kind <- kindOf moduleName ty
144− guardWith "Expected kind *" $ kind == Star
145− case M.lookup (moduleName, name) (names env) of
146− Just _ -> throwError $ show name ++ " is already defined"
147− Nothing -> putEnv (env { names = M.insert (moduleName, name) (qualifyAllUnqualifiedNames moduleName env ty, Extern) (names env) })
148− ds <- typeCheckAll moduleName rest
149− return $ d : ds
150−typeCheckAll moduleName (d@(FixityDeclaration _ name) : rest) = do
151− ds <- typeCheckAll moduleName rest
152− env <- getEnv
153− guardWith ("Fixity declaration with no binding: " ++ name) $ M.member (moduleName, Op name) $ names env
154− return $ d : ds
155−typeCheckAll currentModule (d@(ImportDeclaration moduleName idents) : rest) = do
156− env <- getEnv
157− rethrow errorMessage $ do
158− guardWith ("Module " ++ show moduleName ++ " does not exist") $ moduleExists env
159− case idents of
160− Nothing -> do
161− shadowIdents (map snd $ filterModule (names env)) env
162− shadowTypes (map snd $ filterModule (types env)) env
163− Just idents' -> do
164− shadowIdents (lefts idents') env
165− shadowTypes (rights idents') env
166− ds <- typeCheckAll currentModule rest
167− return $ d : ds
168− where errorMessage = (("Error in import declaration " ++ show moduleName ++ ":\n") ++)
169− filterModule = filter ((== moduleName) . fst) . M.keys
170− moduleExists env = not (null (filterModule (names env))) || not (null (filterModule (types env)))
171− shadowIdents idents' env =
172− forM_ idents' $ \ident -> do
173− case (moduleName, ident) `M.lookup` names env of
174− Just (_, Alias _ _) -> return ()
175− Just (pt, _) -> do
176− guardWith (show currentModule ++ "." ++ show ident ++ " is already defined") $ (currentModule, ident) `M.notMember` names env
177− modifyEnv (\e -> e { names = M.insert (currentModule, ident) (pt, Alias moduleName ident) (names e) })
178− Nothing -> throwError (show moduleName ++ "." ++ show ident ++ " is undefined")
179− shadowTypes pns env =
180− forM_ pns $ \pn -> do
181− case (moduleName, pn) `M.lookup` types env of
182− Nothing -> throwError (show moduleName ++ "." ++ show pn ++ " is undefined")
183− Just (_, DataAlias _ _) -> return ()
184− Just (k, _) -> do
185− guardWith (show currentModule ++ "." ++ show pn ++ " is already defined") $ (currentModule, pn) `M.notMember` types env
186− modifyEnv (\e -> e { types = M.insert (currentModule, pn) (k, DataAlias moduleName pn) (types e) })
187− let keys = map (snd . fst) . filter (\(_, (fn, _)) -> fn `constructs` pn) . M.toList . dataConstructors $ env
188− forM_ keys $ \dctor -> do
189− case (moduleName, dctor) `M.lookup` dataConstructors env of
190− Just (_, Alias _ _) -> return ()
191− Just (ctorTy, _) -> do
192− guardWith (show currentModule ++ "." ++ show dctor ++ " is already defined") $ (currentModule, dctor) `M.notMember` dataConstructors env
193− modifyEnv (\e -> e { dataConstructors = M.insert (currentModule, dctor) (ctorTy, Alias moduleName (Ident (runProperName dctor))) (dataConstructors e) })
194− Nothing -> throwError (show moduleName ++ "." ++ show dctor ++ " is undefined")
195− constructs (TypeConstructor (Qualified (Just mn) pn')) pn
196− = mn == moduleName && pn' == pn
197− constructs (ForAll _ ty) pn = ty `constructs` pn
198− constructs (Function _ ty) pn = ty `constructs` pn
199− constructs (TypeApp ty _) pn = ty `constructs` pn
200− constructs fn _ = error $ "Invalid arguments to constructs: " ++ show fn
201−typeCheckAll moduleName (d@(TypeClassDeclaration _ _ _) : rest) = do
202− ds <- typeCheckAll moduleName rest
203− return $ d : ds
204−typeCheckAll moduleName (d@(TypeInstanceDeclaration deps className ty _) : rest) = do
205− dictName <- Check . lift $ mkDictionaryValueName moduleName className ty
206− ds <- withTypeClassDictionaries [(dictName, deps, className, ty)] $
207− typeCheckAll moduleName rest
208− return $ d : ds
209−
210−qualifyAllUnqualifiedNames :: (Data d) => ModuleName -> Environment -> d -> d
211−qualifyAllUnqualifiedNames mn env = everywhere (mkT go)
212− where
213− go :: Qualified ProperName -> Qualified ProperName
214− go qual = let (mn', pn') = canonicalizeType mn env qual
215− in Qualified (Just mn') pn'
216−
src/Language/PureScript/TypeChecker/Kinds.hsdeleted−144
@@ -1,144 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−{-# OPTIONS_GHC -fno-warn-orphans #-}
16−{-# LANGUAGE DeriveDataTypeable #-}
17−
18−module Language.PureScript.TypeChecker.Kinds (
19− kindOf,
20− kindsOf,
21− kindsOfAll
22−) where
23−
24−import Language.PureScript.Types
25−import Language.PureScript.Kinds
26−import Language.PureScript.Names
27−import Language.PureScript.TypeChecker.Monad
28−import Language.PureScript.Pretty
29−import Language.PureScript.Unknown
30−
31−import Control.Monad.State
32−import Control.Monad.Error
33−import Control.Monad.Reader
34−
35−import Control.Applicative
36−
37−import qualified Data.Map as M
38−
39−instance Unifiable Kind where
40− unknown = KUnknown
41− isUnknown (KUnknown u) = Just u
42− isUnknown _ = Nothing
43− KUnknown u1 ~~ KUnknown u2 | u1 == u2 = return ()
44− KUnknown u ~~ k = replace u k
45− k ~~ KUnknown u = replace u k
46− Star ~~ Star = return ()
47− Bang ~~ Bang = return ()
48− Row k1 ~~ Row k2 = k1 ~~ k2
49− FunKind k1 k2 ~~ FunKind k3 k4 = do
50− k1 ~~ k3
51− k2 ~~ k4
52− k1 ~~ k2 = throwError $ "Cannot unify " ++ prettyPrintKind k1 ++ " with " ++ prettyPrintKind k2 ++ "."
53− apply s (KUnknown u) = runSubstitution s u
54− apply s (FunKind k1 k2) = FunKind (apply s k1) (apply s k2)
55− apply _ k = k
56− unknowns (KUnknown (Unknown u)) = [u]
57− unknowns (FunKind k1 k2) = unknowns k1 ++ unknowns k2
58− unknowns _ = []
59−
60−kindOf :: ModuleName -> Type -> Check Kind
61−kindOf moduleName ty = fmap (\(k, s) -> apply s k) . runSubst (SubstContext moduleName) $ starIfUnknown <$> infer ty
62−
63−kindsOf :: ModuleName -> ProperName -> [String] -> [Type] -> Check Kind
64−kindsOf moduleName name args ts = fmap (starIfUnknown . (\(k, s) -> apply s k)) . runSubst (SubstContext moduleName) $ do
65− tyCon <- fresh
66− kargs <- replicateM (length args) fresh
67− let dict = (name, tyCon) : zip (map ProperName args) kargs
68− bindLocalTypeVariables moduleName dict $
69− solveTypes ts kargs tyCon
70−
71−kindsOfAll :: ModuleName -> [(ProperName, [String], [Type])] -> Check [Kind]
72−kindsOfAll moduleName tys = fmap (map starIfUnknown . (\(ks, s) -> apply s ks)) . runSubst (SubstContext moduleName) $ do
73− tyCons <- replicateM (length tys) fresh
74− let dict = zipWith (\(name, _, _) tyCon -> (name, tyCon)) tys tyCons
75− bindLocalTypeVariables moduleName dict $
76− zipWithM (\tyCon (_, args, ts) -> do
77− kargs <- replicateM (length args) fresh
78− let argDict = zip (map ProperName args) kargs
79− bindLocalTypeVariables moduleName argDict $
80− solveTypes ts kargs tyCon) tyCons tys
81−
82−solveTypes :: [Type] -> [Kind] -> Kind -> Subst Kind
83−solveTypes ts kargs tyCon = do
84− ks <- mapM infer ts
85− tyCon ~~ foldr FunKind Star kargs
86− forM_ ks $ \k -> k ~~ Star
87− return tyCon
88−
89−starIfUnknown :: Kind -> Kind
90−starIfUnknown (KUnknown _) = Star
91−starIfUnknown (FunKind k1 k2) = FunKind (starIfUnknown k1) (starIfUnknown k2)
92−starIfUnknown k = k
93−
94−infer :: Type -> Subst Kind
95−infer Number = return Star
96−infer String = return Star
97−infer Boolean = return Star
98−infer (Array t) = do
99− k <- infer t
100− k ~~ Star
101− return Star
102−infer (Object row) = do
103− k <- infer row
104− k ~~ Row Star
105− return Star
106−infer (Function args ret) = do
107− ks <- mapM infer args
108− k <- infer ret
109− k ~~ Star
110− forM_ ks (~~ Star)
111− return Star
112−infer (TypeVar v) = do
113− moduleName <- substCurrentModule <$> ask
114− lookupTypeVariable moduleName (Qualified Nothing (ProperName v))
115−infer (TypeConstructor v) = do
116− env <- liftCheck getEnv
117− moduleName <- substCurrentModule `fmap` ask
118− case M.lookup (qualify moduleName v) (types env) of
119− Nothing -> throwError $ "Unknown type constructor '" ++ show v ++ "'"
120− Just (kind, _) -> return kind
121−infer (TypeApp t1 t2) = do
122− k0 <- fresh
123− k1 <- infer t1
124− k2 <- infer t2
125− k1 ~~ FunKind k2 k0
126− return k0
127−infer (ForAll ident ty) = do
128− k <- fresh
129− moduleName <- substCurrentModule <$> ask
130− bindLocalTypeVariables moduleName [(ProperName ident, k)] $ infer ty
131−infer REmpty = do
132− k <- fresh
133− return $ Row k
134−infer (RCons _ ty row) = do
135− k1 <- infer ty
136− k2 <- infer row
137− k2 ~~ Row k1
138− return $ Row k1
139−infer (ConstrainedType deps ty) = do
140− mapM_ (infer . snd) deps
141− k <- infer ty
142− k ~~ Star
143− return Star
144−infer _ = error "Invalid argument to infer"
src/Language/PureScript/TypeChecker/Monad.hsdeleted−235
@@ -1,235 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleInstances, RankNTypes, DeriveDataTypeable,
16− GADTs, StandaloneDeriving, MultiParamTypeClasses, FlexibleContexts #-}
17−
18−module Language.PureScript.TypeChecker.Monad where
19−
20−import Language.PureScript.Types
21−import Language.PureScript.Kinds
22−import Language.PureScript.Names
23−import Language.PureScript.Unknown
24−
25−import Data.Data
26−import Data.Maybe
27−import Data.Monoid
28−import Control.Applicative
29−import Control.Monad.State
30−import Control.Monad.Error
31−import Control.Monad.Reader
32−
33−import qualified Data.Map as M
34−
35−data NameKind
36− = Value
37− | Extern
38− | Alias ModuleName Ident
39− | LocalVariable
40− | DataConstructor deriving Show
41−
42−data TypeDeclarationKind
43− = Data
44− | ExternData
45− | TypeSynonym
46− | DataAlias ModuleName ProperName
47− | LocalTypeVariable deriving Show
48−
49−data Environment = Environment
50− { names :: M.Map (ModuleName, Ident) (Type, NameKind)
51− , types :: M.Map (ModuleName, ProperName) (Kind, TypeDeclarationKind)
52− , dataConstructors :: M.Map (ModuleName, ProperName) (Type, NameKind)
53− , typeSynonyms :: M.Map (ModuleName, ProperName) ([String], Type)
54− , typeClassDictionaries :: [(Ident, [(Qualified ProperName, Type)], Qualified ProperName, Type)]
55− } deriving (Show)
56−
57−emptyEnvironment :: Environment
58−emptyEnvironment = Environment M.empty M.empty M.empty M.empty []
59−
60−bindNames :: (MonadState CheckState m) => M.Map (ModuleName, Ident) (Type, NameKind) -> m a -> m a
61−bindNames newNames action = do
62− orig <- get
63− modify $ \st -> st { checkEnv = (checkEnv st) { names = newNames `M.union` (names . checkEnv $ st) } }
64− a <- action
65− modify $ \st -> st { checkEnv = (checkEnv st) { names = names . checkEnv $ orig } }
66− return a
67−
68−bindTypes :: (MonadState CheckState m) => M.Map (ModuleName, ProperName) (Kind, TypeDeclarationKind) -> m a -> m a
69−bindTypes newNames action = do
70− orig <- get
71− modify $ \st -> st { checkEnv = (checkEnv st) { types = newNames `M.union` (types . checkEnv $ st) } }
72− a <- action
73− modify $ \st -> st { checkEnv = (checkEnv st) { types = types . checkEnv $ orig } }
74− return a
75−
76−withTypeClassDictionaries :: (MonadState CheckState m) => [(Ident, [(Qualified ProperName, Type)], Qualified ProperName, Type)] -> m a -> m a
77−withTypeClassDictionaries entries action = do
78− orig <- get
79− modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = entries ++ (typeClassDictionaries . checkEnv $ st) } }
80− a <- action
81− modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = typeClassDictionaries . checkEnv $ orig } }
82− return a
83−
84−getTypeClassDictionaries :: (Functor m, MonadState CheckState m) => m [(Ident, [(Qualified ProperName, Type)], Qualified ProperName, Type)]
85−getTypeClassDictionaries = typeClassDictionaries . checkEnv <$> get
86−
87−bindLocalVariables :: (Functor m, MonadState CheckState m) => ModuleName -> [(Ident, Type)] -> m a -> m a
88−bindLocalVariables moduleName bindings action =
89− bindNames (M.fromList $ flip map bindings $ \(name, ty) -> ((moduleName, name), (ty, LocalVariable))) action
90−
91−bindLocalTypeVariables :: (Functor m, MonadState CheckState m) => ModuleName -> [(ProperName, Kind)] -> m a -> m a
92−bindLocalTypeVariables moduleName bindings action =
93− bindTypes (M.fromList $ flip map bindings $ \(name, k) -> ((moduleName, name), (k, LocalTypeVariable))) action
94−
95−lookupVariable :: (Functor m, MonadState CheckState m, MonadError String m) => ModuleName -> Qualified Ident -> m Type
96−lookupVariable currentModule (Qualified moduleName var) = do
97− env <- getEnv
98− case M.lookup (fromMaybe currentModule moduleName, var) (names env) of
99− Nothing -> throwError $ show var ++ " is undefined"
100− Just (ty, _) -> return ty
101−
102−lookupTypeVariable :: (Functor m, MonadState CheckState m, MonadError String m) => ModuleName -> Qualified ProperName -> m Kind
103−lookupTypeVariable currentModule (Qualified moduleName name) = do
104− env <- getEnv
105− case M.lookup (fromMaybe currentModule moduleName, name) (types env) of
106− Nothing -> throwError $ "Type variable " ++ show name ++ " is undefined"
107− Just (k, _) -> return k
108−
109−canonicalize :: ModuleName -> Environment -> Qualified Ident -> (ModuleName, Ident)
110−canonicalize _ _ (Qualified (Just mn) i) = (mn, i)
111−canonicalize mn env (Qualified Nothing i) = case (mn, i) `M.lookup` names env of
112− Just (_, Alias mn' i') -> (mn', i')
113− _ -> (mn, i)
114−
115−canonicalizeType :: ModuleName -> Environment -> Qualified ProperName -> (ModuleName, ProperName)
116−canonicalizeType _ _ (Qualified (Just mn) nm) = (mn, nm)
117−canonicalizeType mn env (Qualified Nothing nm) = case (mn, nm) `M.lookup` types env of
118− Just (_, DataAlias mn' pn') -> (mn', pn')
119− _ -> (mn, nm)
120−
121−data CheckState = CheckState { checkEnv :: Environment
122− , checkNextVar :: Int
123− , checkNextDictName :: Int
124− }
125−
126−newtype Check a = Check { unCheck :: StateT CheckState (Either String) a }
127− deriving (Functor, Monad, Applicative, MonadPlus, MonadState CheckState, MonadError String)
128−
129−getEnv :: (Functor m, MonadState CheckState m) => m Environment
130−getEnv = checkEnv <$> get
131−
132−putEnv :: (MonadState CheckState m) => Environment -> m ()
133−putEnv env = modify (\s -> s { checkEnv = env })
134−
135−modifyEnv :: (MonadState CheckState m) => (Environment -> Environment) -> m ()
136−modifyEnv f = modify (\s -> s { checkEnv = f (checkEnv s) })
137−
138−runCheck :: Check a -> Either String (a, Environment)
139−runCheck c = do
140− (a, s) <- flip runStateT (CheckState emptyEnvironment 0 0) $ unCheck c
141− return (a, checkEnv s)
142−
143−guardWith :: (MonadError e m) => e -> Bool -> m ()
144−guardWith _ True = return ()
145−guardWith e False = throwError e
146−
147−rethrow :: (MonadError e m) => (e -> e) -> m a -> m a
148−rethrow f = flip catchError $ \e -> throwError (f e)
149−
150−freshDictionaryName :: Check Int
151−freshDictionaryName = do
152− n <- checkNextDictName <$> get
153− modify $ \s -> s { checkNextDictName = succ (checkNextDictName s) }
154− return n
155−
156−newtype Substitution = Substitution { runSubstitution :: forall t. (Unifiable t) => Unknown t -> t }
157−
158−instance Monoid Substitution where
159− mempty = Substitution unknown
160− s1 `mappend` s2 = Substitution $ \u -> apply s1 (apply s2 (unknown u))
161−
162−data SubstState = SubstState { substSubst :: Substitution }
163−
164−newtype SubstContext = SubstContext { substCurrentModule :: ModuleName } deriving (Show)
165−
166−newtype Subst a = Subst { unSubst :: ReaderT SubstContext (StateT SubstState Check) a }
167− deriving (Functor, Monad, Applicative, MonadPlus, MonadReader SubstContext)
168−
169−instance MonadState CheckState Subst where
170− get = Subst . lift . lift $ get
171− put = Subst . lift . lift . put
172−
173−deriving instance MonadError String Subst
174−
175−liftCheck :: Check a -> Subst a
176−liftCheck = Subst . lift . lift
177−
178−getSubstState :: Subst SubstState
179−getSubstState = Subst . lift $ get
180−
181−runSubst :: SubstContext -> Subst a -> Check (a, Substitution)
182−runSubst context subst = do
183− (a, s) <- flip runStateT (SubstState mempty) . flip runReaderT context . unSubst $ subst
184− return (a, substSubst s)
185−
186−substituteWith :: (Typeable t) => (Unknown t -> t) -> Substitution
187−substituteWith f = Substitution $ \u -> fromMaybe (unknown u) $ do
188− u1 <- cast u
189− cast (f u1)
190−
191−substituteOne :: (Unifiable t) => Unknown t -> t -> Substitution
192−substituteOne u t = substituteWith $ \u1 ->
193− case u1 of
194− u2 | u2 == u -> t
195− | otherwise -> unknown u2
196−
197−replace :: (Unifiable t) => Unknown t -> t -> Subst ()
198−replace u t' = do
199− sub <- substSubst <$> Subst get
200− let t = apply sub t'
201− occursCheck u t
202− let current = apply sub $ unknown u
203− case isUnknown current of
204− Just u1 | u1 == u -> return ()
205− _ -> current ~~ t
206− Subst . modify $ \s -> s { substSubst = substituteOne u t <> substSubst s }
207−
208−class (Typeable t, Data t, Show t) => Unifiable t where
209− unknown :: Unknown t -> t
210− (~~) :: t -> t -> Subst ()
211− isUnknown :: t -> Maybe (Unknown t)
212− apply :: Substitution -> t -> t
213− unknowns :: t -> [Int]
214−
215−instance (Unifiable a) => Unifiable [a] where
216− unknown _ = error "not supported"
217− (~~) = zipWithM_ (~~)
218− isUnknown _ = error "not supported"
219− apply s = map (apply s)
220− unknowns = concatMap unknowns
221−
222−occursCheck :: (Unifiable t) => Unknown s -> t -> Subst ()
223−occursCheck (Unknown u) t =
224− case isUnknown t of
225− Nothing -> guardWith "Occurs check fails" (u `notElem` unknowns t)
226− _ -> return ()
227−
228−fresh' :: Subst Int
229−fresh' = do
230− n <- checkNextVar <$> get
231− modify $ \s -> s { checkNextVar = succ (checkNextVar s) }
232− return n
233−
234−fresh :: (Unifiable t) => Subst t
235−fresh = unknown . Unknown <$> fresh'
src/Language/PureScript/TypeChecker/Synonyms.hsdeleted−49
@@ -1,49 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−module Language.PureScript.TypeChecker.Synonyms (
16− saturateTypeSynonym,
17− saturateAllTypeSynonyms
18−) where
19−
20−import Language.PureScript.Types
21−import Language.PureScript.Names
22−import Language.PureScript.TypeChecker.Monad (Environment(..), canonicalizeType)
23−
24−import Data.Maybe (fromMaybe)
25−import Data.Data
26−import Data.Generics
27−import Data.Generics.Extras
28−import Control.Monad.Writer
29−import Control.Monad.Error
30−
31−buildTypeSubstitution :: Environment -> ModuleName -> (ModuleName, ProperName) -> Int -> Type -> Either String (Maybe Type)
32−buildTypeSubstitution env moduleName name n = go n []
33− where
34− go :: Int -> [Type] -> Type -> Either String (Maybe Type)
35− go 0 args (TypeConstructor ctor) | name == canonicalizeType moduleName env ctor = return (Just $ SaturatedTypeSynonym ctor args)
36− go m _ (TypeConstructor ctor) | m > 0 && name == qualify moduleName ctor = throwError $ "Partially applied type synonym " ++ show name
37− go m args (TypeApp f arg) = go (m - 1) (arg:args) f
38− go _ _ _ = return Nothing
39−
40−saturateTypeSynonym :: (Data d) => Environment -> ModuleName -> (ModuleName, ProperName) -> Int -> d -> Either String d
41−saturateTypeSynonym env moduleName name n = everywhereM' (mkM replace)
42− where
43− replace t = fmap (fromMaybe t) $ buildTypeSubstitution env moduleName name n t
44−
45−saturateAllTypeSynonyms :: (Data d) => Environment -> ModuleName -> [((ModuleName, ProperName), Int)] -> d -> Either String d
46−saturateAllTypeSynonyms env moduleName syns d = foldM (\result (name, n) -> saturateTypeSynonym env moduleName name n result) d syns
47−
48−
49−
src/Language/PureScript/TypeChecker/Types.hsdeleted−794
@@ -1,794 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−{-# OPTIONS_GHC -fno-warn-orphans #-}
16−{-# LANGUAGE DeriveDataTypeable, FlexibleContexts #-}
17−
18−module Language.PureScript.TypeChecker.Types (
19− typesOf
20−) where
21−
22−import Data.List
23−import Data.Maybe (maybeToList, isNothing, isJust, fromMaybe)
24−import qualified Data.Data as D
25−import Data.Generics
26− (mkM, everywhereM, everything, mkT, something, everywhere, mkQ)
27−
28−import Language.PureScript.Values
29−import Language.PureScript.Types
30−import Language.PureScript.Kinds
31−import Language.PureScript.Names
32−import Language.PureScript.TypeChecker.Monad
33−import Language.PureScript.TypeChecker.Kinds
34−import Language.PureScript.TypeChecker.Synonyms
35−import Language.PureScript.Pretty
36−import Language.PureScript.Unknown
37−
38−import Control.Monad.State
39−import Control.Monad.Error
40−import Control.Monad.Reader
41−
42−import Control.Applicative
43−import Control.Arrow (Arrow(..))
44−
45−import qualified Data.Map as M
46−import Data.Function (on)
47−
48−instance Unifiable Type where
49− unknown = TUnknown
50− isUnknown (TUnknown u) = Just u
51− isUnknown _ = Nothing
52− (~~) = unifyTypes
53− apply s (TUnknown u) = runSubstitution s u
54− apply s (SaturatedTypeSynonym name tys) = SaturatedTypeSynonym name $ map (apply s) tys
55− apply s (ForAll idents ty) = ForAll idents $ apply s ty
56− apply s (Array t) = Array (apply s t)
57− apply s (Object r) = Object (apply s r)
58− apply s (Function args ret) = Function (map (apply s) args) (apply s ret)
59− apply s (TypeApp t1 t2) = TypeApp (apply s t1) (apply s t2)
60− apply s (RCons name ty r) = RCons name (apply s ty) (apply s r)
61− apply _ t = t
62− unknowns (TUnknown (Unknown u)) = [u]
63− unknowns (SaturatedTypeSynonym _ tys) = concatMap unknowns tys
64− unknowns (ForAll _ ty) = unknowns ty
65− unknowns (Array t) = unknowns t
66− unknowns (Object r) = unknowns r
67− unknowns (Function args ret) = concatMap unknowns args ++ unknowns ret
68− unknowns (TypeApp t1 t2) = unknowns t1 ++ unknowns t2
69− unknowns (RCons _ ty r) = unknowns ty ++ unknowns r
70− unknowns _ = []
71−
72−unifyTypes :: Type -> Type -> Subst ()
73−unifyTypes t1 t2 = rethrow (\e -> "Error unifying type " ++ prettyPrintType t1 ++ " with type " ++ prettyPrintType t2 ++ ":\n" ++ e) $ do
74− unifyTypes' t1 t2
75− where
76− unifyTypes' (TUnknown u1) (TUnknown u2) | u1 == u2 = return ()
77− unifyTypes' (TUnknown u) t = replace u t
78− unifyTypes' t (TUnknown u) = replace u t
79− unifyTypes' (SaturatedTypeSynonym name args) ty = do
80− ty1 <- expandTypeSynonym name args
81− ty1 `unifyTypes` ty
82− unifyTypes' ty s@(SaturatedTypeSynonym _ _) = s `unifyTypes` ty
83− unifyTypes' (ForAll ident1 ty1) (ForAll ident2 ty2) = do
84− sk <- skolemize ident1 ty1
85− replaced <- replaceVarWithUnknown ident2 ty2
86− sk `unifyTypes` replaced
87− unifyTypes' (ForAll ident ty1) ty2 = do
88− sk <- skolemize ident ty1
89− sk `unifyTypes` ty2
90− unifyTypes' ty f@(ForAll _ _) = f `unifyTypes` ty
91− unifyTypes' Number Number = return ()
92− unifyTypes' String String = return ()
93− unifyTypes' Boolean Boolean = return ()
94− unifyTypes' (Array s) (Array t) = s `unifyTypes` t
95− unifyTypes' (Object row1) (Object row2) = row1 ~~ row2
96− unifyTypes' (Function args1 ret1) (Function args2 ret2) = do
97− guardWith "Function applied to incorrect number of args" $ length args1 == length args2
98− zipWithM_ unifyTypes args1 args2
99− ret1 `unifyTypes` ret2
100− unifyTypes' (TypeVar v1) (TypeVar v2) | v1 == v2 = return ()
101− unifyTypes' (TypeConstructor c1) (TypeConstructor c2) = do
102− env <- getEnv
103− moduleName <- substCurrentModule `fmap` ask
104− guardWith ("Cannot unify " ++ show c1 ++ " with " ++ show c2 ++ ".") (typeConstructorsAreEqual env moduleName c1 c2)
105− unifyTypes' (TypeApp t3 t4) (TypeApp t5 t6) = do
106− t3 `unifyTypes` t5
107− t4 `unifyTypes` t6
108− unifyTypes' (Skolem s1) (Skolem s2) | s1 == s2 = return ()
109− unifyTypes' r1@(RCons _ _ _) r2 = unifyRows r1 r2
110− unifyTypes' r1 r2@(RCons _ _ _) = unifyRows r1 r2
111− unifyTypes' r1@REmpty r2 = unifyRows r1 r2
112− unifyTypes' r1 r2@REmpty = unifyRows r1 r2
113− unifyTypes' t3 t4 = throwError $ "Cannot unify " ++ prettyPrintType t3 ++ " with " ++ prettyPrintType t4 ++ "."
114−
115−unifyRows :: Type -> Type -> Subst ()
116−unifyRows r1 r2 =
117− let
118− (s1, r1') = rowToList r1
119− (s2, r2') = rowToList r2
120− int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
121− sd1 = [ (name, t1) | (name, t1) <- s1, name `notElem` map fst s2 ]
122− sd2 = [ (name, t2) | (name, t2) <- s2, name `notElem` map fst s1 ]
123− in do
124− forM_ int (uncurry (~~))
125− unifyRows' sd1 r1' sd2 r2'
126− where
127− unifyRows' :: [(String, Type)] -> Type -> [(String, Type)] -> Type -> Subst ()
128− unifyRows' [] (TUnknown u) sd r = replace u (rowFromList (sd, r))
129− unifyRows' sd r [] (TUnknown u) = replace u (rowFromList (sd, r))
130− unifyRows' ((name, ty):row) r others u@(TUnknown un) = do
131− occursCheck un ty
132− forM_ row $ \(_, t) -> occursCheck un t
133− u' <- fresh
134− u ~~ RCons name ty u'
135− unifyRows' row r others u'
136− unifyRows' [] REmpty [] REmpty = return ()
137− unifyRows' [] (TypeVar v1) [] (TypeVar v2) | v1 == v2 = return ()
138− unifyRows' [] (Skolem s1) [] (Skolem s2) | s1 == s2 = return ()
139− unifyRows' sd3 r3 sd4 r4 = throwError $ "Cannot unify " ++ prettyPrintRow (rowFromList (sd3, r3)) ++ " with " ++ prettyPrintRow (rowFromList (sd4, r4)) ++ "."
140−
141−typeConstructorsAreEqual :: Environment -> ModuleName -> Qualified ProperName -> Qualified ProperName -> Bool
142−typeConstructorsAreEqual env moduleName = (==) `on` canonicalizeType moduleName env
143−
144−typesOf :: ModuleName -> [(Ident, Value)] -> Check [(Ident, (Value, Type))]
145−typesOf moduleName vals = do
146− tys <- fmap (\(tys, s) -> map (\(ident, (val, ty)) -> (ident, (overTypes (apply s) val, apply s ty))) tys)
147− . runSubst (SubstContext moduleName) $ do
148− let es = map isTyped vals
149− typed = filter (isJust . snd . snd) es
150− untyped = filter (isNothing . snd . snd) es
151− typedDict = map (\(ident, (_, Just ty)) -> (ident, ty)) typed
152− untypedNames <- replicateM (length untyped) fresh
153− let untypedDict = zip (map fst untyped) untypedNames
154− dict = M.fromList (map (\(ident, ty) -> ((moduleName, ident), (ty, LocalVariable))) $ typedDict ++ untypedDict)
155− forM es $ \e -> do
156− triple@(_, (val, ty)) <- case e of
157− (ident, (val, Just ty)) -> do
158− kind <- liftCheck $ kindOf moduleName ty
159− guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star
160− ty' <- replaceAllTypeSynonyms ty
161− val' <- bindNames dict $ check val ty'
162− return (ident, (val', ty'))
163− (ident, (val, Nothing)) -> do
164− TypedValue val' ty <- bindNames dict $ infer val
165− ty ~~ fromMaybe (error "name not found in dictionary") (lookup ident untypedDict)
166− return (ident, (val', ty))
167− when (moduleName == ModuleName (ProperName "Main") && fst e == Ident "main") $ do
168− [eff, a] <- replicateM 2 fresh
169− ty ~~ TypeApp (TypeApp (TypeConstructor (Qualified (Just (ModuleName (ProperName "Eff"))) (ProperName "Eff"))) eff) a
170− escapeCheck val ty
171− return triple
172− forM_ tys $ skolemEscapeCheck . snd . snd
173− forM tys $ \(ident, (val, ty)) -> do
174− val' <- replaceTypeClassDictionaries moduleName val
175− return (ident, (overTypes (desaturateAllTypeSynonyms . setifyAll) $ val'
176− , varIfUnknown . desaturateAllTypeSynonyms . setifyAll $ ty))
177−
178−isTyped :: (Ident, Value) -> (Ident, (Value, Maybe Type))
179−isTyped (name, TypedValue value ty) = (name, (value, Just ty))
180−isTyped (name, value) = (name, (value, Nothing))
181−
182−overTypes :: (Type -> Type) -> Value -> Value
183−overTypes f = everywhere (mkT f)
184−
185−replaceTypeClassDictionaries :: ModuleName -> Value -> Check Value
186−replaceTypeClassDictionaries mn = everywhereM (mkM go)
187− where
188− go (TypeClassDictionary constraint dicts) = entails mn dicts constraint
189− go other = return other
190−
191−entails :: ModuleName -> [(Ident, [(Qualified ProperName, Type)], Qualified ProperName, Type)] -> (Qualified ProperName, Type) -> Check Value
192−entails moduleName context goal = do
193− env <- getEnv
194− case go env goal of
195− [] -> throwError $ "No type class instance for " ++ show goal ++ " in context " ++ show context
196− (dict : _) -> return dict
197− where
198− go env (className, ty) =
199− [ App (Var (Qualified Nothing fnName)) args
200− | (fnName, subgoals, className', ty') <- context
201− , className == className'
202− , subst <- maybeToList $ typeHeadsAreEqual moduleName env ty ty'
203− , args <- forM (replaceAllTypeVars subst subgoals) (go env) ]
204−
205−typeHeadsAreEqual :: ModuleName -> Environment -> Type -> Type -> Maybe [(String, Type)]
206−typeHeadsAreEqual _ _ String String = Just []
207−typeHeadsAreEqual _ _ Number Number = Just []
208−typeHeadsAreEqual _ _ Boolean Boolean = Just []
209−typeHeadsAreEqual _ _ (Skolem s1) (Skolem s2) | s1 == s2 = Just []
210−typeHeadsAreEqual m e (Array ty1) (Array ty2) = typeHeadsAreEqual m e ty1 ty2
211−typeHeadsAreEqual m e (TypeConstructor c1) (TypeConstructor c2) | typeConstructorsAreEqual e m c1 c2 = Just []
212−typeHeadsAreEqual m e (TypeApp h1 (TypeVar v)) (TypeApp h2 arg) = (:) (v, arg) <$> typeHeadsAreEqual m e h1 h2
213−typeHeadsAreEqual m e t1@(TypeApp _ _) t2@(TypeApp _ (TypeVar _)) = typeHeadsAreEqual m e t2 t1
214−typeHeadsAreEqual _ _ _ _ = Nothing
215−
216−escapeCheck :: Value -> Type -> Subst ()
217−escapeCheck value ty = do
218− subst <- substSubst <$> getSubstState
219− let visibleUnknowns = nub $ unknowns $ apply subst ty
220− let allUnknowns = findAllTypes value
221− forM_ allUnknowns $ \t -> do
222− let unsolvedUnknowns = nub . unknowns $ apply subst t
223− guardWith "Escape check fails" $ null $ unsolvedUnknowns \\ visibleUnknowns
224−
225−findAllTypes :: Value -> [Type]
226−findAllTypes = everything (++) (mkQ [] go)
227− where
228− go (TypedValue _ ty) = [ty]
229− go _ = []
230−
231−skolemEscapeCheck :: Type -> Check ()
232−skolemEscapeCheck ty =
233− case something (mkQ Nothing findSkolems) ty of
234− Nothing -> return ()
235− Just _ -> throwError $ "Skolem variables cannot escape. Consider adding a type signature." ++ show ty
236− where
237− findSkolems (Skolem _) = return ()
238− findSkolems _ = mzero
239−
240−setify :: Type -> Type
241−setify = rowFromList . first (M.toList . M.fromList) . rowToList
242−
243−setifyAll :: (D.Data d) => d -> d
244−setifyAll = everywhere (mkT setify)
245−
246−varIfUnknown :: Type -> Type
247−varIfUnknown ty =
248− let unks = nub $ unknowns ty
249− toName = (:) 't' . show
250− ty' = everywhere (mkT typeToVar) $ ty
251− typeToVar :: Type -> Type
252− typeToVar (TUnknown (Unknown u)) = TypeVar (toName u)
253− typeToVar t = t
254− in mkForAll (sort . map toName $ unks) ty'
255−
256−replaceAllTypeVars :: (D.Data d) => [(String, Type)] -> d -> d
257−replaceAllTypeVars = foldl' (\f (name, ty) -> replaceTypeVars name ty . f) id
258−
259−replaceAllVarsWithUnknowns :: Type -> Subst Type
260−replaceAllVarsWithUnknowns (ForAll ident ty) = replaceVarWithUnknown ident ty >>= replaceAllVarsWithUnknowns
261−replaceAllVarsWithUnknowns ty = return ty
262−
263−replaceVarWithUnknown :: String -> Type -> Subst Type
264−replaceVarWithUnknown ident ty = do
265− tu <- fresh
266− return $ replaceTypeVars ident tu $ ty
267−
268−replaceAllTypeSynonyms :: (Functor m, MonadState CheckState m, MonadReader SubstContext m, MonadError String m) => (D.Data d) => d -> m d
269−replaceAllTypeSynonyms d = do
270− env <- getEnv
271− moduleName <- substCurrentModule <$> ask
272− let syns = map (\((path, name), (args, _)) -> ((path, name), length args)) . M.toList $ typeSynonyms env
273− either throwError return $ saturateAllTypeSynonyms env moduleName syns d
274−
275−desaturateAllTypeSynonyms :: (D.Data d) => d -> d
276−desaturateAllTypeSynonyms = everywhere (mkT replaceSaturatedTypeSynonym)
277− where
278− replaceSaturatedTypeSynonym (SaturatedTypeSynonym name args) = foldl TypeApp (TypeConstructor name) args
279− replaceSaturatedTypeSynonym t = t
280−
281−expandTypeSynonym :: Qualified ProperName -> [Type] -> Subst Type
282−expandTypeSynonym name args = do
283− env <- getEnv
284− moduleName <- substCurrentModule `fmap` ask
285− case M.lookup (canonicalizeType moduleName env name) (typeSynonyms env) of
286− Just (synArgs, body) -> return $ replaceAllTypeVars (zip synArgs args) body
287− Nothing -> error "Type synonym was not defined"
288−
289−ensureNoDuplicateProperties :: (MonadError String m) => [(String, Value)] -> m ()
290−ensureNoDuplicateProperties ps = guardWith "Duplicate property names" $ length (nub . map fst $ ps) == length ps
291−
292−infer :: Value -> Subst Value
293−infer val = rethrow (\e -> "Error inferring type of term " ++ prettyPrintValue val ++ ":\n" ++ e) $ infer' val
294−
295−infer' :: Value -> Subst Value
296−infer' v@(NumericLiteral _) = return $ TypedValue v Number
297−infer' v@(StringLiteral _) = return $ TypedValue v String
298−infer' v@(BooleanLiteral _) = return $ TypedValue v Boolean
299−infer' (ArrayLiteral vals) = do
300− ts <- mapM infer vals
301− els <- fresh
302− forM_ ts $ \(TypedValue _ t) -> els ~~ Array t
303− return $ TypedValue (ArrayLiteral ts) els
304−infer' (Unary op val) = do
305− v <- infer val
306− inferUnary op v
307−infer' (Binary op left right) = do
308− v1 <- infer left
309− v2 <- infer right
310− inferBinary op v1 v2
311−infer' (ObjectLiteral ps) = do
312− ensureNoDuplicateProperties ps
313− ts <- mapM (infer . snd) ps
314− let fields = zipWith (\name (TypedValue _ t) -> (name, t)) (map fst ps) ts
315− ty = Object $ rowFromList (fields, REmpty)
316− return $ TypedValue (ObjectLiteral (zip (map fst ps) ts)) ty
317−infer' (ObjectUpdate o ps) = do
318− ensureNoDuplicateProperties ps
319− row <- fresh
320− newVals <- zipWith (\(name, _) t -> (name, t)) ps <$> mapM (infer . snd) ps
321− let newTys = map (\(name, TypedValue _ ty) -> (name, ty)) newVals
322− oldTys <- zip (map fst ps) <$> replicateM (length ps) fresh
323− o' <- check o $ Object $ rowFromList (oldTys, row)
324− return $ TypedValue (ObjectUpdate o' newVals) $ Object $ rowFromList (newTys, row)
325−infer' (Indexer index val) = do
326− el <- fresh
327− index' <- check index Number
328− val' <- check val (Array el)
329− return $ TypedValue (Indexer (TypedValue index' Number) (TypedValue val' (Array el))) el
330−infer' (Accessor prop val) = do
331− typed@(TypedValue _ objTy) <- infer val
332− propTy <- inferProperty objTy prop
333− case propTy of
334− Nothing -> do
335− field <- fresh
336− rest <- fresh
337− objTy `subsumes` Object (RCons prop field rest)
338− return $ TypedValue (Accessor prop typed) field
339− Just ty -> return $ TypedValue (Accessor prop typed) ty
340−infer' (Abs args ret) = do
341− ts <- replicateM (length args) fresh
342− moduleName <- substCurrentModule <$> ask
343− bindLocalVariables moduleName (zip args ts) $ do
344− body@(TypedValue _ bodyTy) <- infer' ret
345− return $ TypedValue (Abs args body) $ Function ts bodyTy
346−infer' (App f args) = do
347− f'@(TypedValue _ ft) <- infer f
348− ret <- fresh
349− app <- checkFunctionApplication f' ft args ret
350− return $ TypedValue app ret
351−infer' (Var var) = do
352− moduleName <- substCurrentModule <$> ask
353− ty <- lookupVariable moduleName var
354− ty' <- replaceAllTypeSynonyms ty
355− case ty' of
356− ConstrainedType constraints _ -> do
357− dicts <- getTypeClassDictionaries
358− return $ TypedValue (App (Var var) (map (flip TypeClassDictionary dicts) constraints)) ty'
359− _ -> return $ TypedValue (Var var) ty'
360−infer' (Block ss) = do
361− ret <- fresh
362− (allCodePathsReturn, _, ss') <- checkBlock M.empty ret ss
363− guardWith "Block is missing a return statement" allCodePathsReturn
364− return $ TypedValue (Block ss') ret
365−infer' v@(Constructor c) = do
366− env <- getEnv
367− moduleName <- substCurrentModule `fmap` ask
368− case M.lookup (qualify moduleName c) (dataConstructors env) of
369− Nothing -> throwError $ "Constructor " ++ show c ++ " is undefined"
370− Just (ty, _) -> do ty' <- replaceAllTypeSynonyms ty
371− return $ TypedValue v ty'
372−infer' (Case vals binders) = do
373− ts <- mapM infer vals
374− ret <- fresh
375− binders' <- checkBinders (map (\(TypedValue _ t) -> t) ts) ret binders
376− return $ TypedValue (Case ts binders') ret
377−infer' (IfThenElse cond th el) = do
378− cond' <- check cond Boolean
379− v2@(TypedValue _ t2) <- infer th
380− v3@(TypedValue _ t3) <- infer el
381− t2 ~~ t3
382− return $ TypedValue (IfThenElse cond' v2 v3) t2
383−infer' (TypedValue val ty) = do
384− moduleName <- substCurrentModule <$> ask
385− kind <- liftCheck $ kindOf moduleName ty
386− guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star
387− ty' <- replaceAllTypeSynonyms ty
388− val' <- check val ty'
389− return $ TypedValue val' ty
390−infer' _ = error "Invalid argument to infer"
391−
392−inferProperty :: Type -> String -> Subst (Maybe Type)
393−inferProperty (Object row) prop = do
394− let (props, _) = rowToList row
395− return $ lookup prop props
396−inferProperty (SaturatedTypeSynonym name args) prop = do
397− replaced <- expandTypeSynonym name args
398− inferProperty replaced prop
399−inferProperty (ForAll ident ty) prop = do
400− replaced <- replaceVarWithUnknown ident ty
401− inferProperty replaced prop
402−inferProperty _ _ = return Nothing
403−
404−inferUnary :: UnaryOperator -> Value -> Subst Value
405−inferUnary op (TypedValue val valTy) =
406− case fromMaybe (error "Invalid operator") $ lookup op unaryOps of
407− (valTy', resTy) -> do
408− valTy' ~~ valTy
409− return $ TypedValue (Unary op val) resTy
410−inferUnary _ _ = error "Invalid arguments to inferUnary"
411−
412−checkUnary :: UnaryOperator -> Value -> Type -> Subst Value
413−checkUnary op val res =
414− case fromMaybe (error "Invalid operator") $ lookup op unaryOps of
415− (valTy, resTy) -> do
416− res ~~ resTy
417− val' <- check val valTy
418− return $ Unary op val'
419−
420−unaryOps :: [(UnaryOperator, (Type, Type))]
421−unaryOps = [ (Negate, (Number, Number))
422− , (Not, (Boolean, Boolean))
423− , (BitwiseNot, (Number, Number))
424− ]
425−
426−inferBinary :: BinaryOperator -> Value -> Value -> Subst Value
427−inferBinary op left@(TypedValue _ leftTy) right@(TypedValue _ rightTy) | isEqualityTest op = do
428− leftTy ~~ rightTy
429− return $ TypedValue (Binary op left right) Boolean
430−inferBinary op left@(TypedValue _ leftTy) right@(TypedValue _ rightTy) =
431− case fromMaybe (error "Invalid operator") $ lookup op binaryOps of
432− (valTy, resTy) -> do
433− leftTy ~~ valTy
434− rightTy ~~ valTy
435− return $ TypedValue (Binary op left right) resTy
436−inferBinary _ _ _ = error "Invalid arguments to inferBinary"
437−
438−checkBinary :: BinaryOperator -> Value -> Value -> Type -> Subst Value
439−checkBinary op left right res | isEqualityTest op = do
440− res ~~ Boolean
441− left'@(TypedValue _ t1) <- infer left
442− right'@(TypedValue _ t2) <- infer right
443− t1 ~~ t2
444− return $ Binary op left' right'
445−checkBinary op left right res =
446− case fromMaybe (error "Invalid operator") $ lookup op binaryOps of
447− (valTy, resTy) -> do
448− res ~~ resTy
449− left' <- check left valTy
450− right' <- check right valTy
451− return $ Binary op left' right'
452−
453−isEqualityTest :: BinaryOperator -> Bool
454−isEqualityTest EqualTo = True
455−isEqualityTest NotEqualTo = True
456−isEqualityTest _ = False
457−
458−binaryOps :: [(BinaryOperator, (Type, Type))]
459−binaryOps = [ (Add, (Number, Number))
460− , (Subtract, (Number, Number))
461− , (Multiply, (Number, Number))
462− , (Divide, (Number, Number))
463− , (Modulus, (Number, Number))
464− , (BitwiseAnd, (Number, Number))
465− , (BitwiseOr, (Number, Number))
466− , (BitwiseXor, (Number, Number))
467− , (ShiftRight, (Number, Number))
468− , (ZeroFillShiftRight, (Number, Number))
469− , (And, (Boolean, Boolean))
470− , (Or, (Boolean, Boolean))
471− , (Concat, (String, String))
472− , (Modulus, (Number, Number))
473− , (LessThan, (Number, Boolean))
474− , (LessThanOrEqualTo, (Number, Boolean))
475− , (GreaterThan, (Number, Boolean))
476− , (GreaterThanOrEqualTo, (Number, Boolean))
477− ]
478−
479−inferBinder :: Type -> Binder -> Subst (M.Map Ident Type)
480−inferBinder _ NullBinder = return M.empty
481−inferBinder val (StringBinder _) = val ~~ String >> return M.empty
482−inferBinder val (NumberBinder _) = val ~~ Number >> return M.empty
483−inferBinder val (BooleanBinder _) = val ~~ Boolean >> return M.empty
484−inferBinder val (VarBinder name) = return $ M.singleton name val
485−inferBinder val (NullaryBinder ctor) = do
486− env <- getEnv
487− moduleName <- substCurrentModule <$> ask
488− case M.lookup (qualify moduleName ctor) (dataConstructors env) of
489− Just (ty, _) -> do
490− ty `subsumes` val
491− return M.empty
492− _ -> throwError $ "Constructor " ++ show ctor ++ " is not defined"
493−inferBinder val (UnaryBinder ctor binder) = do
494− env <- getEnv
495− moduleName <- substCurrentModule <$> ask
496− case M.lookup (qualify moduleName ctor) (dataConstructors env) of
497− Just (ty, _) -> do
498− fn <- replaceAllVarsWithUnknowns ty
499− case fn of
500− Function [obj] ret -> do
501− val `subsumes` ret
502− inferBinder obj binder
503− _ -> throwError $ "Constructor " ++ show ctor ++ " is not a unary constructor"
504− _ -> throwError $ "Constructor " ++ show ctor ++ " is not defined"
505−inferBinder val (ObjectBinder props) = do
506− row <- fresh
507− rest <- fresh
508− m1 <- inferRowProperties row rest props
509− val ~~ Object row
510− return m1
511− where
512− inferRowProperties :: Type -> Type -> [(String, Binder)] -> Subst (M.Map Ident Type)
513− inferRowProperties nrow row [] = nrow ~~ row >> return M.empty
514− inferRowProperties nrow row ((name, binder):binders) = do
515− propTy <- fresh
516− m1 <- inferBinder propTy binder
517− m2 <- inferRowProperties nrow (RCons name propTy row) binders
518− return $ m1 `M.union` m2
519−inferBinder val (ArrayBinder binders) = do
520− el <- fresh
521− m1 <- M.unions <$> mapM (inferBinder el) binders
522− val ~~ Array el
523− return m1
524−inferBinder val (ConsBinder headBinder tailBinder) = do
525− el <- fresh
526− m1 <- inferBinder el headBinder
527− m2 <- inferBinder val tailBinder
528− val ~~ Array el
529− return $ m1 `M.union` m2
530−inferBinder val (NamedBinder name binder) = do
531− m <- inferBinder val binder
532− return $ M.insert name val m
533−
534−checkBinders :: [Type] -> Type -> [([Binder], Maybe Guard, Value)] -> Subst [([Binder], Maybe Guard, Value)]
535−checkBinders _ _ [] = return []
536−checkBinders nvals ret ((binders, grd, val):bs) = do
537− moduleName <- substCurrentModule <$> ask
538− m1 <- M.unions <$> zipWithM inferBinder nvals binders
539− r <- bindLocalVariables moduleName (M.toList m1) $ do
540− val' <- check val ret
541− case grd of
542− Nothing -> return (binders, Nothing, val')
543− Just g -> do
544− g' <- check g Boolean
545− return (binders, Just g', val')
546− rs <- checkBinders nvals ret bs
547− return $ r : rs
548−
549−assignVariable :: Ident -> Subst ()
550−assignVariable name = do
551− env <- checkEnv <$> get
552− moduleName <- substCurrentModule <$> ask
553− case M.lookup (moduleName, name) (names env) of
554− Just (_, LocalVariable) -> throwError $ "Variable with name " ++ show name ++ " already exists."
555− _ -> return ()
556−
557−checkStatement :: M.Map Ident Type -> Type -> Statement -> Subst (Bool, M.Map Ident Type, Statement)
558−checkStatement mass _ (VariableIntroduction name val) = do
559− assignVariable name
560− val'@(TypedValue _ t) <- infer val
561− return (False, M.insert name t mass, VariableIntroduction name val')
562−checkStatement mass _ (Assignment ident val) = do
563− val'@(TypedValue _ t) <- infer val
564− case M.lookup ident mass of
565− Nothing -> throwError $ "No local variable with name " ++ show ident
566− Just ty -> do t ~~ ty
567− return (False, mass, Assignment ident val')
568−checkStatement mass ret (While val inner) = do
569− val' <- check val Boolean
570− (allCodePathsReturn, _, inner') <- checkBlock mass ret inner
571− return (allCodePathsReturn, mass, While val' inner')
572−checkStatement mass ret (If ifst) = do
573− (allCodePathsReturn, ifst') <- checkIfStatement mass ret ifst
574− return (allCodePathsReturn, mass, If ifst')
575−checkStatement mass ret (For ident start end inner) = do
576− moduleName <- substCurrentModule <$> ask
577− assignVariable ident
578− start' <- check start Number
579− end' <- check end Number
580− (allCodePathsReturn, _, inner') <- bindLocalVariables moduleName [(ident, Number)] $ checkBlock mass ret inner
581− return (allCodePathsReturn, mass, For ident start' end' inner')
582−checkStatement mass ret (Return val) = do
583− val' <- check val ret
584− return (True, mass, Return val')
585−
586−checkIfStatement :: M.Map Ident Type -> Type -> IfStatement -> Subst (Bool, IfStatement)
587−checkIfStatement mass ret (IfStatement val thens Nothing) = do
588− val' <- check val Boolean
589− (_, _, thens') <- checkBlock mass ret thens
590− return (False, IfStatement val' thens' Nothing)
591−checkIfStatement mass ret (IfStatement val thens (Just elses)) = do
592− val' <- check val Boolean
593− (allCodePathsReturn1, _, thens') <- checkBlock mass ret thens
594− (allCodePathsReturn2, elses') <- checkElseStatement mass ret elses
595− return (allCodePathsReturn1 && allCodePathsReturn2, IfStatement val' thens' (Just elses'))
596−
597−checkElseStatement :: M.Map Ident Type -> Type -> ElseStatement -> Subst (Bool, ElseStatement)
598−checkElseStatement mass ret (Else elses) = do
599− (allCodePathsReturn, _, elses') <- checkBlock mass ret elses
600− return (allCodePathsReturn, Else elses')
601−checkElseStatement mass ret (ElseIf ifst) = (id *** ElseIf) <$> checkIfStatement mass ret ifst
602−
603−checkBlock :: M.Map Ident Type -> Type -> [Statement] -> Subst (Bool, M.Map Ident Type, [Statement])
604−checkBlock mass _ [] = return (False, mass, [])
605−checkBlock mass ret (s:ss) = do
606− moduleName <- substCurrentModule <$> ask
607− (b1, mass1, s') <- checkStatement mass ret s
608− bindLocalVariables moduleName (M.toList mass1) $ case (b1, ss) of
609− (True, []) -> return (True, mass1, [s'])
610− (True, _) -> throwError "Unreachable code"
611− (False, ss') -> do
612− (b, m, ss'') <- checkBlock mass1 ret ss'
613− return (b, m, s':ss'')
614−
615−skolemize :: String -> Type -> Subst Type
616−skolemize ident ty = do
617− tsk <- Skolem <$> fresh'
618− return $ replaceTypeVars ident tsk ty
619−
620−check :: Value -> Type -> Subst Value
621−check val ty = rethrow errorMessage $ check' val ty
622− where
623− errorMessage msg =
624− "Error checking type of term " ++
625− prettyPrintValue val ++
626− " against type " ++
627− prettyPrintType ty ++
628− ":\n" ++
629− msg
630−
631−check' :: Value -> Type -> Subst Value
632−check' val (ForAll idents ty) = do
633− sk <- skolemize idents ty
634− check val sk
635−check' val (ConstrainedType constraints ty) = do
636− dictNames <- flip mapM constraints $ \(Qualified _ (ProperName className), _) -> do
637− n <- liftCheck freshDictionaryName
638− return $ Ident $ "__dict_" ++ className ++ "_" ++ show n
639− val' <- withTypeClassDictionaries (zipWith (\name (className, instanceTy) -> (name, [], className, instanceTy)) dictNames constraints) $ check val ty
640− return $ Abs dictNames val'
641−check' val u@(TUnknown _) = do
642− val'@(TypedValue _ ty) <- infer val
643− -- Don't unify an unknown with an inferred polytype
644− ty' <- replaceAllVarsWithUnknowns ty
645− ty' ~~ u
646− return val'
647−check' v@(NumericLiteral _) Number = return v
648−check' v@(StringLiteral _) String = return v
649−check' v@(BooleanLiteral _) Boolean = return v
650−check' (Unary op val) ty = checkUnary op val ty
651−check' (Binary op left right) ty = checkBinary op left right ty
652−check' (ArrayLiteral vals) (Array ty) = ArrayLiteral <$> forM vals (\val -> check val ty)
653−check' (Indexer index vals) ty = do
654− index' <- check index Number
655− vals' <- check vals (Array ty)
656− return $ Indexer index' vals'
657−check' (Abs args ret) (Function argTys retTy) = do
658− moduleName <- substCurrentModule <$> ask
659− guardWith "Incorrect number of function arguments" (length args == length argTys)
660− ret' <- bindLocalVariables moduleName (zip args argTys) $ check ret retTy
661− return $ Abs args ret'
662−check' (App f args) ret = do
663− f'@(TypedValue _ ft) <- infer f
664− app <- checkFunctionApplication f' ft args ret
665− return $ app
666−check' (Var var) ty = do
667− moduleName <- substCurrentModule <$> ask
668− ty1 <- lookupVariable moduleName var
669− repl <- replaceAllTypeSynonyms ty1
670− repl `subsumes` ty
671− return $ Var var
672−check' (TypedValue val ty1) ty2 = do
673− moduleName <- substCurrentModule <$> ask
674− kind <- liftCheck $ kindOf moduleName ty1
675− guardWith ("Expected type of kind *, was " ++ prettyPrintKind kind) $ kind == Star
676− ty1 `subsumes` ty2
677− val' <- check val ty1
678− return $ TypedValue val' ty1
679−check' (Case vals binders) ret = do
680− vals' <- mapM infer vals
681− let ts = map (\(TypedValue _ t) -> t) vals'
682− binders' <- checkBinders ts ret binders
683− return $ Case vals' binders'
684−check' (IfThenElse cond th el) ty = do
685− cond' <- check cond Boolean
686− th' <- check th ty
687− el' <- check el ty
688− return $ IfThenElse cond' th' el'
689−check' (ObjectLiteral ps) (Object row) = do
690− ensureNoDuplicateProperties ps
691− ps' <- checkProperties ps row False
692− return $ ObjectLiteral ps'
693−check' (ObjectUpdate obj ps) (Object row) = do
694− ensureNoDuplicateProperties ps
695− us <- zip (map fst ps) <$> replicateM (length ps) fresh
696− let (propsToCheck, rest) = rowToList row
697− propsToRemove = map fst ps
698− remainingProps = filter (\(p, _) -> p `notElem` propsToRemove) propsToCheck
699− obj' <- check obj (Object (rowFromList (us ++ remainingProps, rest)))
700− ps' <- checkProperties ps row True
701− return $ ObjectUpdate obj' ps'
702−check' (Accessor prop val) ty = do
703− rest <- fresh
704− val' <- check val (Object (RCons prop ty rest))
705− return $ Accessor prop val'
706−check' (Block ss) ret = do
707− (allCodePathsReturn, _, ss') <- checkBlock M.empty ret ss
708− guardWith "Block is missing a return statement" allCodePathsReturn
709− return $ Block ss'
710−check' (Constructor c) ty = do
711− env <- getEnv
712− moduleName <- substCurrentModule <$> ask
713− case M.lookup (qualify moduleName c) (dataConstructors env) of
714− Nothing -> throwError $ "Constructor " ++ show c ++ " is undefined"
715− Just (ty1, _) -> do
716− repl <- replaceAllTypeSynonyms ty1
717− repl `subsumes` ty
718− return $ Constructor c
719−check' val (SaturatedTypeSynonym name args) = do
720− ty <- expandTypeSynonym name args
721− check val ty
722−check' val ty = throwError $ prettyPrintValue val ++ " does not have type " ++ prettyPrintType ty
723−
724−checkProperties :: [(String, Value)] -> Type -> Bool -> Subst [(String, Value)]
725−checkProperties ps row lax = let (ts, r') = rowToList row in go ps ts r' where
726− go [] [] REmpty = return []
727− go [] [] u@(TUnknown _) = do u ~~ REmpty
728− return []
729− go [] [] (Skolem _) | lax = return []
730− go [] ((p, _): _) _ | lax = return []
731− | otherwise = throwError $ prettyPrintValue (ObjectLiteral ps) ++ " does not have property " ++ p
732− go ((p,_):_) [] REmpty = throwError $ "Property " ++ p ++ " is not present in closed object type " ++ prettyPrintRow row
733− go ((p,v):ps') [] u@(TUnknown _) = do
734− v'@(TypedValue _ ty) <- infer v
735− rest <- fresh
736− u ~~ RCons p ty rest
737− ps'' <- go ps' [] rest
738− return $ (p, v') : ps''
739− go ((p,v):ps') ts r =
740− case lookup p ts of
741− Nothing -> do
742− v'@(TypedValue _ ty) <- infer v
743− rest <- fresh
744− r ~~ RCons p ty rest
745− ps'' <- go ps' ts rest
746− return $ (p, v') : ps''
747− Just ty -> do
748− v' <- check v ty
749− ps'' <- go ps' (delete (p, ty) ts) r
750− return $ (p, v') : ps''
751− go _ _ _ = throwError $ prettyPrintValue (ObjectLiteral ps) ++ " does not have type " ++ prettyPrintType (Object row)
752−
753−checkFunctionApplication :: Value -> Type -> [Value] -> Type -> Subst Value
754−checkFunctionApplication fn fnTy args ret = rethrow errorMessage $ checkFunctionApplication' fn fnTy args ret
755− where
756− errorMessage msg = "Error applying function of type "
757− ++ prettyPrintType fnTy
758− ++ " to arguments " ++ intercalate ", " (map prettyPrintValue args)
759− ++ ":\n" ++ msg
760−
761−checkFunctionApplication' :: Value -> Type -> [Value] -> Type -> Subst Value
762−checkFunctionApplication' fn (Function argTys retTy) args ret = do
763− guardWith "Incorrect number of function arguments" (length args == length argTys)
764− args' <- zipWithM check args argTys
765− retTy `subsumes` ret
766− return $ App fn args'
767−checkFunctionApplication' fn (ForAll ident ty) args ret = do
768− replaced <- replaceVarWithUnknown ident ty
769− checkFunctionApplication fn replaced args ret
770−checkFunctionApplication' fn u@(TUnknown _) args ret = do
771− args' <- mapM (\arg -> infer arg >>= \(TypedValue v t) -> TypedValue v <$> replaceAllVarsWithUnknowns t) args
772− let tys = map (\(TypedValue _ t) -> t) args'
773− u ~~ Function tys ret
774− return $ App fn args'
775−checkFunctionApplication' fn (SaturatedTypeSynonym name tyArgs) args ret = do
776− ty <- expandTypeSynonym name tyArgs
777− checkFunctionApplication fn ty args ret
778−checkFunctionApplication' fn (ConstrainedType constraints fnTy) args ret = do
779− dicts <- getTypeClassDictionaries
780− checkFunctionApplication' (App fn (map (flip TypeClassDictionary dicts) constraints)) fnTy args ret
781−checkFunctionApplication' _ fnTy args ret = throwError $ "Applying a function of type "
782− ++ prettyPrintType fnTy
783− ++ " to argument(s) " ++ intercalate ", " (map prettyPrintValue args)
784− ++ " does not yield a value of type " ++ prettyPrintType ret ++ "."
785−
786−subsumes :: Type -> Type -> Subst ()
787−subsumes (ForAll ident ty1) ty2 = do
788− replaced <- replaceVarWithUnknown ident ty1
789− replaced `subsumes` ty2
790−subsumes (Function args1 ret1) (Function args2 ret2) = do
791− zipWithM_ subsumes args2 args1
792− ret1 `subsumes` ret2
793−subsumes ty1 ty2 = ty1 ~~ ty2
794−
src/Language/PureScript/Types.hsdeleted−77
@@ -1,77 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE DeriveDataTypeable #-}
16−
17−module Language.PureScript.Types where
18−
19−import Data.Data
20−import Data.Generics (mkT, mkQ, everywhereBut)
21−
22−import Language.PureScript.Names
23−import Language.PureScript.Unknown (Unknown(..))
24−
25−data Type
26− = TUnknown (Unknown Type)
27− | Number
28− | String
29− | Boolean
30− | Array Type
31− | Object Type
32− | Function [Type] Type
33− | TypeVar String
34− | TypeConstructor (Qualified ProperName)
35− | TypeApp Type Type
36− | SaturatedTypeSynonym (Qualified ProperName) [Type]
37− | ForAll String Type
38− | ConstrainedType [(Qualified ProperName, Type)] Type
39− | Skolem Int
40− | REmpty
41− | RCons String Type Type deriving (Show, Eq, Data, Typeable)
42−
43−rowToList :: Type -> ([(String, Type)], Type)
44−rowToList (RCons name ty row) = let (tys, rest) = rowToList row
45− in ((name, ty):tys, rest)
46−rowToList r = ([], r)
47−
48−rowFromList :: ([(String, Type)], Type) -> Type
49−rowFromList ([], r) = r
50−rowFromList ((name, t):ts, r) = RCons name t (rowFromList (ts, r))
51−
52−isMonoType :: Type -> Bool
53−isMonoType (ForAll _ _) = False
54−isMonoType ty = isPolyType ty
55−
56−isPolyType :: Type -> Bool
57−isPolyType (Array ty) = isMonoType ty
58−isPolyType (Object ps) = all isPolyType (map snd . fst $ rowToList ps)
59−isPolyType (Function args ret) = all isPolyType args && isPolyType ret
60−isPolyType (TypeApp t1 t2) = isMonoType t1 && isMonoType t2
61−isPolyType (SaturatedTypeSynonym _ args) = all isPolyType args
62−isPolyType (ForAll _ ty) = isPolyType ty
63−isPolyType _ = True
64−
65−mkForAll :: [String] -> Type -> Type
66−mkForAll = flip . foldl . flip $ ForAll
67−
68−unit :: Type
69−unit = Object REmpty
70−
71−replaceTypeVars :: (Data d) => String -> Type -> d -> d
72−replaceTypeVars name t = everywhereBut (mkQ False isShadowed) (mkT replaceTypeVar)
73− where
74− replaceTypeVar (TypeVar v) | v == name = t
75− replaceTypeVar other = other
76− isShadowed (ForAll v _) | v == name = True
77− isShadowed _ = False
src/Language/PureScript/Unknown.hsdeleted−24
@@ -1,24 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Language.PureScript.Unknown
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.Unknown where
18−
19−import Data.Data
20−
21−newtype Unknown t = Unknown { runUnknown :: Int } deriving (Show, Eq, Ord, Data, Typeable)
22−
23−
24−
src/Language/PureScript/Values.hsdeleted−109
@@ -1,109 +0,0 @@
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−--
13−-----------------------------------------------------------------------------
14−
15−{-# LANGUAGE DeriveDataTypeable #-}
16−
17−module Language.PureScript.Values where
18−
19−import Language.PureScript.Types
20−import Language.PureScript.Names
21−
22−import Data.Data
23−
24−type Guard = Value
25−
26−data UnaryOperator
27− = Negate
28− | Not
29− | BitwiseNot
30− | Positive deriving (Show, Eq, Data, Typeable)
31−
32−data BinaryOperator
33− = Add
34− | Subtract
35− | Multiply
36− | Divide
37− | Modulus
38− | EqualTo
39− | NotEqualTo
40− | LessThan
41− | LessThanOrEqualTo
42− | GreaterThan
43− | GreaterThanOrEqualTo
44− | And
45− | Or
46− | BitwiseAnd
47− | BitwiseOr
48− | BitwiseXor
49− | ShiftLeft
50− | ShiftRight
51− | ZeroFillShiftRight
52− | Concat deriving (Show, Eq, Data, Typeable)
53−
54−data Value
55− = NumericLiteral (Either Integer Double)
56− | StringLiteral String
57− | BooleanLiteral Bool
58− | Unary UnaryOperator Value
59− | Binary BinaryOperator Value Value
60− | BinaryNoParens (Qualified Ident) Value Value
61− | Parens Value
62− | ArrayLiteral [Value]
63− | Indexer Value Value
64− | ObjectLiteral [(String, Value)]
65− | Accessor String Value
66− | ObjectUpdate Value [(String, Value)]
67− | Abs [Ident] Value
68− | App Value [Value]
69− | Var (Qualified Ident)
70− | IfThenElse Value Value Value
71− | Block [Statement]
72− | Constructor (Qualified ProperName)
73− | Case [Value] [([Binder], Maybe Guard, Value)]
74− | TypedValue Value Type
75− | Do Value [DoNotationElement]
76− | TypeClassDictionary (Qualified ProperName, Type) [(Ident, [(Qualified ProperName, Type)], Qualified ProperName, Type)] deriving (Show, Data, Typeable)
77−
78−data DoNotationElement
79− = DoNotationValue Value
80− | DoNotationBind Binder Value
81− | DoNotationLet Binder Value
82− | DoNotationReturn Value deriving (Show, Data, Typeable)
83−
84−data Statement
85− = VariableIntroduction Ident Value
86− | Assignment Ident Value
87− | While Value [Statement]
88− | For Ident Value Value [Statement]
89− | If IfStatement
90− | Return Value deriving (Show, Data, Typeable)
91−
92−data IfStatement = IfStatement Value [Statement] (Maybe ElseStatement) deriving (Show, Data, Typeable)
93−
94−data ElseStatement
95− = Else [Statement]
96− | ElseIf IfStatement deriving (Show, Data, Typeable)
97−
98−data Binder
99− = NullBinder
100− | BooleanBinder Bool
101− | StringBinder String
102− | NumberBinder (Either Integer Double)
103− | VarBinder Ident
104− | NullaryBinder (Qualified ProperName)
105− | UnaryBinder (Qualified ProperName) Binder
106− | ObjectBinder [(String, Binder)]
107− | ArrayBinder [Binder]
108− | ConsBinder Binder Binder
109− | NamedBinder Ident Binder deriving (Show, Data, Typeable)
src/Main.hsdeleted−116
@@ -1,116 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Main
4−-- Copyright : (c) Phil Freeman 2013
5−-- License : MIT
6−--
7−-- Maintainer : Phil Freeman <paf31@cantab.net>
8−-- Stability : experimental
9−-- Portability :
10−--
11−-- |
12−--
13−-----------------------------------------------------------------------------
14−
15−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 "libraries/prelude/prelude.purs"
29−
30−readInput :: Maybe [FilePath] -> IO (Either ParseError [P.Module])
31−readInput Nothing = getContents >>= return . P.runIndentParser P.parseModules
32−readInput (Just input) = fmap (fmap concat . sequence) $ forM input $ \inputFile -> do
33− text <- U.readFile inputFile
34− return $ P.runIndentParser 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 Bool
90−runMain = value $ flag $ (optInfo [ "run-main" ])
91− { optDoc = "Generate code to run the main method in the Main module." }
92−
93−options :: Term P.Options
94−options = P.Options <$> tco <*> performRuntimeTypeChecks <*> magicDo <*> runMain
95−
96−stdInOrInputFiles :: FilePath -> Term (Maybe [FilePath])
97−stdInOrInputFiles prelude = combine <$> useStdIn <*> (not <$> noPrelude) <*> inputFiles
98− where
99− combine False True input = Just (prelude : input)
100− combine False False input = Just input
101− combine True _ _ = Nothing
102−
103−term :: FilePath -> Term (IO ())
104−term prelude = compile <$> options <*> stdInOrInputFiles prelude <*> outputFile <*> externsFile
105−
106−termInfo :: TermInfo
107−termInfo = defTI
108− { termName = "psc"
109− , version = showVersion $ Paths.version
110− , termDoc = "Compiles PureScript to Javascript"
111− }
112−
113−main :: IO ()
114−main = do
115− prelude <- preludeFilename
116− run (term prelude, termInfo)
src/Tests.hsnew file+141
@@ -0,0 +1,141 @@
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.nixnew file+23
@@ -0,0 +1,23 @@
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.yamlnew file+24
@@ -0,0 +1,24 @@
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.gonew file+30
@@ -0,0 +1,30 @@
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-loadernew file+2
@@ -0,0 +1,2 @@
1+module $PROJECT/purescript-native/ffi-loader
2+
support/go.mod.outputnew file+2
@@ -0,0 +1,2 @@
1+module $PROJECT/purescript-native/output
2+
support/go.mod.workingnew file+1
@@ -0,0 +1 @@
1+module $PROJECT/example
test/Spec.hsnew file+2
@@ -0,0 +1,2 @@
1+main :: IO ()
2+main = putStrLn "Test suite not yet implemented"
tests/Main.hsdeleted−71
@@ -1,71 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : Main
4−-- Copyright : (c) Phil Freeman 2013
5−-- License : MIT
6−--
7−-- Maintainer : Phil Freeman <paf31@cantab.net>
8−-- Stability : experimental
9−-- Portability :
10−--
11−-- |
12−--
13−-----------------------------------------------------------------------------
14−
15−module Main (main) where
16−
17−import qualified Language.PureScript as P
18−
19−import Data.List (isSuffixOf)
20−import Control.Applicative
21−import Control.Monad
22−import System.Exit (exitSuccess, exitFailure)
23−import System.FilePath (pathSeparator)
24−import System.Directory (getCurrentDirectory, getDirectoryContents)
25−import qualified System.IO.UTF8 as U
26−import qualified Data.Map as M
27−
28−compile :: FilePath -> IO (Either String P.Environment)
29−compile inputFile = do
30− modules <- P.runIndentParser P.parseModules <$> U.readFile inputFile
31− case modules of
32− Left parseError -> do
33− return (Left $ show parseError)
34− Right ms -> do
35− case P.compile P.defaultOptions ms of
36− Left typeError -> do
37− return (Left typeError)
38− Right (_, _, env) -> do
39− return (Right env)
40−
41−assert :: FilePath -> (Either String P.Environment -> Maybe String) -> IO ()
42−assert inputFile f = do
43− e <- compile inputFile
44− case f e of
45− Just err -> exitFailure
46− Nothing -> return ()
47−
48−assertCompiles :: FilePath -> IO ()
49−assertCompiles inputFile = do
50− putStrLn $ "assert " ++ inputFile ++ " compiles successfully"
51− assert inputFile $ either Just (const Nothing)
52−
53−assertDoesNotCompile :: FilePath -> IO ()
54−assertDoesNotCompile inputFile = do
55− putStrLn $ "assert " ++ inputFile ++ " does not compile"
56− assert inputFile $ either (const Nothing) (const $ Just "Should not have compiled")
57−
58−main :: IO ()
59−main = do
60− cd <- getCurrentDirectory
61− putStrLn $ cd
62− let examples = cd ++ pathSeparator : "examples"
63− let passing = examples ++ pathSeparator : "passing"
64− passingTestCases <- getDirectoryContents passing
65− forM_ passingTestCases $ \inputFile -> when (".purs" `isSuffixOf` inputFile) $
66− assertCompiles (passing ++ pathSeparator : inputFile)
67− let failing = examples ++ pathSeparator : "failing"
68− failingTestCases <- getDirectoryContents failing
69− forM_ failingTestCases $ \inputFile -> when (".purs" `isSuffixOf` inputFile) $
70− assertDoesNotCompile (failing ++ pathSeparator : inputFile)
71− exitSuccess