on master help sign in
.buildkite/pipeline.ymlnew file+18
since splitsnapshots
unifiedsplit
@@ -0,0 +1,18 @@
1+steps:
2+ - label: Build and test with GHC 8.6.5
3+ command: |
4+ nix-build --keep-going --no-out-link --argstr ormoluCompiler ghc865
5+ timeout: 100
6+ - label: Build and test with GHC 8.8.4
7+ command: |
8+ nix-build --keep-going --no-out-link --argstr ormoluCompiler ghc884
9+ timeout: 100
10+ - label: Build and test with GHC 8.10.1
11+ command: |
12+ nix-build --keep-going --no-out-link --argstr ormoluCompiler ghc8101
13+ timeout: 100
14+ - wait
15+ - label: Check formatting
16+ command: |
17+ ./format.sh
18+ git diff --exit-code --color=always
.circleci/config.ymldeleted−34
@@ -1,34 +0,0 @@
1−version: 2
2−jobs:
3− build:
4− docker:
5− - image: mrkkrp/haskell-ghc-8.4.4:0.1.0
6− steps:
7− - checkout
8− - restore_cache:
9− keys:
10− - cabal-packages-{{ checksum "ormolu.cabal" }}
11− - cabal-packages-
12− - restore_cache:
13− keys:
14− - cabal-store-{{ checksum "ormolu.cabal" }}
15− - cabal-store-
16− - run: cabal --version
17− - run: ghc --version
18− - run: cabal update
19− - run: cabal new-build --enable-tests --flags=dev
20− - run: cabal new-test
21− - run: cabal new-haddock
22− - run: cabal new-sdist
23− - save_cache:
24− key: cabal-packages-{{ checksum "ormolu.cabal" }}
25− paths: "~/.cabal/packages"
26− - save_cache:
27− key: cabal-store-{{ checksum "ormolu.cabal" }}
28− paths: "~/.cabal/store"
29−
30−workflows:
31− version: 2
32− build:
33− jobs:
34− - build
.github/workflows/binaries.ymlnew file+39
@@ -0,0 +1,39 @@
1+name: Build binaries
2+on:
3+ release:
4+ types: [published]
5+jobs:
6+ build:
7+ strategy:
8+ fail-fast: false
9+ matrix:
10+ os: [ubuntu-latest, macOS-latest, windows-latest]
11+ runs-on: ${{ matrix.os }}
12+ steps:
13+ - uses: actions/checkout@v2
14+ - uses: actions/setup-haskell@v1
15+ if: runner.os != 'Linux'
16+ with:
17+ ghc-version: '8.10.1'
18+ cabal-version: '3.2'
19+ - name: Build Linux binary
20+ if: runner.os == 'Linux'
21+ run: |
22+ docker run \
23+ -v $(pwd):/mnt -w /mnt \
24+ utdemir/ghc-musl:v14-ghc8101 \
25+ bash .github/workflows/build.sh
26+ - name: Build ${{ runner.os }} binary
27+ if: runner.os != 'Linux'
28+ shell: bash
29+ run: |
30+ cabal build exe:ormolu
31+ cp $(find dist-newstyle \( -name ormolu -o -name ormolu.exe \) -type f) ormolu
32+ - uses: actions/upload-release-asset@v1
33+ env:
34+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
35+ with:
36+ upload_url: ${{ github.event.release.upload_url }}
37+ asset_path: ormolu
38+ asset_name: ormolu-${{ runner.os }}
39+ asset_content_type: application/octet-stream
.github/workflows/build.shnew file+7
@@ -0,0 +1,7 @@
1+set -e
2+
3+cabal update
4+cabal build exe:ormolu --enable-executable-static --ghc-options="-split-sections"
5+
6+cp $(find dist-newstyle -name ormolu -type f) .
7+strip -s ormolu
.gitignore+2
@@ -26,3 +26,5 @@ cabal.sandbox.config
26dist-*/
26dist-*/
27dist/
27dist/
28stack.yaml
28stack.yaml
29+stack.yaml.lock
30+result*
CHANGELOG.md+231
@@ -1,3 +1,234 @@
1+## Unreleased
2+
3+* Ormolu no longer overwrites already formatted files. [PR
4+ 649](https://github.com/tweag/ormolu/pull/649).
5+
6+## Ormolu 0.1.2.0
7+
8+* Fixed the bug when comments in different styles got glued together after
9+ formatting. [Issue 589](https://github.com/tweag/ormolu/issues/589).
10+
11+* Added `-i` as a shortcut for `--mode inplace`. [Issue
12+ 467](https://github.com/tweag/ormolu/issues/467).
13+
14+* Improved grouping of top-level declarations. [Issue
15+ 466](https://github.com/tweag/ormolu/issues/466).
16+
17+## Ormolu 0.1.1.0
18+
19+* Imports in a import lists are now normalized: duplicate imports are
20+ combined/eliminated intelligently.
21+
22+* Import declarations that can be merged are now automatically merged.
23+ [Issue 414](https://github.com/tweag/ormolu/issues/414).
24+
25+* The magic comments for disabling and enabling Ormolu now can encompass any
26+ fragment of code provided that the remaining code after exclusion of the
27+ disabled part is still syntactically correct. [Issue
28+ 601](https://github.com/tweag/ormolu/issues/601).
29+
30+* Improved sorting of operators in imports. [Issue
31+ 602](https://github.com/tweag/ormolu/issues/602).
32+
33+* Fixed a bug related to trailing space in multiline comments in certain
34+ cases. [Issue 603](https://github.com/tweag/ormolu/issues/602).
35+
36+* Added support for formatting linked lists with `(:)` as line terminator.
37+ [Issue 478](https://github.com/tweag/ormolu/issues/478).
38+
39+* Fixed rendering of function arguments in multiline layout. [Issue
40+ 609](https://github.com/tweag/ormolu/issues/609).
41+
42+* Blank lines between definitions in `let` and `while` bindings are now
43+ preserved. [Issue 554](https://github.com/tweag/ormolu/issues/554).
44+
45+* Fixed the bug when type applications stuck to the `$` of TH splices that
46+ followed them. [Issue 613](https://github.com/tweag/ormolu/issues/613).
47+
48+* Improved region formatting so that indented fragments—such as definitions
49+ inside of `where` clauses—can be formatted. [Issue
50+ 572](https://github.com/tweag/ormolu/issues/572).
51+
52+* Fixed the bug related to the de-association of pragma comments. [Issue
53+ 619](https://github.com/tweag/ormolu/issues/619).
54+
55+## Ormolu 0.1.0.0
56+
57+* Fixed rendering of type signatures concerning several identifiers. [Issue
58+ 566](https://github.com/tweag/ormolu/issues/566).
59+
60+* Fixed an idempotence issue with inline comments in tuples and parentheses.
61+ [Issue 450](https://github.com/tweag/ormolu/issues/450).
62+
63+* Fixed an idempotence issue when certain comments were picked up as
64+ “continuation” of a series of comments [Issue
65+ 449](https://github.com/tweag/ormolu/issues/449).
66+
67+* Fixed an idempotence issue related to different indentation levels in a
68+ comment series. [Issue 512](https://github.com/tweag/ormolu/issues/512).
69+
70+* Fixed an idempotence issue related to comments which may happen to be
71+ separated from the elements they are attached to by the equality sign.
72+ [Issue 340](https://github.com/tweag/ormolu/issues/340).
73+
74+* Fixed an idempotence issue with type synonym and data declarations where
75+ the type has a Haddock. [Issue
76+ 578](https://github.com/tweag/ormolu/issues/578).
77+
78+* Fix the false positive about AST differences in presence of comments with
79+ multiple blank lines in a row. [Issue
80+ 518](https://github.com/tweag/ormolu/issues/518).
81+
82+* Fixed rendering of comments around if expressions. [Issue
83+ 458](https://github.com/tweag/ormolu/issues/458).
84+
85+* Unnamed fields of data constructors are now documented using the `-- ^`
86+ syntax. [Issue 445](https://github.com/tweag/ormolu/issues/445) and [Issue
87+ 428](https://github.com/tweag/ormolu/issues/428).
88+
89+* Fixed non-idempotent transformation of partly documented data definition.
90+ [Issue 590](https://github.com/tweag/ormolu/issues/590).
91+
92+* Fixed an idempotence issue related to operators. [Issue
93+ 522](https://github.com/tweag/ormolu/issues/522).
94+
95+* Renamed the `--check-idempotency` flag to `--check-idempotence`.
96+ Apparently only the latter is correct.
97+
98+## Ormolu 0.0.5.0
99+
100+* Grouping of statements in `do`-blocks is now preserved. [Issue
101+ 74](https://github.com/tweag/ormolu/issues/74).
102+
103+* Grouping of TH splices is now preserved. [Issue
104+ 507](https://github.com/tweag/ormolu/issues/507).
105+
106+* Comments on pragmas are now preserved. [Issue
107+ 216](https://github.com/tweag/ormolu/issues/216).
108+
109+* Ormolu can now be enabled and disabled via special comments. [Issue
110+ 435](https://github.com/tweag/ormolu/issues/435).
111+
112+* Added experimental support for simple CPP. [Issue
113+ 415](https://github.com/tweag/ormolu/issues/415).
114+
115+* Added two new options `--start-line` and `--end-line` that allow us to
116+ select a region to format. [Issue
117+ 516](https://github.com/tweag/ormolu/issues/516).
118+
119+* Fixed rendering of module headers in the presence of preceding comments or
120+ Haddocks. [Issue 561](https://github.com/tweag/ormolu/issues/561).
121+
122+## Ormolu 0.0.4.0
123+
124+* When given several files to format, Ormolu does not stop on the first
125+ failure, but tries to format all the files. [Issue
126+ 502](https://github.com/tweag/ormolu/issues/502).
127+
128+* Made rendering of pattern matches involving operators consistent with
129+ other cases of rendering of operators. [Issue
130+ 500](https://github.com/tweag/ormolu/issues/500).
131+
132+* More compact rendering of type family injectivity constraints. [Issue
133+ 482](https://github.com/tweag/ormolu/issues/482).
134+
135+* Improved rendering of the keyword `where` in class, data, and type family
136+ declarations. When headers of these declarations are multi-line `where` is
137+ now put on its own line. [Issue
138+ 509](https://github.com/tweag/ormolu/issues/509).
139+
140+* Fixed the bug pertaining to rendering of arrow notation with multiline
141+ expressions. [Issue 513](https://github.com/tweag/ormolu/issues/513).
142+
143+* Made rendering of data type definitions, value-level applications, and
144+ application of types use the same style. Moreover, existential now doesn't
145+ cause the data constructor be unconditionally rendered in multiline
146+ layout. [Issue 427](https://github.com/tweag/ormolu/issues/427).
147+
148+* Records with a single data constructor are now formatted more compactly.
149+ [Issue 425](https://github.com/tweag/ormolu/issues/425).
150+
151+* Switched to `ghc-lib-parser-8.10.1`.
152+
153+* Implemented support for the new language extensions `ImportQualifiedPost`
154+ and `StandaloneKindSignatures`.
155+
156+## Ormolu 0.0.3.1
157+
158+* Fixed rendering of record updates with the record dot preprocessor syntax
159+ [Issue 498](https://github.com/tweag/ormolu/issues/498).
160+
161+## Ormolu 0.0.3.0
162+
163+* Fixed an issue related to unnecessary use of curly braces. [Issue
164+ 473](https://github.com/tweag/ormolu/issues/473).
165+
166+* Fixed the issue with formatting multi-way if when it happens to be a
167+ function applied to arguments [Issue
168+ 488](https://github.com/tweag/ormolu/issues/488). This changed the way
169+ multi-line if is formatted in general.
170+
171+* Added support for record dot pre-processor when used via the plugin.
172+ [Issue 486](https://github.com/tweag/ormolu/issues/486).
173+
174+* Stopped hanging record constructors and improved placing
175+ potentially-hanging consturctions in the presence of comments. [Issue
176+ 447](https://github.com/tweag/ormolu/issues/447).
177+
178+* Fixed indentation in presence of type applications. [Issue
179+ 493](https://github.com/tweag/ormolu/issues/493).
180+
181+* Class and instance declarations now do not have a blank line after
182+ `where`. Grouping of methods from the original input is also preserved
183+ with some normalizations. [Issue
184+ 431](https://github.com/tweag/ormolu/issues/431).
185+
186+## Ormolu 0.0.2.0
187+
188+* Switched to `ghc-lib-parser` instead of depending on the `ghc` package
189+ directly. This should allow us to use newest features of GHC while not
190+ necessarily depending on the newest version of the compiler. In addition
191+ to that Ormolu is now GHCJS-compatible.
192+
193+* Now unrecognized GHC options passed with `--ghc-opt` cause Ormolu to fail
194+ (exit code 7).
195+
196+* Fixed formatting of result type in closed type families. See [issue
197+ 420](https://github.com/tweag/ormolu/issues/420).
198+
199+* Fixed a minor inconsistency between formatting of normal and foreign type
200+ signatures. See [issue 408](https://github.com/tweag/ormolu/issues/408).
201+
202+* Fixed a bug when comment before module header with Haddock was moved
203+ inside the export list. See [issue
204+ 430](https://github.com/tweag/ormolu/issues/430).
205+
206+* Empty `forall`s are now correctly preserved. See [issue
207+ 429](https://github.com/tweag/ormolu/issues/429).
208+
209+* Fixed [issue 446](https://github.com/tweag/ormolu/issues/446), which
210+ involved braces and operators.
211+
212+* When there are comments between preceding Haddock (pipe-style) and its
213+ corresponding declaration they are preserved like this in the output
214+ instead of being shifted. To be clear, this is not a very good idea to
215+ have comments in that position because the Haddock will end up not being
216+ associated with the declarations. Issues
217+ [440](https://github.com/tweag/ormolu/issues/440) and
218+ [448](https://github.com/tweag/ormolu/issues/448).
219+
220+* Implemented correct handling of shebangs. [Issue
221+ 377](https://github.com/tweag/ormolu/issues/377).
222+
223+* Implemented correct handling of stack headers. [Issue
224+ 393](https://github.com/tweag/ormolu/issues/393).
225+
226+* Sorting language pragmas cannot not change meaning of the input program
227+ anymore. [Issue 404](https://github.com/tweag/ormolu/issues/404).
228+
229+* Fixed formatting of applications where function is a complex expression.
230+ [Issue 444](https://github.com/tweag/ormolu/issues/444).
231+
1## Ormolu 0.0.1.0
232## Ormolu 0.0.1.0
2
233
3* Initial release.
234* Initial release.
CONTRIBUTING.mdnew file+64
@@ -0,0 +1,64 @@
1+# Contributing
2+
3+Issues (bugs, feature requests or otherwise feedback) may be reported in
4+[the GitHub issue tracker for this project][issues]. Pull requests are also
5+welcome.
6+
7+When contributing to this repository, please first discuss the change you
8+wish to make via an issue, unless it's entirely trivial (typo fixes, etc.).
9+If there is already an issue that describes the change you have in mind,
10+comment on it indicating that you're going to work on that. This way we can
11+avoid the situation when several people work on the same thing.
12+
13+Please make sure that all non-trivial changes are described in commit
14+messages and PR descriptions.
15+
16+## What to hack on?
17+
18+* [Fixing bugs][bugs]. This is the main focus right now.
19+
20+### Testing
21+
22+Testing has been taken good care of and now it amounts to just adding
23+examples under `data/examples`. Each example is a pair of files:
24+`<example-name>.hs` for input and `<example-name>-out.hs` for corresponding
25+expected output.
26+
27+Testing is performed as following:
28+
29+* Given snippet of source code is parsed and pretty-printed.
30+* The result of printing is parsed back again and the AST is compared to the
31+ AST obtained from the original file. They should match.
32+* The output of printer is checked against the expected output.
33+* Idempotence property is verified: formatting already formatted code
34+ results in exactly the same output.
35+
36+Examples can be organized in sub-directories, see the existing ones for
37+inspiration.
38+
39+Please note that we try to keep individual files at most 25 lines long
40+because otherwise it's hard to figure out want went wrong when a test fails.
41+
42+## CI
43+
44+We use Circle CI. Some outside contributors may have problems, as in, CI
45+won't run for PRs opened from forks with “unauthorized” errors. In that case
46+the best we can do is to add you as a contributor or to restart your build
47+manually.
48+
49+If you have been added as a contributor but the builds still do not start,
50+try clicking
51+
52+```
53+User settings -> Account integrations -> Refresh permissions
54+```
55+
56+in Circle CI app.
57+
58+## Formatting
59+
60+Use `format.sh` script to format Ormolu with current version of Ormolu. If
61+Ormolu is not formatted like this, the CI will fail.
62+
63+[issues]: https://github.com/tweag/ormolu/issues
64+[bugs]: https://github.com/tweag/ormolu/issues?q=is%3Aissue+is%3Aopen+label%3Abug
DESIGN.md+26−50
@@ -1,5 +1,8 @@
1# Ormolu
1# Ormolu
2
2
3+*This document represents our discussions and plans at early stages of
4+development, it is no longer being updated.*
5+
3* [Analysis of the existing solutions](#analysis-of-the-existing-solutions)
6* [Analysis of the existing solutions](#analysis-of-the-existing-solutions)
4 * [Brittany](#brittany)
7 * [Brittany](#brittany)
5 * [Hindent](#hindent)
8 * [Hindent](#hindent)
@@ -14,14 +17,14 @@
14 * [Testing](#testing)
17 * [Testing](#testing)
15 * [Functionality of executable](#functionality-of-executable)
18 * [Functionality of executable](#functionality-of-executable)
16 * [Why not contribute to/fork Hindent or Brittany?](#why-not-contribute-tofork-hindent-or-brittany)
19 * [Why not contribute to/fork Hindent or Brittany?](#why-not-contribute-tofork-hindent-or-brittany)
17−* [Roadmap](#roadmap)
20+* [Examples](#examples)
18
21
19This document describes design of a new formatter for Haskell source code.
22This document describes design of a new formatter for Haskell source code.
20It also includes recommendations for future implementers.
23It also includes recommendations for future implementers.
21
24
22We set for the following goals (mostly taken from
25We set for the following goals (mostly taken from
23[brittany](https://github.com/lspitzner/brittany)):
26[brittany](https://github.com/lspitzner/brittany)):
24−* Preserve the meaning of the formatted functions;
27+* Preserve the meaning of the formatted functions when no CPP is used;
25* Make reasonable use of screen space;
28* Make reasonable use of screen space;
26* Use linear space and computation time on the size of the input;
29* Use linear space and computation time on the size of the input;
27* Preserve comments;
30* Preserve comments;
@@ -137,8 +140,10 @@ impossible to guess what they'll be called on.
137
140
138### CPP
141### CPP
139
142
140−Formatting a module which uses CPP directives won't be supported. Instead,
143+We allow CPP directives in the input, but we forgo the goal to preserve the
144+meaning of the formatted functions in that case.
145+Instead of supporting CPP better, we hope for a solution to replace CPP to
141−we hope for a solution to replace CPP to do conditional compilation.
146+do conditional compilation.
142
147
143There are the following challenges when formatting a module with CPP:
148There are the following challenges when formatting a module with CPP:
144
149
@@ -177,14 +182,15 @@ True
177```
182```
178
183
179At the time of this writing, formatting this program with Hindent
184At the time of this writing, formatting this program with Hindent
180−produces the same output we would get if the CPP directives were
185+or Ormolu produces the same output we would get if the CPP directives
181−considered comments:
186+were considered comments:
182
187
183```
188```
184−$ hindent --version
189+$ ormolu --version
185−hindent 5.2.7
190+ormolu 0.0.5.0 HEAD fc64eada5c4da7a5b07d2872e253671b48aec115
191+using ghc-lib-parser 8.10.1.20200412
186
192
187−$ hindent test.hs
193+$ ormolu --mode inplace test.hs
188
194
189$ cat test.hs
195$ cat test.hs
190{-# LANGUAGE CPP #-}
196{-# LANGUAGE CPP #-}
@@ -224,9 +230,6 @@ to parse Haskell modules. If CPP is replaced with some language
224extension or mechanism to do conditional compilation, all tools
230extension or mechanism to do conditional compilation, all tools
225will benefit from it.
231will benefit from it.
226
232
227−Therefore, CPP won't be supported. If the CPP extension
228−is enabled, we should signal an error right away.
229−
230### Printing
233### Printing
231
234
232Just pretty-printing code (following the approach of Hindent) seems sane. It
235Just pretty-printing code (following the approach of Hindent) seems sane. It
@@ -282,22 +285,22 @@ map :: (a -> b) -> [a] -> [b]
282foldr :: (a -> b -> b) ->
285foldr :: (a -> b -> b) ->
283 b -> [a] -> [b]
286 b -> [a] -> [b]
284-- Is reformatted to:
287-- Is reformatted to:
285−foldr
288+foldr ::
286− :: (a -> b -> b)
289+ (a -> b -> b) ->
287− -> b
290+ b ->
288− -> [a]
291+ [a] ->
289− -> [b]
292+ [b]
290
293
291t = let x = foo bar
294t = let x = foo bar
292 baz
295 baz
293 in foo bar baz
296 in foo bar baz
294-- Is reformatted to:
297-- Is reformatted to:
295t =
298t =
296− let x =
299+ let x =
297− foo
300+ foo
298− bar
301+ bar
299− baz
302+ baz
300− in foo far baz
303+ in foo far baz
301```
304```
302
305
303Crucially, no effort is made to fit within reasonable line lengths. That's
306Crucially, no effort is made to fit within reasonable line lengths. That's
@@ -388,34 +391,7 @@ also possible that we'll find a nicer way to write pretty-printer.
388
391
389## Examples
392## Examples
390
393
391−A list of formatting examples can be found [here](EXAMPLES.md).
394+A list of formatting examples can be found [here](data/examples).
392−
393−## Roadmap
394−
395−Proposed roadmap (for a single person, about 39 full-time work days):
396−
397−* ~~Create and setup a repo, setup CI (less than 1 day).~~
398−* ~~Implement parsing (2 days).~~
399−* ~~Implement basis for pretty-printing of code. We could take
400− [this][hindent-printer] as inspiration, although AST from the `ghc`
401− package may be slightly different. Also, don't forget about annotations
402− and comments (1 week).~~
403−* Implement executable program so we can easier fool around. Try it on
404− simple code samples (2 days).
405−* Implement location and reading of configuration file in YAML format (2
406− days).
407−* Continue writing the pretty-printing code till we cover everything. Start
408− adding tests, see [the section about testing](#testing). Fix bugs. At this
409− point just repeat this till we cover everything that Brittany and Hindent
410− can do maybe by stealing their tests (at least 2 weeks).
411−* Start checking how our formatter works on real-world code from Hackage.
412− Fix bugs that we find that way (2 weeks).
413−* Write a good readme explaining why the project was created and how it is
414− better, etc (2 days).
415−* Switch CI to Travis and test with multiple GHC versions (1 day).
416−* Make and announce the first public release on Twitter/Reddit (1 day).
417−* Figure out how to use the formatter application with major text editors
418− and add the info to the readme (no estimate).
419
395
420[brittany]: https://hackage.haskell.org/package/brittany
396[brittany]: https://hackage.haskell.org/package/brittany
421[hindent]: https://hackage.haskell.org/package/hindent
397[hindent]: https://hackage.haskell.org/package/hindent
EXAMPLES.mddeleted−296
@@ -1,296 +0,0 @@
1−We aim for a format of Haskell code that minimizes the amount of changes
2−necessary when modifying a line. For instance the indentation of any
3−given fragment of code should not depend on the length of identifiers.
4−
5−```Haskell
6−longFunctionName :: a
7− -> b
8− -> c
9− -> d
10− -> (a, b, c, d)
11−```
12−
13−Renaming the function requires changing all the lines to
14−```Haskell
15−f :: a
16− -> b
17− -> c
18− -> d
19− -> (a, b, c, d)
20−```
21−
22−A preferred alternative is to format like
23−```Haskell
24−longFunctionName
25− :: a
26− -> b
27− -> c
28− -> d
29− -> (a, b, c, d)
30−```
31−
32−We are grabbing some inspiration from
33−[Elm](https://elm-lang.org/docs/style-guide)
34−and
35−[Tweag's](https://github.com/tweag/guides/blob/master/style/Haskell.md)
36−style guides.
37−
38−The following examples show how a program is formatted in
39−multiple lines when the user introduces linebreaks. Otherwise,
40−the programs would be written in one line.
41−
42−### Function types
43−
44−```Haskell
45−functionName
46− :: (C1, C2, C3)
47− => a
48− -> b
49− -> c
50− -> d
51− -> (a, b, c, d)
52−```
53−
54−Context
55−```Haskell
56−functionName
57− :: ( C1
58− , C2
59− , C3
60− , C4
61− , C5
62− )
63− => a
64− -> b
65− -> c
66− -> d
67− -> (a, b, c, d)
68−```
69−
70−Arguments
71−```Haskell
72−functionName
73− :: (C1, C2, C3, C4, C5)
74− => a
75− -> b
76− -> (forall a.
77− (C6, C7)
78− => LongDataTypeName
79− -> a
80− -> AnotherLongDataTypeName
81− -> b
82− -> c
83− )
84− -> (c -> d)
85− -> (a, b, c, d)
86−```
87−
88−```Haskell
89−functionName
90− :: (C1, C2, C3, C4, C5)
91− => a
92− -> b
93− -> ( LongDataTypeName
94− AnotherLongDataTypeName
95− AnotherLongDataTypeName2
96− AnotherLongDataTypeName3
97− -> a
98− -> AnotherLongDataTypeName4
99− -> b
100− -> c
101− )
102− -> (c -> d)
103− -> (a, b, c, d)
104−```
105−
106−### Expressions
107−
108−```Haskell
109−f x y z =
110− if x then longFunctionName y else anotherLongFunctionName z
111−```
112−
113−A lambda
114−```Haskell
115−f =
116− \(LongPattern x) ->
117− longFunctionName x
118−```
119−
120−Multiple lambdas
121−```Haskell
122−f =
123− \(LongPattern x) ->
124− \(LongPattern2 y) ->
125− longFunctionName x
126−```
127−
128−Lambda arguments
129−```Haskell
130−f xs =
131− forM xs $
132− \( LongPattern x
133− , LongPattern2 y
134− ) ->
135− longFunctionName x
136−```
137−
138−There is a do block. Note the change of indentation in the
139−body of `forM`.
140−```Haskell
141−f xs = do
142− forM xs $
143− \( LongPattern x
144− , LongPattern2 y
145− ) ->
146− longFunctionName x
147−```
148−
149−`if` expression
150−```Haskell
151−f x y z =
152− if x then
153− longFunctionName x y
154− else
155− anotherLongFunctionName x z
156−```
157−
158−`if` expression with monadic blocks
159−```Haskell
160−f x y z =
161− if x then do
162− longFunctionName1 x y
163− longFunctionName2 x y
164− else do
165− anotherLongFunctionName1 x z
166− anotherLongFunctionName2 x z
167−```
168−
169−Monadic blocks
170−```Haskell
171−f x y z = do
172− functionName1 x y
173− functionName2 x z
174−```
175−
176−`case` expression
177−```Haskell
178−f x y z = case
179− Just w -> functionName x y w
180− Nothing -> functionName x y z
181−```
182−
183−Branches of `case` expression
184−```Haskell
185−f x y z = case
186− Just w ->
187− longFunctionName x y w
188− Nothing ->
189− anotherLongFunctionName x y z
190−```
191−
192−A list of arguments
193−```Haskell
194−f
195− (LongPattern x)
196− (AnotherLongPattern y)
197− =
198− functionName x y
199−```
200−
201−Guards
202−```Haskell
203−f x y
204− | x > y = True
205− | otherwise = False
206−```
207−
208−The right-hand side of guards
209−```Haskell
210−f x y
211− | x > y =
212− longFunctionName y
213− | otherwise =
214− anotherLongFunctionName x
215−```
216−
217−Long guards
218−```Haskell
219−function x y z w y
220− | x > y
221− , y > z
222− , z > w
223− , w > z
224− =
225− longFunctionName y
226− | otherwise =
227− anotherLongFunctionName x
228−```
229−
230−### Data type declarations
231−
232−Declaration
233−```Haskell
234−data A
235− = B
236− | C
237− | D
238− | E
239− | F
240− | G
241−```
242−
243−TODO: GADTs, record syntax, type families
244−
245−### Comments
246−
247−```Haskell
248−{- When a comment is not preceded with elements on the same line,
249− they are indented as the elements in the enclosing AST node or
250− braces/parenthesis/brackets.
251− If it is between AST nodes, it is indented as the following
252− node.
253− If the end-of-file follows, then indent to column 0.
254−-}
255−
256−f = g {- When there are preceding elements, keep single-line comments in the same line. -}
257−
258−h = g
259−{- Multi-line comments can't be kept on the same line as @h = g@.
260− Otherwise, changing h or g would change the indentation of all
261− the comment lines.
262− -}
263−
264−data R = R
265− {- This comment always follows the R constructor -}
266− { f1 :: T1
267− {- A comment not preceded by other elements -}
268− {- Another comment -}
269− , f2 :: T2
270− , f3 :: T3
271− }
272−```
273−
274−```Haskell
275−{- a comment line -}
276−f = h
277− where
278− h = g
279− -- indented the same as g
280− g = False
281−```
282−
283−This example
284−```Haskell
285−data R = R {- This comment always follows the R constructor -}
286− { f1 :: T1, {- An inner comment -} {- Another inner comment -} f2 :: T2, f3 :: T3}
287−```
288−is reformatted to
289−```Haskell
290−data R = R
291− {- This comment always follows the R constructor -}
292− { f1 :: T1 {- An inner comment -} {- Another inner comment -}
293− , f2 :: T2
294− , f3 :: T3
295− }
296−```
LICENSE.md+1−1
@@ -1,4 +1,4 @@
1−Copyright © 2018 Tweag I/O
1+Copyright © 2018–present Tweag I/O
2
2
3All rights reserved.
3All rights reserved.
4
4
README.md+175−3
@@ -1,9 +1,181 @@
1# Ormolu
1# Ormolu
2
2
3−[![CircleCI](https://circleci.com/gh/tweag/ormolu/tree/master.svg?style=svg&circle-token=cfd37a39265561eb44e608f97cf953cb2a394c03)](https://circleci.com/gh/tweag/ormolu/tree/master)
3+[![License BSD3](https://img.shields.io/badge/license-BSD3-brightgreen.svg)](http://opensource.org/licenses/BSD-3-Clause)
4+[![Hackage](https://img.shields.io/hackage/v/ormolu.svg?style=flat)](https://hackage.haskell.org/package/ormolu)
5+[![Stackage Nightly](http://stackage.org/package/ormolu/badge/nightly)](http://stackage.org/nightly/package/ormolu)
6+[![Stackage LTS](http://stackage.org/package/ormolu/badge/lts)](http://stackage.org/lts/package/ormolu)
7+[![Build status](https://badge.buildkite.com/8e3b0951f3652b77e1c422b361904136a539b0522029156354.svg?branch=master)](https://buildkite.com/tweag-1/ormolu)
4
8
5−Ormolu is a formatter for Haskell source code.
9+Ormolu is a formatter for Haskell source code. The project was created with
10+the following goals in mind:
11+
12+* Using GHC's own parser to avoid parsing problems caused by
13+ [`haskell-src-exts`][haskell-src-exts].
14+* Let some whitespace be programmable. The layout of the input influences
15+ the layout choices in the output. This means that the choices between
16+ single-line/multi-line layouts in each particular situation are made by
17+ the user, not by an algorithm. This makes the implementation simpler and
18+ leaves some control to the user while still guaranteeing that the
19+ formatted code is stylistically consistent.
20+* Writing code in such a way so it's easy to modify and maintain.
21+* Implementing one “true” formatting style which admits no configuration.
22+* That formatting style aims to result in minimal diffs while still
23+ remaining very close to “conventional” Haskell formatting people use.
24+* Choose a style compatible with modern dialects of Haskell. As new Haskell
25+ extensions enter broad use, we may change the style to accommodate them.
26+* Idempotence: formatting already formatted code doesn't change it.
27+* Be well-tested and robust to the point that it can be used in large
28+ projects without exposing unfortunate, disappointing bugs here and there.
29+
30+## Building
31+
32+The easiest way to build the project is with Nix:
33+
34+```console
35+$ nix-build -A ormolu
36+```
37+
38+Or with `cabal-install` from the Nix shell:
39+
40+```console
41+$ nix-shell --run "cabal new-build"
42+```
43+
44+Alternatively, `stack` could be used with a `stack.yaml` file as follows.
45+
46+```console
47+$ cat stack.yaml
48+resolver: lts-16.0
49+packages:
50+- '.'
51+
52+$ stack build # to build
53+$ stack install # to install
54+```
55+
56+To use Ormolu directly from GitHub with Nix, this snippet may come in handy:
57+
58+```nix
59+# This overlay adds Ormolu straight from GitHub.
60+self: super:
61+
62+let source = super.fetchFromGitHub {
63+ owner = "tweag";
64+ repo = "ormolu";
65+ rev = "de279d80122b287374d4ed87c7b630db1f157642"; # update as necessary
66+ sha256 = "0qrxfk62ww6b60ha9sqcgl4nb2n5fhf66a65wszjngwkybwlzmrv"; # as well
67+ };
68+ ormolu = import source { pkgs = self; };
69+in {
70+ haskell = super.haskell // {
71+ packages = super.haskell.packages // {
72+ "${ormolu.ormoluCompiler}" = super.haskell.packages.${ormolu.ormoluCompiler}.override {
73+ overrides = ormolu.ormoluOverlay;
74+ };
75+ };
76+ };
77+}
78+```
79+
80+## Usage
81+
82+The following will print the formatted output to the standard output.
83+
84+```console
85+$ ormolu Module.hs
86+```
87+
88+Add `--mode inplace` to replace the contents of the input file with the
89+formatted output.
90+
91+```console
92+$ ormolu --mode inplace Module.hs
93+```
94+
95+Use `find` to format a tree recursively:
96+
97+```console
98+$ ormolu --mode inplace $(find . -name '*.hs')
99+```
100+
101+## Magic comments
102+
103+Ormolu understands two magic comments:
104+
105+```haskell
106+{- ORMOLU_DISABLE -}
107+```
108+
109+and
110+
111+```haskell
112+{- ORMOLU_ENABLE -}
113+```
114+
115+This allows us to disable formatting selectively for code between these
116+markers or disable it for the entire file. To achieve the latter, just put
117+`{- ORMOLU_DISABLE -}` at the very top. Note that the source code should
118+still be parseable even without the “excluded” part. Because of that the
119+magic comments cannot be placed arbitrary, but should rather enclose
120+independent top-level definitions.
121+
122+## Current limitations
123+
124+* CPP support is experimental. CPP is virtually impossible to handle
125+ correctly, so we process them as a sort of unchangeable snippets. This
126+ works only in simple cases when CPP conditionals surround top-level
127+ declarations. See the [CPP][design-cpp] section in the design notes for
128+ a discussion of the dangers.
129+* Input modules should be parsable by Haddock, which is a bit stricter
130+ criterion than just being valid Haskell modules.
131+* Various minor idempotence issues, most of them are related to comments.
132+
133+## Running on Hackage
134+
135+It's possible to try Ormolu on arbitrary packages from Hackage. For that
136+execute (from the root of the cloned repo):
137+
138+```console
139+$ nix-build -A hackage.<package>
140+```
141+
142+Then inspect `result/log.txt` for possible problems. The derivation will
143+also contain formatted `.hs` files for inspection and original inputs with
144+`.hs-original` extension (those are with CPP dropped, exactly what is fed
145+into Ormolu).
146+
147+## Editor integration
148+
149+We know of the following editor integrations:
150+
151+* [Emacs][emacs-package]
152+* [VS Code][vs-code-plugin]
153+* vim: [neoformat][neoformat], [vim-ormolu][vim-ormolu]
154+
155+## Arch Linux
156+
157+To install Ormolu on Arch Linux, one can use [the package on AUR][aur]:
158+
159+```console
160+yay -S ormolu
161+```
162+
163+## Contributing
164+
165+See [CONTRIBUTING.md][contributing].
6
166
7## License
167## License
8
168
169+See [LICENSE.md][license].
170+
9−Copyright © 2018–2019 Tweag I/O
171+Copyright © 2018–present Tweag I/O
172+
173+[design-cpp]: https://github.com/tweag/ormolu/blob/master/DESIGN.md#cpp
174+[contributing]: https://github.com/tweag/ormolu/blob/master/CONTRIBUTING.md
175+[license]: https://github.com/tweag/ormolu/blob/master/LICENSE.md
176+[haskell-src-exts]: https://hackage.haskell.org/package/haskell-src-exts
177+[emacs-package]: https://github.com/vyorkin/ormolu.el
178+[vs-code-plugin]: https://marketplace.visualstudio.com/items?itemName=sjurmillidahl.ormolu-vscode
179+[vim-ormolu]: https://github.com/sdiehl/vim-ormolu
180+[neoformat]: https://github.com/sbdchd/neoformat
181+[aur]: https://aur.archlinux.org/packages/ormolu
app/Main.hs+161−91
@@ -1,133 +1,203 @@
1−{-# LANGUAGE CPP #-}
1+{-# LANGUAGE CPP #-}
2−{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE LambdaCase #-}
3{-# LANGUAGE RecordWildCards #-}
3{-# LANGUAGE RecordWildCards #-}
4{-# LANGUAGE TemplateHaskell #-}
4{-# LANGUAGE TemplateHaskell #-}
5+{-# LANGUAGE TypeApplications #-}
5
6
6module Main (main) where
7module Main (main) where
7
8
9+import Control.Exception (SomeException, displayException, try)
8import Control.Monad
10import Control.Monad
11+import Data.Bool (bool)
12+import Data.Either (lefts)
9−import Data.List (intercalate)
13+import Data.List (intercalate, sort)
14+import qualified Data.Text.IO as TIO
10import Data.Version (showVersion)
15import Data.Version (showVersion)
11import Development.GitRev
16import Development.GitRev
12import Options.Applicative
17import Options.Applicative
13import Ormolu
18import Ormolu
19+import Ormolu.Parser (manualExts)
20+import Ormolu.Utils (showOutputable)
14import Paths_ormolu (version)
21import Paths_ormolu (version)
15−import System.Exit (exitFailure)
22+import System.Exit (ExitCode (..), exitWith)
16−import qualified Data.Text.IO as TIO
23+import System.IO (hPutStrLn, stderr)
17−import qualified Data.Yaml as Yaml
18
24
19-- | Entry point of the program.
25-- | Entry point of the program.
20−
21main :: IO ()
26main :: IO ()
22main = withPrettyOrmoluExceptions $ do
27main = withPrettyOrmoluExceptions $ do
23 Opts {..} <- execParser optsParserInfo
28 Opts {..} <- execParser optsParserInfo
24− config <- case optConfigFile of
29+ let formatOne' = formatOne optMode optConfig
25− Nothing -> return optConfig
30+ case optInputFiles of
26− Just path -> do
31+ [] -> formatOne' Nothing
27− config <- Yaml.decodeFileThrow path
32+ ["-"] -> formatOne' Nothing
28− return (config <> optConfig)
33+ [x] -> formatOne' (Just x)
29− r <- ormoluFile config optInputFile
34+ xs -> do
30− case optMode of
35+ -- It is possible to get IOException, error's and 'OrmoluException's
31− Stdout ->
36+ -- from 'formatOne', so we just catch everything.
37+ errs <-
38+ lefts <$> mapM (try @SomeException . formatOne' . Just) (sort xs)
39+ unless (null errs) $ do
40+ mapM_ (hPutStrLn stderr . displayException) errs
41+ exitWith (ExitFailure 102)
42+
43+-- | Format a single input.
44+formatOne ::
45+ -- | Mode of operation
46+ Mode ->
47+ -- | Configuration
48+ Config RegionIndices ->
49+ -- | File to format or stdin as 'Nothing'
50+ Maybe FilePath ->
51+ IO ()
52+formatOne mode config = \case
53+ Nothing -> do
54+ r <- ormoluStdin config
55+ case mode of
32− TIO.putStr r
56+ Stdout -> TIO.putStr r
57+ _ -> do
58+ hPutStrLn
59+ stderr
60+ "This feature is not supported when input comes from stdin."
61+ -- 101 is different from all the other exit codes we already use.
62+ exitWith (ExitFailure 101)
63+ Just inputFile -> do
64+ originalInput <- TIO.readFile inputFile
65+ formattedInput <- ormoluFile config inputFile
66+ case mode of
67+ Stdout ->
68+ TIO.putStr formattedInput
33− InPlace ->
69+ InPlace -> do
70+ -- Only write when the contents have changed, in order to avoid
71+ -- updating the modified timestamp if the file was already correctly
72+ -- formatted.
73+ when (formattedInput /= originalInput) $
34− TIO.writeFile optInputFile r
74+ TIO.writeFile inputFile formattedInput
35− Check -> do
75+ Check -> do
36− r' <- TIO.readFile optInputFile
76+ when (formattedInput /= originalInput) $
37− when (r /= r') exitFailure
77+ -- 100 is different to all the other exit code that are emitted
78+ -- either from an 'OrmoluException' or from 'error' and
79+ -- 'notImplemented'.
80+ exitWith (ExitFailure 100)
38
81
39----------------------------------------------------------------------------
82----------------------------------------------------------------------------
40-- Command line options parsing.
83-- Command line options parsing.
41
84
42data Opts = Opts
85data Opts = Opts
43− { optMode :: !Mode
44− -- ^ Mode of operation
86+ { -- | Mode of operation
45− , optConfigFile :: !(Maybe FilePath)
87+ optMode :: !Mode,
46− -- ^ Location of configuration file (optional)
47− , optConfig :: !Config
48− -- ^ Ormolu 'Config'
88+ -- | Ormolu 'Config'
49− , optInputFile :: !FilePath
89+ optConfig :: !(Config RegionIndices),
50− -- ^ Input source file
90+ -- | Haskell source files to format or stdin (when the list is empty)
91+ optInputFiles :: ![FilePath]
51 }
92 }
52
93
53-- | Mode of operation.
94-- | Mode of operation.
54−
55data Mode
95data Mode
56− = Stdout -- ^ Output formatted source code to stdout
96+ = -- | Output formatted source code to stdout
97+ Stdout
57− | InPlace -- ^ Overwrite original file
98+ | -- | Overwrite original file
99+ InPlace
58− | Check -- ^ Exit with non-zero status code if
100+ | -- | Exit with non-zero status code if
59− -- source is not already formatted
101+ -- source is not already formatted
102+ Check
60 deriving (Eq, Show)
103 deriving (Eq, Show)
61
104
62optsParserInfo :: ParserInfo Opts
105optsParserInfo :: ParserInfo Opts
106+optsParserInfo =
63−optsParserInfo = info (helper <*> ver <*> optsParser) . mconcat $
107+ info (helper <*> ver <*> exts <*> optsParser) . mconcat $
64− [ fullDesc
108+ [ fullDesc,
65− , progDesc ""
109+ progDesc "",
66− , header ""
110+ header ""
67− ]
111+ ]
68 where
112 where
69 ver :: Parser (a -> a)
113 ver :: Parser (a -> a)
114+ ver =
70− ver = infoOption verStr . mconcat $
115+ infoOption verStr . mconcat $
71− [ long "version"
116+ [ long "version",
72− , short 'v'
117+ short 'v',
73− , help "Print version of the program"
118+ help "Print version of the program"
74− ]
75− verStr = intercalate "\n"
76− [ unwords
77− [ "ormolu"
78− , showVersion version
79− , $gitBranch
80− , $gitHash
81 ]
119 ]
82− , "using ghc-exactprint " ++ VERSION_ghc_exactprint
120+ verStr =
83− , "using ghc " ++ VERSION_ghc
121+ intercalate
122+ "\n"
123+ [ unwords
124+ [ "ormolu",
125+ showVersion version,
126+ $gitBranch,
127+ $gitHash
128+ ],
129+ "using ghc-lib-parser " ++ VERSION_ghc_lib_parser
130+ ]
131+ exts :: Parser (a -> a)
132+ exts =
133+ infoOption displayExts . mconcat $
134+ [ long "manual-exts",
135+ help "Display extensions that need to be enabled manually"
84− ]
136+ ]
137+ displayExts = unlines $ sort (showOutputable <$> manualExts)
85
138
86optsParser :: Parser Opts
139optsParser :: Parser Opts
87−optsParser = Opts
140+optsParser =
141+ Opts
142+ <$> ( (fmap (bool Stdout InPlace) . switch . mconcat)
143+ [ short 'i',
144+ help "A shortcut for --mode inplace"
145+ ]
88− <$> (option parseMode . mconcat)
146+ <|> (option parseMode . mconcat)
89− [ long "mode"
147+ [ long "mode",
90− , short 'm'
148+ short 'm',
91− , metavar "MODE"
149+ metavar "MODE",
92− , value Stdout
150+ value Stdout,
93− , help "Mode of operation: 'stdout', 'inplace', or 'check'"
151+ help "Mode of operation: 'stdout' (default), 'inplace', or 'check'"
94− ]
152+ ]
95− <*> (optional . strOption . mconcat)
153+ )
96− [ long "config"
97− , short 'c'
98− , metavar "CONFIG"
99− , help "Location of configuration file"
100− ]
101− <*> configParser
154+ <*> configParser
102− <*> (strArgument . mconcat)
155+ <*> (many . strArgument . mconcat)
103− [ metavar "FILE"
156+ [ metavar "FILE",
104− , help "Haskell source file to format"
157+ help "Haskell source files to format or stdin (default)"
105− ]
158+ ]
106
159
107−configParser :: Parser Config
160+configParser :: Parser (Config RegionIndices)
108−configParser = Config
161+configParser =
162+ Config
109− <$> (fmap (fmap DynOption) . many . strOption . mconcat)
163+ <$> (fmap (fmap DynOption) . many . strOption . mconcat)
110− [ long "ghc-opt"
164+ [ long "ghc-opt",
111− , short 'o'
165+ short 'o',
112− , metavar "OPT"
166+ metavar "OPT",
113− , help "GHC options to enable (e.g. language extensions)"
167+ help "GHC options to enable (e.g. language extensions)"
114− ]
168+ ]
115− <*> (switch . mconcat)
169+ <*> (switch . mconcat)
116− [ long "unsafe"
170+ [ long "unsafe",
117− , short 'u'
171+ short 'u',
118− , help "Do formatting faster but without automatic detection of defects"
172+ help "Do formatting faster but without automatic detection of defects"
119− ]
173+ ]
120− <*> (switch . mconcat)
174+ <*> (switch . mconcat)
121− [ long "debug"
175+ [ long "debug",
122− , short 'd'
176+ short 'd',
123− , help "Output information useful for debugging"
177+ help "Output information useful for debugging"
178+ ]
179+ <*> (switch . mconcat)
180+ [ long "check-idempotence",
181+ short 'c',
182+ help "Fail if formatting is not idempotent"
124− ]
183+ ]
184+ <*> ( RegionIndices
185+ <$> (optional . option auto . mconcat)
186+ [ long "start-line",
187+ metavar "START",
188+ help "Start line of the region to format (starts from 1)"
189+ ]
190+ <*> (optional . option auto . mconcat)
191+ [ long "end-line",
192+ metavar "END",
193+ help "End line of the region to format (inclusive)"
194+ ]
195+ )
125
196
126----------------------------------------------------------------------------
197----------------------------------------------------------------------------
127-- Helpers
198-- Helpers
128
199
129-- | Parse 'Mode'.
200-- | Parse 'Mode'.
130−
131parseMode :: ReadM Mode
201parseMode :: ReadM Mode
132parseMode = eitherReader $ \case
202parseMode = eitherReader $ \case
133 "stdout" -> Right Stdout
203 "stdout" -> Right Stdout
data/examples/declaration/annotation/annotation-out.hsnew file+22
@@ -0,0 +1,22 @@
1+{-# ANN module (5 :: Int) #-}
2+
3+{-# ANN
4+ module
5+ ( 5 ::
6+ Int
7+ )
8+ #-}
9+
10+{-# ANN foo "hey" #-}
11+foo :: Int
12+foo = 5
13+
14+{-# ANN
15+ Char
16+ (Just 42)
17+ #-}
18+
19+data Foo = Foo Int
20+{-# ANN type Foo ("HLint: ignore") #-}
21+
22+{- Comment -}
data/examples/declaration/annotation/annotation.hsnew file+20
@@ -0,0 +1,20 @@
1+{-#ANN module (5 :: Int)#-}
2+
3+{-# ANN module (5
4+ :: Int)#-}
5+
6+{-# ANN foo "hey" #-}
7+
8+foo :: Int
9+foo = 5
10+
11+{-# ANN
12+ Char
13+
14+ (Just 42)#-}
15+
16+data Foo = Foo Int
17+
18+{-# ANN type Foo ("HLint: ignore") #-}
19+
20+{- Comment -}
data/examples/declaration/class/associated-data1-out.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+class Foo a where data FooBar a
4+
5+-- | Something.
6+class Bar a where
7+ -- | Bar bar
8+ data BarBar a
9+
10+ -- | Bar baz
11+ data
12+ BarBaz
13+ a
data/examples/declaration/class/associated-data1.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+class Foo a where data FooBar a
4+
5+-- | Something.
6+class Bar a
7+ where
8+ -- | Bar bar
9+ data BarBar a
10+ -- | Bar baz
11+ data family BarBaz
12+ a
data/examples/declaration/class/associated-data2-out.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+module Main where
4+
5+-- | Something more.
6+class Baz a where
7+ -- | Baz bar
8+ data
9+ BazBar
10+ a
11+ b
12+ c
13+
14+ -- | Baz baz
15+ data
16+ BazBaz
17+ b
18+ a
19+ c
data/examples/declaration/class/associated-data2.hsnew file+17
@@ -0,0 +1,17 @@
1+module Main where
2+
3+{-# LANGUAGE TypeFamilies #-}
4+
5+-- | Something more.
6+class Baz a where
7+ -- | Baz bar
8+ data BazBar
9+ a
10+ b
11+ c
12+
13+ -- | Baz baz
14+ data family BazBaz
15+ b
16+ a
17+ c
data/examples/declaration/class/associated-type-defaults-out.hsnew file+26
@@ -0,0 +1,26 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+class Foo a where type FooBar a = Int
4+
5+-- | Something.
6+class Bar a where
7+ -- Define bar
8+ type
9+ BarBar a =
10+ BarBaz a
11+
12+ -- Define baz
13+ type
14+ BarBaz
15+ a =
16+ BarBar -- Middle comment
17+ a
18+
19+class Baz a where
20+ type
21+ BazBar
22+ a
23+
24+ type
25+ BazBar a =
26+ Bar a
data/examples/declaration/class/associated-type-defaults.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+class Foo a where type FooBar a = Int
4+
5+-- | Something.
6+class Bar a where
7+ -- Define bar
8+ type BarBar a
9+ = BarBaz a
10+ -- Define baz
11+ type BarBaz
12+ a = BarBar -- Middle comment
13+ a
14+
15+class Baz a where
16+ type BazBar
17+ a
18+
19+ type BazBar a =
20+ Bar a
data/examples/declaration/class/associated-types1-out.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+class Foo a where type FooBar a
4+
5+-- | Something.
6+class Bar a where
7+ -- | Bar bar
8+ type BarBar a
9+
10+ -- | Bar baz
11+ type
12+ BarBaz
13+ a
data/examples/declaration/class/associated-types1.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+class Foo a where type FooBar a
4+
5+-- | Something.
6+class Bar a
7+ where
8+ -- | Bar bar
9+ type BarBar a
10+ -- | Bar baz
11+ type BarBaz
12+ a
data/examples/declaration/class/associated-types2-out.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+module Main where
4+
5+-- | Something more.
6+class Baz a where
7+ -- | Baz bar
8+ type
9+ BazBar
10+ a -- Foo
11+ b -- Bar
12+ c
13+
14+ -- | Baz baz
15+ type
16+ -- After type
17+ BazBaz
18+ b
19+ a
20+ c
data/examples/declaration/class/associated-types2.hsnew file+18
@@ -0,0 +1,18 @@
1+module Main where
2+
3+{-# LANGUAGE TypeFamilies #-}
4+
5+-- | Something more.
6+class Baz a where
7+ -- | Baz bar
8+ type BazBar
9+ a -- Foo
10+ b -- Bar
11+ c
12+
13+ -- | Baz baz
14+ type -- After type
15+ BazBaz
16+ b
17+ a
18+ c
data/examples/declaration/class/default-implementations-comments-out.hsnew file+26
@@ -0,0 +1,26 @@
1+module Main where
2+
3+-- | Baz
4+class Baz a where
5+ foobar :: a -> a
6+ foobar a =
7+ barbaz (bazbar a)
8+
9+ -- | Bar baz
10+ barbaz ::
11+ a -> a
12+
13+ -- | Baz bar
14+ bazbar ::
15+ a ->
16+ a
17+
18+ -- First comment
19+ barbaz a =
20+ bazbar -- Middle comment
21+ a
22+
23+ -- Last comment
24+ bazbar a =
25+ barbaz
26+ a
data/examples/declaration/class/default-implementations-comments.hsnew file+22
@@ -0,0 +1,22 @@
1+module Main where
2+
3+-- | Baz
4+class Baz a where
5+ foobar :: a -> a
6+ foobar a =
7+ barbaz (bazbar a)
8+ -- | Bar baz
9+ barbaz ::
10+ a -> a
11+ -- | Baz bar
12+ bazbar ::
13+ a ->
14+ a
15+ -- First comment
16+ barbaz a
17+ = bazbar -- Middle comment
18+ a
19+ -- Last comment
20+ bazbar a
21+ = barbaz
22+ a
data/examples/declaration/class/default-implementations-out.hsnew file+13
@@ -0,0 +1,13 @@
1+module Main where
2+
3+-- | Foo
4+class Foo a where
5+ foo :: a -> a
6+ foo a = a
7+
8+-- | Bar
9+class Bar a where
10+ bar ::
11+ a ->
12+ Int
13+ bar = const 0
data/examples/declaration/class/default-implementations.hsnew file+13
@@ -0,0 +1,13 @@
1+module Main where
2+
3+-- | Foo
4+class Foo a where
5+ foo :: a -> a
6+ foo a = a
7+
8+-- | Bar
9+class Bar a where
10+ bar ::
11+ a
12+ -> Int
13+ bar = const 0
data/examples/declaration/class/default-signatures-out.hsnew file+24
@@ -0,0 +1,24 @@
1+{-# LANGUAGE DefaultSignatures #-}
2+
3+module Main where
4+
5+-- | Something else.
6+class Bar a where
7+ -- | Bar
8+ bar ::
9+ String ->
10+ String ->
11+ a
12+ -- Pointless comment
13+ default bar ::
14+ ( Read a,
15+ Semigroup a
16+ ) =>
17+ a ->
18+ a ->
19+ a
20+ -- Even more pointless comment
21+ bar
22+ a
23+ b =
24+ read a <> read b
data/examples/declaration/class/default-signatures-simple-out.hsnew file+8
@@ -0,0 +1,8 @@
1+module Main where
2+
3+-- | Something.
4+class Foo a where
5+ -- | Foo
6+ foo :: a -> String
7+ default foo :: Show a => a -> String
8+ foo = show
data/examples/declaration/class/default-signatures-simple.hsnew file+8
@@ -0,0 +1,8 @@
1+module Main where
2+
3+-- | Something.
4+class Foo a where
5+ -- | Foo
6+ foo :: a -> String
7+ default foo :: Show a => a -> String
8+ foo = show
data/examples/declaration/class/default-signatures.hsnew file+26
@@ -0,0 +1,26 @@
1+module Main where
2+
3+{-# LANGUAGE DefaultSignatures #-}
4+
5+-- | Something else.
6+class Bar a
7+ where
8+ -- | Bar
9+ bar ::
10+ String
11+ -> String
12+ -> a
13+
14+ -- Pointless comment
15+ default bar :: (
16+ Read a,
17+ Semigroup a
18+ ) =>
19+ a -> a -> a
20+
21+ -- Even more pointless comment
22+ bar
23+ a
24+ b
25+ =
26+ read a <> read b
data/examples/declaration/class/dependency-super-classes-out.hsnew file+25
@@ -0,0 +1,25 @@
1+{-# LANGUAGE FunctionalDependencies #-}
2+
3+module Main where
4+
5+-- | Something.
6+class (MonadReader r s, MonadWriter w m) => MonadState s m | m -> s where
7+ get :: m s
8+ put :: s -> m ()
9+
10+-- | 'MonadParsec'
11+class
12+ ( Stream s, -- Token streams
13+ MonadPlus m -- Potential for failure
14+ ) =>
15+ MonadParsec e s m
16+ | m -> e s
17+ where
18+ -- | 'getState' returns state
19+ getState ::
20+ m s
21+
22+ -- | 'putState' sets state
23+ putState ::
24+ s ->
25+ m ()
data/examples/declaration/class/dependency-super-classes.hsnew file+24
@@ -0,0 +1,24 @@
1+module Main where
2+
3+{-# LANGUAGE FunctionalDependencies #-}
4+
5+-- | Something.
6+class ( MonadReader r s,MonadWriter w m ) => MonadState s m| m -> s where
7+ get :: m s
8+ put :: s -> m ()
9+
10+-- | 'MonadParsec'
11+
12+class (
13+ Stream s, -- Token streams
14+ MonadPlus m -- Potential for failure
15+ ) => MonadParsec e s m | m -> e s
16+ where
17+ -- | 'getState' returns state
18+ getState
19+ ::
20+ m s
21+ -- | 'putState' sets state
22+ putState ::
23+ s
24+ -> m ()
data/examples/declaration/class/empty-classes-out.hsnew file+7
@@ -0,0 +1,7 @@
1+module Main where
2+
3+-- | Foo!
4+class Foo a
5+
6+-- | Bar!
7+class Bar a
data/examples/declaration/class/empty-classes.hsnew file+6
@@ -0,0 +1,6 @@
1+module Main where
2+
3+-- | Foo!
4+class Foo a where
5+-- | Bar!
6+class Bar a
data/examples/declaration/class/functional-dependencies-out.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# LANGUAGE FunctionalDependencies #-}
2+
3+module Main where
4+
5+-- | Something.
6+class Foo a b | a -> b
7+
8+class Bar a b | a -> b, b -> a where bar :: a
9+
10+-- | Something else.
11+class
12+ Baz a b c d
13+ | a b -> c d, -- Foo
14+ b c -> a d, -- Bar
15+ a c -> b d, -- Baz
16+ a c d -> b,
17+ a b d -> a b c d
18+ where
19+ baz :: a -> b
data/examples/declaration/class/functional-dependencies.hsnew file+18
@@ -0,0 +1,18 @@
1+module Main where
2+
3+{-# LANGUAGE FunctionalDependencies #-}
4+
5+-- | Something.
6+class Foo a b | a -> b
7+
8+class Bar a b | a -> b, b -> a where bar :: a
9+
10+-- | Something else.
11+class Baz a b c d
12+ | a b -> c d -- Foo
13+ , b c -> a d -- Bar
14+ , a c -> b d-- Baz
15+ , a c d -> b
16+ , a b d -> a b c d
17+ where
18+ baz :: a -> b
data/examples/declaration/class/multi-parameters1-out.hsnew file+15
@@ -0,0 +1,15 @@
1+{-# LANGUAGE MultiParamTypeClasses #-}
2+
3+class Foo a b where foo :: a -> b
4+
5+-- | Something.
6+class Bar a b c d where
7+ bar ::
8+ a ->
9+ b ->
10+ c ->
11+ d
12+
13+class -- Before name
14+ Baz where
15+ baz :: Int
data/examples/declaration/class/multi-parameters1.hsnew file+18
@@ -0,0 +1,18 @@
1+{-# LANGUAGE MultiParamTypeClasses #-}
2+
3+class Foo a b where foo :: a -> b
4+
5+-- | Something.
6+class Bar a b c d
7+ where
8+ bar ::
9+ a
10+ -> b
11+ -> c
12+ -> d
13+
14+class -- Before name
15+ Baz
16+ where
17+ baz :: Int
18+
data/examples/declaration/class/multi-parameters2-out.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# LANGUAGE MultiParamTypeClasses #-}
2+
3+module Main where
4+
5+-- | Something else.
6+class
7+ BarBaz
8+ a -- Foo
9+ b -- Bar
10+ c -- Baz bar
11+ d -- Baz baz
12+ e -- Rest
13+ f
14+ where
15+ barbaz ::
16+ a -> f
17+ bazbar ::
18+ e ->
19+ f
data/examples/declaration/class/multi-parameters2.hsnew file+18
@@ -0,0 +1,18 @@
1+module Main where
2+
3+{-# LANGUAGE MultiParamTypeClasses #-}
4+
5+-- | Something else.
6+class
7+ BarBaz
8+ a -- Foo
9+ b -- Bar
10+ c -- Baz bar
11+ d -- Baz baz
12+ e -- Rest
13+ f where
14+ barbaz ::
15+ a -> f
16+ bazbar ::
17+ e ->
18+ f
data/examples/declaration/class/newlines-after-where-out.hsnew file+5
@@ -0,0 +1,5 @@
1+class Num a where
2+ (+) :: a -> a -> a
3+
4+class Num a where
5+ (+) :: a -> a -> a
data/examples/declaration/class/newlines-after-where.hsnew file+7
@@ -0,0 +1,7 @@
1+class Num a where
2+ (+) :: a -> a -> a
3+
4+class Num a where
5+
6+
7+ (+) :: a -> a -> a
data/examples/declaration/class/newlines-and-default-decls-out.hsnew file+11
@@ -0,0 +1,11 @@
1+class Foo a where
2+ foo :: a
3+ default foo :: ()
4+ foo = ()
5+ bar :: a
6+ default bar :: ()
7+ bar = ()
8+
9+ qux :: a
10+ default qux :: ()
11+ qux = ()
data/examples/declaration/class/newlines-and-default-decls.hsnew file+13
@@ -0,0 +1,13 @@
1+class Foo a where
2+ foo :: a
3+ default foo :: ()
4+ foo = ()
5+ bar :: a
6+ default bar :: ()
7+ bar = ()
8+
9+ qux :: a
10+
11+ default qux :: ()
12+
13+ qux = ()
data/examples/declaration/class/newlines-and-haddocks-out.hsnew file+23
@@ -0,0 +1,23 @@
1+class Foo a where
2+ -- | Haddock
3+ foo :: a
4+
5+ -- | Another Haddock
6+ bar :: a
7+
8+ baz :: a
9+ -- ^ Post-Haddock
10+
11+ raz :: a
12+ -- ^ Another Post-Haddock
13+
14+ -- | One more Haddock
15+ qux :: a
16+
17+ -- Comment before a Haddock
18+
19+ -- | And one more Haddock
20+ xyz :: a
21+
22+ -- | Haddock followed by a blank line
23+ abc :: a
data/examples/declaration/class/newlines-and-haddocks.hsnew file+19
@@ -0,0 +1,19 @@
1+class Foo a where
2+ -- | Haddock
3+ foo :: a
4+ -- | Another Haddock
5+ bar :: a
6+ baz :: a
7+ -- ^ Post-Haddock
8+ raz :: a
9+ -- ^ Another Post-Haddock
10+
11+ -- | One more Haddock
12+ qux :: a
13+ -- Comment before a Haddock
14+ -- | And one more Haddock
15+ xyz :: a
16+
17+ -- | Haddock followed by a blank line
18+
19+ abc :: a
data/examples/declaration/class/newlines-between-methods-out.hsnew file+17
@@ -0,0 +1,17 @@
1+class Num a where
2+ (+) :: a -> a -> a
3+ (-) :: a -> a -> a
4+ (*) :: a -> a -> a
5+
6+ -- Comment before definition
7+ negate :: a -> a
8+
9+ -- Comment after definition
10+
11+ -- Separator
12+
13+ abs :: a -> a
14+ signum :: a -> a
15+
16+ -- Comment between unrelated definitions
17+ fromInteger :: Integer -> a
data/examples/declaration/class/newlines-between-methods.hsnew file+15
@@ -0,0 +1,15 @@
1+class Num a where
2+ (+) :: a -> a -> a
3+ (-) :: a -> a -> a
4+ (*) :: a -> a -> a
5+
6+ -- Comment before definition
7+ negate :: a -> a
8+ -- Comment after definition
9+
10+ -- Separator
11+
12+ abs :: a -> a
13+ signum :: a -> a
14+ -- Comment between unrelated definitions
15+ fromInteger :: Integer -> a
data/examples/declaration/class/poly-kinded-classes-out.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# LANGUAGE PolyKinds #-}
2+
3+class Foo (a :: k)
4+
5+class
6+ Bar
7+ ( a :: -- Variable
8+ * -- Star
9+ )
data/examples/declaration/class/poly-kinded-classes.hsnew file+8
@@ -0,0 +1,8 @@
1+{-# LANGUAGE PolyKinds #-}
2+
3+class Foo (a::k)
4+
5+class Bar
6+ (a -- Variable
7+ :: * -- Star
8+ )
data/examples/declaration/class/single-parameters-out.hsnew file+26
@@ -0,0 +1,26 @@
1+module Main where
2+
3+-- | Something.
4+class Foo a where foo :: a
5+
6+-- | Something more.
7+class Bar a where
8+ -- | Bar
9+ bar :: a -> a -> a
10+
11+class Baz a where
12+ -- | Baz
13+ baz ::
14+ -- | First argument
15+ ( a,
16+ a
17+ ) ->
18+ -- | Second argument
19+ a ->
20+ -- | Return value
21+ a
22+
23+class BarBaz a where
24+ barbaz ::
25+ a -> b
26+ bazbar :: b -> a
data/examples/declaration/class/single-parameters.hsnew file+22
@@ -0,0 +1,22 @@
1+module Main where
2+
3+-- | Something.
4+class Foo a where foo :: a
5+
6+-- | Something more.
7+class Bar a where
8+ -- | Bar
9+ bar :: a -> a -> a
10+
11+class Baz a where
12+ -- | Baz
13+ baz ::
14+ (a,
15+ a) -- ^ First argument
16+ -> a -- ^ Second argument
17+ -> a -- ^ Return value
18+
19+class BarBaz a where
20+ barbaz ::
21+ a -> b
22+ bazbar :: b -> a
data/examples/declaration/class/super-classes-out.hsnew file+14
@@ -0,0 +1,14 @@
1+class Foo a
2+
3+class Foo a => Bar a
4+
5+class
6+ (Foo a, Bar a) =>
7+ Baz a
8+
9+class
10+ ( Foo a, -- Foo?
11+ Bar a, -- Bar?
12+ Baz a -- Baz
13+ ) =>
14+ BarBar a
data/examples/declaration/class/super-classes.hsnew file+9
@@ -0,0 +1,9 @@
1+class () => Foo a
2+class Foo a => Bar a
3+class (Foo a,Bar a) =>
4+ Baz a
5+class (
6+ Foo a, -- Foo?
7+ Bar a, -- Bar?
8+ Baz a -- Baz
9+ ) => BarBar a
data/examples/declaration/class/type-operators1-out.hsnew file+21
@@ -0,0 +1,21 @@
1+{-# LANGUAGE MultiParamTypeClasses #-}
2+{-# LANGUAGE TypeOperators #-}
3+
4+class (:$) a b
5+
6+class
7+ (:&)
8+ a
9+ b
10+
11+class a :* b
12+
13+class
14+ a -- Before operator
15+ :+ b -- After operator
16+
17+class
18+ ( f
19+ :. g
20+ )
21+ a
data/examples/declaration/class/type-operators1.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# LANGUAGE MultiParamTypeClasses #-}
2+{-# LANGUAGE TypeOperators #-}
3+
4+class (:$) a b
5+
6+class (:&)
7+ a
8+ b
9+
10+class a:*b
11+
12+class
13+ a -- Before operator
14+ :+
15+ b -- After operator
16+
17+class (
18+ f :. g
19+ ) a
data/examples/declaration/class/type-operators2-out.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE MultiParamTypeClasses #-}
2+{-# LANGUAGE TypeOperators #-}
3+
4+class a `Pair` b
5+
6+class
7+ a
8+ `Sum` b
9+
10+class (f `Product` g) a
11+
12+class
13+ ( f
14+ `Sum` g
15+ )
16+ a
data/examples/declaration/class/type-operators2.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE MultiParamTypeClasses #-}
2+{-# LANGUAGE TypeOperators #-}
3+
4+class
5+ a`Pair`b
6+
7+class
8+ a
9+ `Sum` b
10+
11+class (f`Product`g)a
12+
13+class (
14+ f `Sum` g
15+ ) a
16+
data/examples/declaration/class/type-operators3-out.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE PolyKinds #-}
2+{-# LANGUAGE TypeFamilies #-}
3+{-# LANGUAGE TypeOperators #-}
4+{-# LANGUAGE NoStarIsType #-}
5+
6+class PNum x where
7+ type (a :: x) * (b :: x)
8+
9+instance PNum Nat where
10+ type a * b = ()
data/examples/declaration/class/type-operators3.hsnew file+7
@@ -0,0 +1,7 @@
1+{-# LANGUAGE TypeFamilies, TypeOperators, NoStarIsType, PolyKinds #-}
2+
3+class PNum x where
4+ type (a :: x) * (b :: x)
5+
6+instance PNum Nat where
7+ type a * b = ()
data/examples/declaration/data/deriving-out.hsnew file+2
@@ -0,0 +1,2 @@
1+newtype R r a = R (ReaderT r IO a)
2+ deriving (MonadReader r)
data/examples/declaration/data/deriving-strategies-out.hs+8−2
@@ -1,8 +1,14 @@
1+module Main where
2+
1-- | Something.
3-- | Something.
2newtype Foo = Foo Int
4newtype Foo = Foo Int
3 deriving stock (Eq, Show, Generic)
5 deriving stock (Eq, Show, Generic)
4 deriving anyclass
6 deriving anyclass
5− ( ToJSON
7+ ( ToJSON,
6− , FromJSON
8+ FromJSON
7 )
9 )
8 deriving newtype (Num)
10 deriving newtype (Num)
11+ deriving (Monoid) via (Sum Int)
12+ deriving
13+ (Semigroup)
14+ via (Sum Int)
data/examples/declaration/data/deriving-strategies.hs+5
@@ -1,3 +1,5 @@
1+module Main where
2+
1-- | Something.
3-- | Something.
2
4
3newtype Foo = Foo Int
5newtype Foo = Foo Int
@@ -7,3 +9,6 @@ newtype Foo = Foo Int
7 , FromJSON
9 , FromJSON
8 )
10 )
9 deriving newtype (Num)
11 deriving newtype (Num)
12+ deriving Monoid via (Sum Int)
13+ deriving Semigroup
14+ via (Sum Int)
data/examples/declaration/data/deriving.hsnew file+2
@@ -0,0 +1,2 @@
1+newtype R r a = R (ReaderT r IO a)
2+ deriving (MonadReader r)
data/examples/declaration/data/empty-out.hsnew file+3
@@ -0,0 +1,3 @@
1+{-# LANGUAGE EmptyDataDecls #-}
2+
3+data Foo
data/examples/declaration/data/empty.hsnew file+3
@@ -0,0 +1,3 @@
1+{-# LANGUAGE EmptyDataDecls #-}
2+
3+data Foo
data/examples/declaration/data/existential-multiline-out.hs+13
@@ -1,4 +1,17 @@
1{-# LANGUAGE ExistentialQuantification #-}
1{-# LANGUAGE ExistentialQuantification #-}
2+
2data Foo
3data Foo
3 = forall a. MkFoo a (a -> Bool)
4 = forall a. MkFoo a (a -> Bool)
4 | forall a. Eq a => MkBar a
5 | forall a. Eq a => MkBar a
6+
7+data Bar
8+ = forall x y.
9+ Bar x y x y
10+
11+data Baz
12+ = forall x y.
13+ Baz
14+ x
15+ y
16+ x
17+ y
data/examples/declaration/data/existential-multiline.hs+7
@@ -3,3 +3,10 @@
3data Foo
3data Foo
4 = forall a. MkFoo a (a -> Bool)
4 = forall a. MkFoo a (a -> Bool)
5 | forall a. Eq a => MkBar a
5 | forall a. Eq a => MkBar a
6+
7+data Bar = forall x y.
8+ Bar x y x y
9+
10+data Baz = forall x y.
11+ Baz x y x
12+ y
data/examples/declaration/data/existential-out.hs+3
@@ -1,2 +1,5 @@
1{-# LANGUAGE ExistentialQuantification #-}
1{-# LANGUAGE ExistentialQuantification #-}
2+
2data Foo = forall a. MkFoo a (a -> Bool)
3data Foo = forall a. MkFoo a (a -> Bool)
4+
5+data Bar = forall a b. a + b => Bar a b
data/examples/declaration/data/existential.hs+2
@@ -1,3 +1,5 @@
1{-# LANGUAGE ExistentialQuantification #-}
1{-# LANGUAGE ExistentialQuantification #-}
2
2
3data Foo = forall a. MkFoo a (a -> Bool)
3data Foo = forall a. MkFoo a (a -> Bool)
4+
5+data Bar = forall a b. a + b => Bar a b
data/examples/declaration/data/fat-multiline-out.hs+6−5
@@ -1,11 +1,12 @@
1−-- | Something.
1+module Main where
2
2
3+-- | Something.
3data Foo
4data Foo
5+ = -- | Foo
4− = Foo
6+ Foo
5 Int
7 Int
6 Int
8 Int
7− -- ^ Foo
9+ | -- | Bar
8− | Bar
10+ Bar
9 Bool
11 Bool
10 Bool
12 Bool
11− -- ^ Bar
data/examples/declaration/data/fat-multiline.hs+2
@@ -1,3 +1,5 @@
1+module Main where
2+
1-- | Something.
3-- | Something.
2
4
3data Foo
5data Foo
data/examples/declaration/data/field-layout/gadt-out.hsnew file+11
@@ -0,0 +1,11 @@
1+module Main where
2+
3+-- | Foo.
4+data Foo a b where
5+ -- | Something
6+ Foo :: Foo Int Int
7+ -- | Something else
8+ Bar ::
9+ Foo
10+ Char
11+ Char
data/examples/declaration/data/field-layout/gadt.hsnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+-- | Foo.
4+
5+data Foo a b where
6+ -- | Something
7+ Foo :: Foo Int Int
8+ -- | Something else
9+ Bar :: Foo Char
10+ Char
data/examples/declaration/data/field-layout/record-out.hsnew file+12
@@ -0,0 +1,12 @@
1+module Main where
2+
3+-- | Foo.
4+data Foo = Foo
5+ { -- | Something
6+ foo :: Foo Int Int,
7+ -- | Something else
8+ bar ::
9+ Bar
10+ Char
11+ Char
12+ }
data/examples/declaration/data/field-layout/record.hsnew file+11
@@ -0,0 +1,11 @@
1+module Main where
2+
3+-- | Foo.
4+
5+data Foo = Foo
6+ { foo :: Foo Int Int
7+ -- ^ Something
8+ , bar :: Bar Char
9+ Char
10+ -- ^ Something else
11+ }
data/examples/declaration/data/field-layout/variants-out.hsnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+-- | Foo.
4+data Foo
5+ = -- | Something
6+ Foo Int Int
7+ | -- | Something else
8+ Bar
9+ Char
10+ Char
data/examples/declaration/data/field-layout/variants.hsnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+-- | Foo.
4+
5+data Foo =
6+ Foo Int Int
7+ -- ^ Something
8+ | Bar Char
9+ Char
10+ -- ^ Something else
data/examples/declaration/data/gadt-syntax-out.hs+3−3
@@ -1,3 +1,3 @@
1−{-# LANUGAGE GADTSyntax #-}
1+{-# LANGUAGE GADTSyntax #-}
2−data Foo where
2+
3− MKFoo :: a -> (a -> Bool) -> Foo
3+data Foo where MKFoo :: a -> (a -> Bool) -> Foo
data/examples/declaration/data/gadt-syntax.hs+1−1
@@ -1,3 +1,3 @@
1−{-# LANUGAGE GADTSyntax #-}
1+{-# LANGUAGE GADTSyntax #-}
2
2
3data Foo where { MKFoo :: a -> (a->Bool) -> Foo }
3data Foo where { MKFoo :: a -> (a->Bool) -> Foo }
data/examples/declaration/data/gadt/multiline-out.hs+17−14
@@ -1,22 +1,25 @@
1{-# LANGUAGE ExplicitForAll #-}
1{-# LANGUAGE ExplicitForAll #-}
2
2
3+module Main where
4+
3-- | Here goes a comment.
5-- | Here goes a comment.
4data Foo a where
6data Foo a where
5 -- | 'Foo' is wonderful.
7 -- | 'Foo' is wonderful.
6− Foo
8+ Foo ::
7− :: forall a b. ( Show a
9+ forall a b.
8− , Eq b
10+ (Show a, Eq b) => -- foo
9− ) -- foo
10 -- bar
11 -- bar
11− => a
12+ a ->
12− -> b
13+ b ->
13− -> Foo 'Int
14+ Foo 'Int
14 -- | But 'Bar' is also not too bad.
15 -- | But 'Bar' is also not too bad.
15− Bar
16+ Bar ::
16− :: Int
17+ Int ->
17− -> Maybe Text
18+ Maybe Text ->
18− -> Foo 'Bool
19+ Foo 'Bool
19 -- | So is 'Baz'.
20 -- | So is 'Baz'.
20− Baz
21+ Baz ::
21− :: forall a. a
22+ forall a.
23+ a ->
22− -> Foo 'String
24+ Foo 'String
25+ (:~>) :: Foo a -> Foo a -> Foo a
data/examples/declaration/data/gadt/multiline-where-out.hsnew file+7
@@ -0,0 +1,7 @@
1+data
2+ Foo
3+ a
4+ b
5+ c
6+ where
7+ Foo :: a -> b -> c -> Foo a b c
data/examples/declaration/data/gadt/multiline-where.hsnew file+6
@@ -0,0 +1,6 @@
1+data
2+ Foo
3+ a
4+ b
5+ c where
6+ Foo :: a -> b -> c -> Foo a b c
data/examples/declaration/data/gadt/multiline.hs+3
@@ -1,3 +1,5 @@
1+module Main where
2+
1{-# LANGUAGE ExplicitForAll #-}
3{-# LANGUAGE ExplicitForAll #-}
2
4
3-- | Here goes a comment.
5-- | Here goes a comment.
@@ -13,3 +15,4 @@ data Foo a where
13 -- | So is 'Baz'.
15 -- | So is 'Baz'.
14 Baz
16 Baz
15 :: forall a. a -> Foo 'String
17 :: forall a. a -> Foo 'String
18+ (:~>) :: Foo a -> Foo a -> Foo a
data/examples/declaration/data/gadt/multiple-declaration-out.hsnew file+15
@@ -0,0 +1,15 @@
1+data GADT0 a where
2+ GADT01, GADT02 :: Int -> GADT0 a
3+
4+data GADT1 a where
5+ GADT11,
6+ GADT12 ::
7+ Int ->
8+ GADT1 a
9+
10+data GADT2 a where
11+ GADT21,
12+ GADT21,
13+ GADT22 ::
14+ Int ->
15+ GADT2 a
data/examples/declaration/data/gadt/multiple-declaration.hsnew file+11
@@ -0,0 +1,11 @@
1+data GADT0 a where
2+ GADT01, GADT02 :: Int -> GADT0 a
3+
4+data GADT1 a where
5+ GADT11
6+ , GADT12 :: Int -> GADT1 a
7+
8+data GADT2 a where
9+ GADT21
10+ , GADT21
11+ , GADT22 :: Int -> GADT2 a
data/examples/declaration/data/gadt/record-out.hs+11−8
@@ -1,11 +1,14 @@
1+module Main where
2+
1-- | Something.
3-- | Something.
2data Foo where
4data Foo where
3 Foo :: {fooX :: Int} -> Foo
5 Foo :: {fooX :: Int} -> Foo
4− Bar
6+ Bar ::
5− :: { fooY :: Int
7+ { fooY :: Int,
6− , fooBar, fooBaz :: Bool
8+ fooBar, fooBaz :: Bool,
7− , fooFoo
9+ fooFoo,
8− , barBar
10+ barBar,
11+ bazBaz ::
9− :: Int
12+ Int
10− }
13+ } ->
11− -> Foo
14+ Foo
data/examples/declaration/data/gadt/record.hs+4−1
@@ -1,3 +1,5 @@
1+module Main where
2+
1-- | Something.
3-- | Something.
2
4
3data Foo where
5data Foo where
@@ -5,5 +7,6 @@ data Foo where
5 Bar :: { fooY :: Int
7 Bar :: { fooY :: Int
6 , fooBar, fooBaz :: Bool
8 , fooBar, fooBaz :: Bool
7 , fooFoo
9 , fooFoo
8− , barBar :: Int
10+ , barBar
11+ , bazBaz :: Int
9 } -> Foo
12 } -> Foo
data/examples/declaration/data/gadt/simple-out.hs+12−2
@@ -1,8 +1,18 @@
1{-# LANGUAGE ExplicitForAll #-}
1{-# LANGUAGE ExplicitForAll #-}
2
2
3+module Main where
4+
3-- | Here goes a comment.
5-- | Here goes a comment.
4data Foo a where
6data Foo a where
5 -- | 'Foo' is wonderful.
7 -- | 'Foo' is wonderful.
6 Foo :: forall a b. (Show a, Eq b) => a -> b -> Foo 'Int
8 Foo :: forall a b. (Show a, Eq b) => a -> b -> Foo 'Int
9+ Bar ::
10+ Int ->
11+ Text ->
7− Bar :: Int -> Text -> Foo 'Bool -- ^ But 'Bar' is also not too bad.
12+ -- | But 'Bar' is also not too bad.
13+ Foo 'Bool
14+ Baz ::
15+ forall a.
16+ a ->
17+ -- | So is 'Baz'.
8− Baz :: forall a. a -> Foo 'String -- ^ So is 'Baz'.
18+ Foo 'String
data/examples/declaration/data/gadt/simple.hs+2
@@ -1,3 +1,5 @@
1+module Main where
2+
1{-# LANGUAGE ExplicitForAll #-}
3{-# LANGUAGE ExplicitForAll #-}
2
4
3-- | Here goes a comment.
5-- | Here goes a comment.
data/examples/declaration/data/gadt/strictness-out.hs+2−1
@@ -1,2 +1,3 @@
1data Foo a where
1data Foo a where
2− Foo :: !Int -> {-# UNPACK #-} !Bool -> Foo Int
2+ Foo1 :: !Int -> {-# UNPACK #-} !Bool -> Foo Int
3+ Foo2 :: {-# UNPACK #-} Maybe Int && Bool -> Foo Int
data/examples/declaration/data/gadt/strictness.hs+2−1
@@ -1,2 +1,3 @@
1data Foo a where
1data Foo a where
2− Foo :: !Int -> {-# UNPACK #-} !Bool -> Foo Int
2+ Foo1 :: !Int -> {-# UNPACK #-} !Bool -> Foo Int
3+ Foo2 :: {-# UNPACK #-} Maybe Int && Bool -> Foo Int
data/examples/declaration/data/kind-annotations-out.hsnew file+11
@@ -0,0 +1,11 @@
1+data Something (n :: Nat) = Something
2+
3+data Format (k :: *) (k' :: *) (k'' :: *)
4+
5+type Parens1 = Proxy '(a :: A, b :: (B :: *))
6+
7+type Parens2 = Proxy '((a :: A), (b :: B))
8+
9+type family Foo a where
10+ Foo '(a :: Int, b :: Bool) = Int
11+ Foo '((a :: Int), (b :: Bool)) = Int
data/examples/declaration/data/kind-annotations.hsnew file+10
@@ -0,0 +1,10 @@
1+data Something (n :: Nat) = Something
2+
3+data Format (k :: *) (k' :: *) (k'' :: *)
4+
5+type Parens1 = Proxy '(a :: A, b :: (B :: *))
6+type Parens2 = Proxy '((a :: A), (b :: B))
7+
8+type family Foo a where
9+ Foo '(a :: Int, b :: Bool) = Int
10+ Foo '((a :: Int), (b :: Bool)) = Int
data/examples/declaration/data/multiline-arg-parens-out.hsnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+-- | Something.
4+data Foo
5+ = Foo
6+ Bar
7+ (Set Baz) -- and here we go
8+ -- and that's it
9+ Text
10+ deriving (Eq)
data/examples/declaration/data/multiline-arg-parens.hsnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+-- | Something.
4+
5+data Foo
6+ = Foo Bar
7+ (Set Baz) -- and here we go
8+ -- and that's it
9+ Text
10+ deriving (Eq)
data/examples/declaration/data/multiline-names-out.hsnew file+29
@@ -0,0 +1,29 @@
1+data
2+ Foo
3+ a
4+ b
5+ = Foo a b
6+
7+data a :-> b = Arrow (a -> b)
8+
9+data (f :* g) a = f a :* g a
10+
11+data
12+ ( f
13+ :+ g
14+ )
15+ a
16+ = L (f a)
17+ | R (g a)
18+
19+data a `Arrow` b = Arrow' (a -> b)
20+
21+data (f `Product` g) a = f a `Product` g a
22+
23+data
24+ ( f
25+ `Sum` g
26+ )
27+ a
28+ = L' (f a)
29+ | R' (g a)
data/examples/declaration/data/multiline-names.hsnew file+23
@@ -0,0 +1,23 @@
1+data Foo a
2+ b
3+ = Foo a b
4+
5+data a :-> b = Arrow (a -> b)
6+
7+data (f :* g) a = f a :* g a
8+
9+data (f
10+ :+
11+ g)
12+ a = L (f a)
13+ | R (g a)
14+
15+data a `Arrow` b = Arrow' (a -> b)
16+
17+data (f `Product` g) a = f a `Product` g a
18+
19+data (f
20+ `Sum`
21+ g)
22+ a = L' (f a)
23+ | R' (g a)
data/examples/declaration/data/multiline-out.hs+10−4
@@ -1,6 +1,12 @@
1+module Main where
2+
1-- | Here we have 'Foo'.
3-- | Here we have 'Foo'.
2data Foo
4data Foo
5+ = -- | One
3− = Foo -- ^ One
6+ Foo
7+ | -- | Two
4− | Bar Int -- ^ Two
8+ Bar Int
5− | Baz -- ^ Three
9+ | -- | Three
10+ Baz
6− deriving (Eq, Show)
11+ deriving
12+ (Eq, Show)
data/examples/declaration/data/multiline.hs+4−1
@@ -1,7 +1,10 @@
1+module Main where
2+
1-- | Here we have 'Foo'.
3-- | Here we have 'Foo'.
2
4
3data Foo
5data Foo
4 = Foo -- ^ One
6 = Foo -- ^ One
5 | Bar Int -- ^ Two
7 | Bar Int -- ^ Two
6 | Baz -- ^ Three
8 | Baz -- ^ Three
7− deriving (Eq, Show)
9+ deriving
10+ (Eq, Show)
data/examples/declaration/data/newline.hs → data/examples/declaration/data/newtype-out.hsrenamed+2−1
@@ -1,4 +1,5 @@
1−-- | Something.
1+module Main where
2
2
3+-- | Something.
3newtype Foo = Foo Int
4newtype Foo = Foo Int
4 deriving (Eq, Show)
5 deriving (Eq, Show)
data/examples/declaration/data/newline-out.hs → data/examples/declaration/data/newtype.hsrenamed+3
@@ -1,3 +1,6 @@
1+module Main where
2+
1-- | Something.
3-- | Something.
4+
2newtype Foo = Foo Int
5newtype Foo = Foo Int
3 deriving (Eq, Show)
6 deriving (Eq, Show)
data/examples/declaration/data/operators-out.hsnew file+12
@@ -0,0 +1,12 @@
1+data ErrorMessage' s
2+ = -- | Show the text as is.
3+ Text s
4+ | -- | Pretty print the type.
5+ -- @ShowType :: k -> ErrorMessage@
6+ forall t. ShowType t
7+ | -- | Put two pieces of error message next
8+ -- to each other.
9+ ErrorMessage' s :<>: ErrorMessage' s
10+ | -- | Stack two pieces of error message on top
11+ -- of each other.
12+ ErrorMessage' s :$$: ErrorMessage' s
data/examples/declaration/data/operators.hsnew file+12
@@ -0,0 +1,12 @@
1+data ErrorMessage' s
2+ = -- | Show the text as is.
3+ Text s
4+ | -- | Pretty print the type.
5+ -- @ShowType :: k -> ErrorMessage@
6+ forall t. ShowType t
7+ | -- | Put two pieces of error message next
8+ -- to each other.
9+ ErrorMessage' s :<>: ErrorMessage' s
10+ | -- | Stack two pieces of error message on top
11+ -- of each other.
12+ ErrorMessage' s :$$: ErrorMessage' s
data/examples/declaration/data/partly-documented-out.hsnew file+5
@@ -0,0 +1,5 @@
1+data Optimisation
2+ = PETransform
3+ | -- | partial eval and associated transforms
4+ GeneralisedNatHack
5+ deriving (Show, Eq, Generic)
data/examples/declaration/data/partly-documented.hsnew file+2
@@ -0,0 +1,2 @@
1+data Optimisation = PETransform | GeneralisedNatHack -- ^ partial eval and associated transforms
2+ deriving (Show, Eq, Generic)
data/examples/declaration/data/record-multi-const-out.hsnew file+17
@@ -0,0 +1,17 @@
1+module Main where
2+
3+-- | Something.
4+data Foo
5+ = Foo
6+ { -- | X
7+ fooX :: Int,
8+ -- | Y
9+ fooY :: Int
10+ }
11+ | Bar
12+ { -- | X
13+ barX :: Int,
14+ -- | Y
15+ barY :: Int
16+ }
17+ deriving (Eq, Show)
data/examples/declaration/data/record-multi-const.hsnew file+13
@@ -0,0 +1,13 @@
1+module Main where
2+
3+-- | Something.
4+
5+data Foo = Foo
6+ { fooX :: Int -- ^ X
7+ , fooY :: Int -- ^ Y
8+ } |
9+ Bar
10+ { barX :: Int -- ^ X
11+ , barY :: Int -- ^ Y
12+ }
13+ deriving (Eq, Show)
data/examples/declaration/data/record-out.hs+21−9
@@ -1,11 +1,23 @@
1+module Main where
2+
1-- | Something.
3-- | Something.
2−data Foo
4+data Foo = Foo
3− = Foo
5+ { -- | X
4− { fooX :: Int -- ^ X
6+ fooX :: Int,
7+ -- | Y
5− , fooY :: Int -- ^ Y
8+ fooY :: Int,
9+ -- | BarBaz
6− , fooBar, fooBaz :: Bool -- ^ BarBaz
10+ fooBar, fooBaz :: NonEmpty (Identity Bool),
11+ -- | GagGog
12+ fooGag,
13+ fooGog ::
14+ NonEmpty
15+ ( Indentity
16+ Bool
17+ ),
18+ -- | Huh!
7− , fooFoo
19+ fooFoo,
8− , barBar
20+ barBar ::
9− :: Int -- ^ Huh!
21+ Int
10− }
22+ }
11 deriving (Eq, Show)
23 deriving (Eq, Show)
data/examples/declaration/data/record-singleline-out.hs+2
@@ -1,3 +1,5 @@
1+module Main where
2+
1-- | Something.
3-- | Something.
2data Foo = Foo {fooX :: Int, fooY :: Int}
4data Foo = Foo {fooX :: Int, fooY :: Int}
3 deriving (Eq, Show)
5 deriving (Eq, Show)
data/examples/declaration/data/record-singleline.hs+2
@@ -1,3 +1,5 @@
1+module Main where
2+
1-- | Something.
3-- | Something.
2
4
3data Foo = Foo { fooX :: Int , fooY :: Int }
5data Foo = Foo { fooX :: Int , fooY :: Int }
data/examples/declaration/data/record.hs+6−1
@@ -1,9 +1,14 @@
1+module Main where
2+
1-- | Something.
3-- | Something.
2
4
3data Foo = Foo
5data Foo = Foo
4 { fooX :: Int -- ^ X
6 { fooX :: Int -- ^ X
5 , fooY :: Int -- ^ Y
7 , fooY :: Int -- ^ Y
6− , fooBar, fooBaz :: Bool -- ^ BarBaz
8+ , fooBar, fooBaz :: NonEmpty (Identity Bool) -- ^ BarBaz
9+ , fooGag, fooGog :: NonEmpty (Indentity
10+ Bool)
11+ -- ^ GagGog
7 , fooFoo
12 , fooFoo
8 , barBar :: Int -- ^ Huh!
13 , barBar :: Int -- ^ Huh!
9 } deriving (Eq, Show)
14 } deriving (Eq, Show)
data/examples/declaration/data/simple-broken-out.hsnew file+9
@@ -0,0 +1,9 @@
1+module Main where
2+
3+-- | Here we go.
4+data Foo = Foo {unFoo :: Int}
5+ deriving (Eq)
6+
7+-- | And once again.
8+data Bar = Bar {unBar :: Int}
9+ deriving (Eq)
data/examples/declaration/data/simple-broken.hsnew file+12
@@ -0,0 +1,12 @@
1+module Main where
2+
3+-- | Here we go.
4+
5+data Foo
6+ = Foo { unFoo :: Int }
7+ deriving (Eq)
8+
9+-- | And once again.
10+
11+data Bar = Bar { unBar :: Int }
12+ deriving (Eq)
data/examples/declaration/data/simple-out.hs+2
@@ -1,3 +1,5 @@
1+module Main where
2+
1-- | And here we have 'Foo'.
3-- | And here we have 'Foo'.
2data Foo = Foo | Bar Int | Baz
4data Foo = Foo | Bar Int | Baz
3 deriving (Eq, Show)
5 deriving (Eq, Show)
data/examples/declaration/data/simple.hs+2
@@ -1,3 +1,5 @@
1+module Main where
2+
1-- | And here we have 'Foo'.
3-- | And here we have 'Foo'.
2
4
3data Foo = Foo | Bar Int | Baz
5data Foo = Foo | Bar Int | Baz
data/examples/declaration/data/strictness-out.hs+5−1
@@ -1,2 +1,6 @@
1+module Main where
2+
1-- | Something.
3-- | Something.
4+data Foo
2−data Foo = Foo !Int {-# UNPACK #-} !Bool {-# NOUNPACK #-} !String
5+ = Foo1 !Int {-# UNPACK #-} !Bool {-# NOUNPACK #-} !String
6+ | Foo2 {a :: {-# UNPACK #-} Maybe Int && Bool}
data/examples/declaration/data/strictness.hs+5−1
@@ -1,3 +1,7 @@
1+module Main where
2+
1-- | Something.
3-- | Something.
2
4
5+data Foo
3−data Foo = Foo !Int {-# UNPACK #-} !Bool {-# NOUNPACK #-} !String
6+ = Foo1 !Int {-# UNPACK #-} !Bool {-# NOUNPACK #-} !String
7+ | Foo2 { a :: {-# UNPACK #-} Maybe Int && Bool }
data/examples/declaration/data/unnamed-field-comment-0-out.hsnew file+7
@@ -0,0 +1,7 @@
1+data Foo
2+ = -- | Bar
3+ Bar
4+ Field1
5+ -- ^ Field 1
6+ Field2
7+ -- ^ Field 2
data/examples/declaration/data/unnamed-field-comment-0.hsnew file+5
@@ -0,0 +1,5 @@
1+data Foo
2+ = -- | Bar
3+ Bar
4+ Field1 -- ^ Field 1
5+ Field2 -- ^ Field 2
data/examples/declaration/data/unnamed-field-comment-1-out.hsnew file+5
@@ -0,0 +1,5 @@
1+data X
2+ = B
3+ !Int
4+ -- ^ y
5+ C
data/examples/declaration/data/unnamed-field-comment-1.hsnew file+4
@@ -0,0 +1,4 @@
1+data X
2+ = B
3+ !Int -- ^ y
4+ C
data/examples/declaration/data/with-comment-out.hsnew file+4
@@ -0,0 +1,4 @@
1+data A
2+ = B -- C
3+ | -- D
4+ E
data/examples/declaration/data/with-comment.hsnew file+5
@@ -0,0 +1,5 @@
1+data A =
2+ B -- C
3+
4+ -- D
5+ | E
data/examples/declaration/data/with-weird-haddock-out.hsnew file+4
@@ -0,0 +1,4 @@
1+data PlusLevel' t
2+ = -- | @n + ℓ@.
3+ Plus Integer (LevelAtom' t)
4+ deriving (Show, Data)
data/examples/declaration/data/with-weird-haddock.hsnew file+2
@@ -0,0 +1,2 @@
1+data PlusLevel' t = Plus Integer (LevelAtom' t) -- ^ @n + ℓ@.
2+ deriving (Show, Data)
data/examples/declaration/default/default-out.hsnew file+7
@@ -0,0 +1,7 @@
1+default (Int, Foo, Bar)
2+
3+default
4+ ( Int,
5+ Foo,
6+ Bar
7+ )
data/examples/declaration/default/default.hsnew file+6
@@ -0,0 +1,6 @@
1+default ( Int , Foo , Bar )
2+
3+default ( Int
4+ , Foo,
5+ Bar
6+ )
data/examples/declaration/deriving/multiline-out.hsnew file+24
@@ -0,0 +1,24 @@
1+deriving instance
2+ Eq
3+ Foo
4+
5+deriving stock instance
6+ Show
7+ Foo
8+
9+deriving anyclass instance
10+ ToJSON
11+ Foo
12+
13+deriving newtype instance
14+ Data
15+ Foo
16+
17+deriving via
18+ Foo
19+ Int
20+ instance
21+ Triple
22+ A
23+ B
24+ C
data/examples/declaration/deriving/multiline.hsnew file+19
@@ -0,0 +1,19 @@
1+deriving instance Eq
2+ Foo
3+
4+deriving stock instance
5+ Show
6+ Foo
7+deriving anyclass instance
8+ ToJSON
9+ Foo
10+deriving newtype instance
11+ Data
12+ Foo
13+
14+deriving via Foo
15+ Int
16+ instance Triple
17+ A
18+ B
19+ C
data/examples/declaration/deriving/overlapping-out.hsnew file+19
@@ -0,0 +1,19 @@
1+deriving instance
2+ {-# OVERLAPPABLE #-}
3+ Ord
4+ Foo
5+
6+deriving instance
7+ {-# OVERLAPPING #-}
8+ Num
9+ Foo
10+
11+deriving instance
12+ {-# OVERLAPS #-}
13+ Read
14+ Foo
15+
16+deriving instance
17+ {-# INCOHERENT #-}
18+ Show
19+ Foo
data/examples/declaration/deriving/overlapping.hsnew file+17
@@ -0,0 +1,17 @@
1+deriving instance
2+ {-# OVERLAPPABLE #-}
3+ Ord
4+ Foo
5+deriving instance
6+ {-# OVERLAPPING #-}
7+ Num
8+ Foo
9+deriving instance
10+ {-# OVERLAPS #-}
11+ Read
12+ Foo
13+deriving instance
14+ {-# INCOHERENT #-}
15+ Show
16+ Foo
17+
data/examples/declaration/deriving/singleline-out.hsnew file+17
@@ -0,0 +1,17 @@
1+deriving instance Eq Foo
2+
3+deriving stock instance Show Foo
4+
5+deriving anyclass instance ToJSON Foo
6+
7+deriving newtype instance Data Foo
8+
9+deriving instance {-# OVERLAPPABLE #-} Ord Foo
10+
11+deriving instance {-# OVERLAPPING #-} Num Foo
12+
13+deriving instance {-# OVERLAPS #-} Read Foo
14+
15+deriving instance {-# INCOHERENT #-} Show Foo
16+
17+deriving via Int instance Triple A B C
data/examples/declaration/deriving/singleline.hsnew file+12
@@ -0,0 +1,12 @@
1+deriving instance Eq Foo
2+
3+deriving stock instance Show Foo
4+deriving anyclass instance ToJSON Foo
5+deriving newtype instance Data Foo
6+
7+deriving instance {-# OVERLAPPABLE #-} Ord Foo
8+deriving instance {-# OVERLAPPING #-} Num Foo
9+deriving instance {-# OVERLAPS #-} Read Foo
10+deriving instance {-# INCOHERENT #-} Show Foo
11+
12+deriving via Int instance Triple A B C
data/examples/declaration/foreign/foreign-export-out.hsnew file+9
@@ -0,0 +1,9 @@
1+foreign export ccall foo :: Int -> IO Int
2+
3+-- | 'foreignTomFun' is a very important thing
4+foreign export ccall "tomography"
5+ foreignTomFun ::
6+ StablePtr Storage {- Storage is bad -} -> TomForegin
7+
8+foreign export {- We can't use capi here -} ccall "dynamic"
9+ export_nullaryMeth :: (IO HRESULT) -> IO (Ptr ())
data/examples/declaration/foreign/foreign-export.hsnew file+8
@@ -0,0 +1,8 @@
1+foreign export ccall foo :: Int -> IO Int
2+
3+-- | 'foreignTomFun' is a very important thing
4+foreign export ccall "tomography" foreignTomFun
5+ :: StablePtr Storage {- Storage is bad -} -> TomForegin
6+
7+foreign export {- We can't use capi here -} ccall "dynamic"
8+ export_nullaryMeth :: (IO HRESULT) -> IO (Ptr ())
data/examples/declaration/foreign/foreign-import-out.hsnew file+25
@@ -0,0 +1,25 @@
1+{-# LANGUAGE CApiFFI #-}
2+
3+foreign import ccall safe foo :: Int -> IO Int
4+
5+-- | 'bar' is a very important thing
6+foreign import stdcall "baz" bar :: String -> Int -> IO String
7+
8+foreign import stdcall unsafe "boo"
9+ -- Here is a comment about my foreign function
10+ boo :: Int -> Text -> IO Array
11+
12+foreign import javascript
13+ baz ::
14+ String ->
15+ Int ->
16+ IO Foo
17+
18+foreign import {- We use capi here -} capi "pi.h value pi" c_pi :: CDouble
19+
20+foreign import stdcall {- This is a bad place for a comment -} "dynamic"
21+ dyn_gluBeginSurface ::
22+ -- | This 'FunPtr' is extremely dangerous, beware
23+ FunPtr (Ptr GLUnurbs -> IO ()) ->
24+ Ptr GLUnurbs ->
25+ IO ()
data/examples/declaration/foreign/foreign-import.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE CApiFFI #-}
2+
3+foreign import ccall safe foo :: Int -> IO Int
4+
5+-- | 'bar' is a very important thing
6+foreign import stdcall "baz" bar :: String -> Int -> IO String
7+
8+foreign import stdcall unsafe "boo"
9+ -- Here is a comment about my foreign function
10+ boo :: Int -> Text -> IO Array
11+
12+foreign import javascript baz :: String
13+ -> Int -> IO Foo
14+
15+foreign import {- We use capi here -} capi "pi.h value pi" c_pi :: CDouble
16+
17+foreign import stdcall {- This is a bad place for a comment -} "dynamic" dyn_gluBeginSurface
18+ :: FunPtr (Ptr GLUnurbs -> IO ())
19+ -- ^ This 'FunPtr' is extremely dangerous, beware
20+ -> Ptr GLUnurbs -> IO ()
data/examples/declaration/instance/associated-data-out.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+instance Foo Int where data Bar Int = IntBar Int Int
4+
5+instance Foo Double where
6+ newtype
7+ Bar
8+ Double
9+ = DoubleBar
10+ Double
11+ Double
12+
13+instance Foo [a] where
14+ data Bar [a]
15+ = ListBar [Bar a]
16+ data Baz [a]
17+ = ListBaz
data/examples/declaration/instance/associated-data.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+instance Foo Int where data Bar Int = IntBar Int Int
4+
5+instance Foo Double where
6+ newtype
7+ Bar
8+ Double
9+ =
10+ DoubleBar
11+ Double
12+ Double
13+
14+instance Foo [a]
15+ where
16+
17+ data Bar [a] =
18+ ListBar [Bar a]
19+ data Baz [a] =
20+ ListBaz
data/examples/declaration/instance/associated-types-out.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+instance Foo Int where type Bar Int = Double
4+
5+instance Foo Double where
6+ type
7+ Bar
8+ Double =
9+ [Double]
10+
11+ type
12+ Baz Double =
13+ [Double]
data/examples/declaration/instance/associated-types.hsnew file+15
@@ -0,0 +1,15 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+instance Foo Int where type Bar Int = Double
4+
5+instance Foo Double
6+ where
7+ type
8+ Bar
9+ Double
10+ =
11+ [Double]
12+
13+
14+ type instance Baz Double
15+ = [Double]
data/examples/declaration/instance/contexts-comments-out.hsnew file+17
@@ -0,0 +1,17 @@
1+instance
2+ ( Read a, -- Foo
3+ Read b,
4+ Read
5+ ( c, -- Bar
6+ d
7+ )
8+ ) =>
9+ Read
10+ ( a, -- Baz
11+ b,
12+ ( c, -- Quux
13+ d
14+ )
15+ )
16+ where
17+ readsPrec = undefined
data/examples/declaration/instance/contexts-comments.hsnew file+18
@@ -0,0 +1,18 @@
1+instance (
2+ Read a, -- Foo
3+ Read b
4+ , Read (
5+ c, -- Bar
6+ d
7+ )
8+ )
9+ =>
10+ Read (
11+ a, -- Baz
12+ b
13+ ,(
14+ c, -- Quux
15+ d
16+ )
17+ ) where
18+ readsPrec = undefined
data/examples/declaration/instance/contexts-out.hsnew file+18
@@ -0,0 +1,18 @@
1+instance Eq a => Eq [a] where (==) _ _ = False
2+
3+instance
4+ ( Ord a,
5+ Ord b
6+ ) =>
7+ Ord (a, b)
8+ where
9+ compare _ _ = GT
10+
11+instance
12+ (Show a, Show b) =>
13+ Show
14+ ( a,
15+ b
16+ )
17+ where
18+ showsPrec _ _ = showString ""
data/examples/declaration/instance/contexts.hsnew file+14
@@ -0,0 +1,14 @@
1+instance Eq a=>Eq [a] where (==) _ _ = False
2+
3+instance (
4+ Ord a,
5+ Ord b
6+ ) => Ord (a,b) where
7+ compare _ _ = GT
8+
9+instance (Show a, Show b) =>
10+ Show (
11+ a,
12+ b
13+ ) where
14+ showsPrec _ _ = showString ""
data/examples/declaration/instance/data-family-instances-gadt-out.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# LANGUAGE GADTSyntax #-}
2+{-# LANGUAGE TypeFamilies #-}
3+
4+data instance Bar Int a where
5+ SameBar ::
6+ Bar
7+ Int
8+ Int
9+ CloseBar :: Bar Int Double
10+ OtherBar ::
11+ Bar
12+ Int
13+ a
data/examples/declaration/instance/data-family-instances-gadt.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE GADTSyntax #-}
2+{-# LANGUAGE TypeFamilies #-}
3+data instance Bar Int a where
4+ SameBar
5+ :: Bar Int
6+ Int
7+ CloseBar :: Bar Int Double
8+ OtherBar
9+ :: Bar Int
10+ a
data/examples/declaration/instance/data-family-instances-newtype-out.hsnew file+6
@@ -0,0 +1,6 @@
1+{-# LANGUAGE GADTSyntax #-}
2+{-# LANGUAGE TypeFamilies #-}
3+
4+newtype instance Foo [Double] = DoubleListFoo
5+ { unDoubleListFoo :: Double
6+ }
data/examples/declaration/instance/data-family-instances-newtype.hsnew file+6
@@ -0,0 +1,6 @@
1+{-# LANGUAGE GADTSyntax #-}
2+{-# LANGUAGE TypeFamilies #-}
3+newtype instance Foo [Double] = DoubleListFoo {
4+ unDoubleListFoo :: Double
5+}
6+
data/examples/declaration/instance/data-family-instances-out.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE GADTSyntax #-}
2+{-# LANGUAGE TypeFamilies #-}
3+
4+data instance Foo Int = FooInt Int
5+
6+data instance
7+ Foo
8+ [Int]
9+ = IntListFoo
10+ ( Int,
11+ Int
12+ )
13+ ( Double,
14+ Double
15+ )
16+
17+data instance Bar Double a
18+ = DoubleBar
19+ Double
20+ (Bar a)
data/examples/declaration/instance/data-family-instances.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE GADTSyntax #-}
2+{-# LANGUAGE TypeFamilies #-}
3+data instance Foo Int = FooInt Int
4+
5+data instance
6+ Foo [
7+ Int
8+ ] = IntListFoo (
9+ Int,
10+ Int
11+ ) (
12+ Double,
13+ Double
14+ )
15+
16+data instance Bar Double a =
17+ DoubleBar
18+ Double
19+ (Bar a)
20+
data/examples/declaration/instance/empty-instance-out.hsnew file+3
@@ -0,0 +1,3 @@
1+instance Typeable Int
2+
3+instance Generic Int
data/examples/declaration/instance/empty-instance.hsnew file+2
@@ -0,0 +1,2 @@
1+instance Typeable Int
2+instance Generic Int where
data/examples/declaration/instance/instance-sigs-multiple-out.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE InstanceSigs #-}
2+
3+instance Applicative [] where
4+ pure ::
5+ a ->
6+ [a]
7+ pure a = [a]
8+ (<*>) ::
9+ [a] -> [a] -> [a]
10+ (<*>) _ _ = []
data/examples/declaration/instance/instance-sigs-multiple.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE InstanceSigs #-}
2+
3+instance Applicative [] where
4+ pure ::
5+ a
6+ -> [a]
7+ pure a = [a]
8+ (<*>)
9+ :: [ a ] -> [ a ] -> [ a ]
10+ (<*>) _ _ = []
data/examples/declaration/instance/instance-sigs-out.hsnew file+15
@@ -0,0 +1,15 @@
1+{-# LANGUAGE InstanceSigs #-}
2+
3+instance Eq Int where
4+ (==) :: Int -> Int -> Bool
5+ (==) _ _ = False
6+
7+instance Ord Int where
8+ compare ::
9+ Int ->
10+ Int ->
11+ Ordering
12+ compare
13+ _
14+ _ =
15+ GT
data/examples/declaration/instance/instance-sigs.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE InstanceSigs #-}
2+
3+instance Eq Int
4+ where
5+ (==) :: Int -> Int -> Bool
6+ (==) _ _ = False
7+
8+instance Ord Int where
9+ compare ::
10+ Int
11+ -> Int
12+ -> Ordering
13+ compare
14+ _
15+ _
16+ = GT
data/examples/declaration/instance/multi-parameter-out.hsnew file+5
@@ -0,0 +1,5 @@
1+instance MonadReader a ((->) a) where ask = id
2+
3+instance MonadState s (State s) where
4+ get = State.get
5+ put = State.put
data/examples/declaration/instance/multi-parameter.hsnew file+6
@@ -0,0 +1,6 @@
1+instance MonadReader a ((->) a) where ask = id
2+
3+instance MonadState s (State s)
4+ where
5+ get = State.get
6+ put = State.put
data/examples/declaration/instance/newlines-after-where-out.hsnew file+5
@@ -0,0 +1,5 @@
1+instance Num X where
2+ (+) = undefined
3+
4+instance Num Y where
5+ (+) = undefined
data/examples/declaration/instance/newlines-after-where.hsnew file+7
@@ -0,0 +1,7 @@
1+instance Num X where
2+ (+) = undefined
3+
4+instance Num Y where
5+
6+
7+ (+) = undefined
data/examples/declaration/instance/newlines-between-methods-out.hsnew file+18
@@ -0,0 +1,18 @@
1+instance Num a => Num (Diff a) where
2+ D u dudx + D v dvdx = D (u + v) (dudx + dvdx)
3+ D u dudx - D v dvdx = D (u - v) (dudx - dvdx)
4+ D u dudx * D v dvdx = D (u * v) (u * dvdx + v * dudx)
5+
6+ -- Comment before definition
7+ negate (D u dudx) = D (- u) (- dudx)
8+ negate (Z u dudx) = undefined
9+
10+ -- Comment after definition
11+
12+ -- Separator
13+
14+ abs (D u _) = D (abs u) (signum u)
15+ signum (D u _) = D (signum u) 0
16+
17+ -- Comment between unrelated definitions
18+ fromInteger n = D (fromInteger n) 0
data/examples/declaration/instance/newlines-between-methods.hsnew file+16
@@ -0,0 +1,16 @@
1+instance Num a => Num (Diff a) where
2+ D u dudx + D v dvdx = D (u + v) (dudx + dvdx)
3+ D u dudx - D v dvdx = D (u - v) (dudx - dvdx)
4+ D u dudx * D v dvdx = D (u * v) (u * dvdx + v * dudx)
5+
6+ -- Comment before definition
7+ negate (D u dudx) = D (-u) (-dudx)
8+ negate (Z u dudx) = undefined
9+ -- Comment after definition
10+
11+ -- Separator
12+
13+ abs (D u _) = D (abs u) (signum u)
14+ signum (D u _) = D (signum u) 0
15+ -- Comment between unrelated definitions
16+ fromInteger n = D (fromInteger n) 0
data/examples/declaration/instance/overlappable-instances-out.hsnew file+14
@@ -0,0 +1,14 @@
1+instance {-# OVERLAPPABLE #-} Eq Int where (==) _ _ = False
2+
3+instance {-# OVERLAPPING #-} Ord Int where
4+ compare _ _ = GT
5+
6+instance {-# OVERLAPS #-} Eq Double where
7+ (==) _ _ = False
8+
9+instance
10+ {-# INCOHERENT #-}
11+ Ord
12+ Double
13+ where
14+ compare _ _ = GT
data/examples/declaration/instance/overlappable-instances.hsnew file+13
@@ -0,0 +1,13 @@
1+instance {-# OVERLAPPABLE #-} Eq Int where (==) _ _ = False
2+
3+instance
4+ {-# OVERLAPPING #-} Ord Int where compare _ _ = GT
5+
6+instance {-# OVERLAPS #-} Eq Double where
7+ (==) _ _ = False
8+
9+instance
10+ {-# INCOHERENT #-}
11+ Ord
12+ Double where
13+ compare _ _ = GT
data/examples/declaration/instance/single-parameter-out.hsnew file+9
@@ -0,0 +1,9 @@
1+instance Monoid Int where (<>) x y = x + y
2+
3+instance Enum Int where
4+ fromEnum x = x
5+ toEnum =
6+ \x ->
7+ x
8+
9+instance Foo Int where foo x = x; bar y = y
data/examples/declaration/instance/single-parameter.hsnew file+10
@@ -0,0 +1,10 @@
1+instance Monoid Int where (<>) x y = x+y
2+
3+instance Enum Int
4+ where
5+ fromEnum x = x
6+ toEnum
7+ = \x ->
8+ x
9+
10+instance Foo Int where { foo x = x; bar y = y }
data/examples/declaration/instance/type-family-instances-out.hsnew file+21
@@ -0,0 +1,21 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+type instance Foo Int = Int
4+
5+type instance
6+ Foo
7+ [Int] =
8+ ( Int,
9+ Int
10+ )
11+
12+type instance Bar Int [Int] Double = (Int, Double)
13+
14+type instance
15+ Bar
16+ [Int]
17+ [Int]
18+ Double =
19+ ( Int,
20+ Double
21+ )
data/examples/declaration/instance/type-family-instances.hsnew file+21
@@ -0,0 +1,21 @@
1+{-# LANGUAGE TypeFamilies #-}
2+
3+type instance Foo Int = Int
4+
5+type instance
6+ Foo
7+ [Int] = ( Int,
8+ Int
9+ )
10+
11+type instance Bar Int [Int] Double = ( Int, Double )
12+
13+type instance
14+ Bar
15+ [Int]
16+ [Int]
17+ Double
18+ = (
19+ Int,
20+ Double
21+ )
data/examples/declaration/rewrite-rule/basic1-out.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# RULES
2+"fold/build" foldr k z (build g) = g k z
3+ #-}
4+
5+{-# RULES
6+"fusable/aux"
7+ fusable x (aux y) =
8+ faux x y
9+ #-}
10+
11+{-# RULES
12+"map/map"
13+ map
14+ f
15+ (map g xs) =
16+ map
17+ (f . g)
18+ xs
19+ #-}
data/examples/declaration/rewrite-rule/basic1.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# RULES
2+"fold/build" foldr k z (build g) = g k z
3+ #-}
4+
5+{-# RULES
6+"fusable/aux"
7+ fusable x (aux y) = faux x y
8+ #-}
9+
10+{-# RULES
11+"map/map"
12+ map f
13+ (map g xs) = map
14+ (f . g)
15+ xs
16+ #-}
17+
data/examples/declaration/rewrite-rule/basic2-out.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# RULES
2+"++" xs ++ ys = augment (\c n -> foldr c n xs) ys
3+"concat" xs `concat` ys = augment (\c n -> foldr c n xs) ys
4+ #-}
5+
6+{-# RULES
7+"++" xs ++ ys = augment (\c n -> foldr c n xs) ys
8+"concat" xs `concat` ys = augment (\c n -> foldr c n xs) ys
9+"map/Double" fmap f xs = foldr (++) f xs
10+ #-}
11+
12+{-# RULES
13+"fb' >\\ (Request b' fb )" forall fb' b' fb.
14+ fb' >\\ (Request b' fb) =
15+ fb' b' >>= \b -> fb' >\\ fb b
16+ #-}
data/examples/declaration/rewrite-rule/basic2.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# RULES
2+"++" xs ++ ys = augment (\c n -> foldr c n xs) ys
3+"concat" xs `concat` ys = augment (\c n -> foldr c n xs) ys
4+ #-}
5+
6+{-# RULES
7+"++" xs ++ ys = augment (\c n -> foldr c n xs) ys;
8+"concat" xs `concat` ys = augment (\c n -> foldr c n xs) ys;
9+"map/Double" fmap f xs = foldr (++) f xs
10+ #-}
11+
12+{-# RULES
13+ "fb' >\\ (Request b' fb )" forall fb' b' fb .
14+ fb' >\\ (Request b' fb ) = fb' b' >>= \b -> fb' >\\ fb b;
15+#-}
16+
data/examples/declaration/rewrite-rule/empty-out.hsnew file+3
@@ -0,0 +1,3 @@
1+{-# RULES
2+
3+ #-}
data/examples/declaration/rewrite-rule/empty.hsnew file+2
@@ -0,0 +1,2 @@
1+{-# RULES
2+ #-}
data/examples/declaration/rewrite-rule/forall-0-out.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# RULES
2+"fold/build" forall k z. foldr k z (build g) = g k z
3+ #-}
4+
5+{-# RULES
6+"fusable/aux" forall x y.
7+ fusable x (aux y) =
8+ faux x y
9+ #-}
data/examples/declaration/rewrite-rule/forall-0.hsnew file+8
@@ -0,0 +1,8 @@
1+{-# RULES
2+"fold/build" forall k z . foldr k z (build g) = g k z
3+ #-}
4+
5+{-# RULES
6+"fusable/aux" forall x y.
7+ fusable x (aux y) = faux x y
8+ #-}
data/examples/declaration/rewrite-rule/forall-1-out.hsnew file+23
@@ -0,0 +1,23 @@
1+{-# RULES "rd_tyvs" forall a. forall (x :: a). id x = x #-}
2+
3+{-# RULES "rd_tyvs'" forall f a. forall (x :: f a). id x = x #-}
4+
5+{-# RULES "rd_tyvs''" forall (a :: *). forall (x :: a). id x = x #-}
6+
7+{-# RULES
8+"rd_tyvs_multiline1" forall (a :: *). forall (x :: a).
9+ id x =
10+ x
11+ #-}
12+
13+{-# RULES
14+"rd_tyvs_multiline2" forall
15+ ( a ::
16+ *
17+ ). forall
18+ ( x ::
19+ a
20+ ).
21+ id x =
22+ x
23+ #-}
data/examples/declaration/rewrite-rule/forall-1.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# RULES "rd_tyvs" forall a. forall (x :: a). id x = x #-}
2+
3+{-# RULES "rd_tyvs'" forall f a. forall (x :: f a). id x = x #-}
4+
5+{-# RULES "rd_tyvs''" forall (a :: *). forall (x :: a). id x = x #-}
6+
7+{-# RULES "rd_tyvs_multiline1"
8+ forall (a :: *).
9+ forall (x :: a).
10+ id x = x #-}
11+
12+{-# RULES "rd_tyvs_multiline2"
13+ forall (a ::
14+ *).
15+ forall (x ::
16+ a).
17+ id x = x #-}
data/examples/declaration/rewrite-rule/phase-out.hsnew file+23
@@ -0,0 +1,23 @@
1+{-# RULES
2+"map/map" [2]
3+ map
4+ f
5+ (map g xs) =
6+ map
7+ (f . g)
8+ xs
9+ #-}
10+
11+{-# RULES
12+"map/map" [1] forall x y z.
13+ map
14+ f
15+ (map g xs) =
16+ map
17+ (f . g)
18+ xs
19+ #-}
20+
21+{-# RULES
22+"++" [~1] forall xs ys. xs ++ ys = augment (\c n -> foldr c n xs) ys
23+ #-}
data/examples/declaration/rewrite-rule/phase.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# RULES
2+"map/map" [2]
3+ map f
4+ (map g xs) = map
5+ (f . g)
6+ xs
7+ #-}
8+
9+{-# RULES
10+"map/map" [1] forall x y z.
11+ map f
12+ (map g xs) = map
13+ (f . g)
14+ xs
15+ #-}
16+
17+{-# RULES
18+"++" [~1] forall xs ys. xs ++ ys = augment (\c n -> foldr c n xs) ys
19+ #-}
data/examples/declaration/rewrite-rule/prelude1-out.hsnew file+18
@@ -0,0 +1,18 @@
1+{-# RULES
2+"map/map" forall f g xs. map f (map g xs) = map (f . g) xs
3+"map/append" forall f xs ys. map f (xs ++ ys) = map f xs ++ map f ys
4+ #-}
5+
6+{-# RULES
7+"map" [~1] forall f xs. map f xs = build (\c n -> foldr (mapFB c f) n xs)
8+"mapList" [1] forall f. foldr (mapFB (:) f) [] = map f
9+"mapFB" forall c f g. mapFB (mapFB c f) g = mapFB c (f . g)
10+ #-}
11+
12+{-# RULES
13+"map/map" [~2] forall f g xs.
14+ map f (map g xs) =
15+ map (f . g) xs
16+"f" op True y = False
17+"g" op True y = False
18+ #-}
data/examples/declaration/rewrite-rule/prelude1.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# RULES
2+"map/map" forall f g xs. map f (map g xs) = map (f.g) xs
3+"map/append" forall f xs ys. map f (xs ++ ys) = map f xs ++ map f ys
4+ #-}
5+
6+{-# RULES
7+"map" [~1] forall f xs. map f xs = build (\c n -> foldr (mapFB c f) n xs)
8+"mapList" [1] forall f. foldr (mapFB (:) f) [] = map f
9+"mapFB" forall c f g. mapFB (mapFB c f) g = mapFB c (f.g)
10+ #-}
11+
12+{-# RULES
13+ "map/map" [~2] forall f g xs.
14+ map f (map g xs) = map (f.g) xs; "f" op True y = False;
15+ "g" op True y = False
16+#-}
17+
data/examples/declaration/rewrite-rule/prelude2-out.hsnew file+31
@@ -0,0 +1,31 @@
1+{-# RULES
2+"fold/build" forall k z (g :: forall b. (a -> b -> b) -> b -> b).
3+ foldr k z (build g) =
4+ g k z
5+"foldr/augment" forall k z xs (g :: forall b. (a -> b -> b) -> b -> b).
6+ foldr k z (augment g xs) =
7+ g k (foldr k z xs)
8+"foldr/id" foldr (:) [] = \x -> x
9+"foldr/app" [1] forall ys. foldr (:) ys = \xs -> xs ++ ys
10+-- Only activate this from phase 1, because that's
11+-- when we disable the rule that expands (++) into foldr
12+
13+-- The foldr/cons rule looks nice, but it can give disastrously
14+-- bloated code when commpiling
15+-- array (a,b) [(1,2), (2,2), (3,2), ...very long list... ]
16+-- i.e. when there are very very long literal lists
17+-- So I've disabled it for now. We could have special cases
18+-- for short lists, I suppose.
19+-- "foldr/cons" forall k z x xs. foldr k z (x:xs) = k x (foldr k z xs)
20+
21+"foldr/single" forall k z x. foldr k z [x] = k x z
22+"foldr/nil" forall k z. foldr k z [] = z
23+"augment/build" forall
24+ (g :: forall b. (a -> b -> b) -> b -> b)
25+ (h :: forall b. (a -> b -> b) -> b -> b).
26+ augment g (build h) =
27+ build (\c n -> g c (h c n))
28+"augment/nil" forall (g :: forall b. (a -> b -> b) -> b -> b).
29+ augment g [] =
30+ build g
31+ #-}
data/examples/declaration/rewrite-rule/prelude2.hsnew file+29
@@ -0,0 +1,29 @@
1+{-# RULES
2+"fold/build" forall k z (g::forall b. (a->b->b) -> b -> b) .
3+ foldr k z (build g) = g k z
4+
5+"foldr/augment" forall k z xs (g::forall b. (a->b->b) -> b -> b) .
6+ foldr k z (augment g xs) = g k (foldr k z xs)
7+
8+"foldr/id" foldr (:) [] = \x -> x
9+"foldr/app" [1] forall ys. foldr (:) ys = \xs -> xs ++ ys
10+ -- Only activate this from phase 1, because that's
11+ -- when we disable the rule that expands (++) into foldr
12+
13+-- The foldr/cons rule looks nice, but it can give disastrously
14+-- bloated code when commpiling
15+-- array (a,b) [(1,2), (2,2), (3,2), ...very long list... ]
16+-- i.e. when there are very very long literal lists
17+-- So I've disabled it for now. We could have special cases
18+-- for short lists, I suppose.
19+-- "foldr/cons" forall k z x xs. foldr k z (x:xs) = k x (foldr k z xs)
20+
21+"foldr/single" forall k z x. foldr k z [x] = k x z
22+"foldr/nil" forall k z. foldr k z [] = z
23+
24+"augment/build" forall (g::forall b. (a->b->b) -> b -> b)
25+ (h::forall b. (a->b->b) -> b -> b) .
26+ augment g (build h) = build (\c n -> g c (h c n))
27+"augment/nil" forall (g::forall b. (a->b->b) -> b -> b) .
28+ augment g [] = build g
29+ #-}
data/examples/declaration/rewrite-rule/prelude3-out.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE MagicHash #-}
2+
3+{-# RULES
4+"x# `eqChar#` x#" forall x#. x# `eqChar#` x# = True
5+"x# `neChar#` x#" forall x#. x# `neChar#` x# = False
6+"x# `gtChar#` x#" forall x#. x# `gtChar#` x# = False
7+"x# `geChar#` x#" forall x#. x# `geChar#` x# = True
8+"x# `leChar#` x#" forall x#. x# `leChar#` x# = True
9+"x# `ltChar#` x#" forall x#. x# `ltChar#` x# = False
10+ #-}
data/examples/declaration/rewrite-rule/prelude3.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE MagicHash #-}
2+
3+{-# RULES
4+"x# `eqChar#` x#" forall x#. x# `eqChar#` x# = True
5+"x# `neChar#` x#" forall x#. x# `neChar#` x# = False
6+"x# `gtChar#` x#" forall x#. x# `gtChar#` x# = False
7+"x# `geChar#` x#" forall x#. x# `geChar#` x# = True
8+"x# `leChar#` x#" forall x#. x# `leChar#` x# = True
9+"x# `ltChar#` x#" forall x#. x# `ltChar#` x# = False
10+ #-}
data/examples/declaration/rewrite-rule/prelude4-out.hsnew file+7
@@ -0,0 +1,7 @@
1+{-# RULES
2+"unpack" [~1] forall a. unpackCString # a = build (unpackFoldrCString # a)
3+"unpack-list" [1] forall a. unpackFoldrCString # a (:) [] = unpackCString # a
4+"unpack-append" forall a n. unpackFoldrCString # a (:) n = unpackAppendCString # a n
5+-- There's a built-in rule (in PrelRules.lhs) for
6+-- unpackFoldr "foo" c (unpackFoldr "baz" c n) = unpackFoldr "foobaz" c n
7+ #-}
data/examples/declaration/rewrite-rule/prelude4.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# RULES
2+"unpack" [~1] forall a . unpackCString# a = build (unpackFoldrCString# a)
3+"unpack-list" [1] forall a . unpackFoldrCString# a (:) [] = unpackCString# a
4+"unpack-append" forall a n . unpackFoldrCString# a (:) n = unpackAppendCString# a n
5+
6+-- There's a built-in rule (in PrelRules.lhs) for
7+-- unpackFoldr "foo" c (unpackFoldr "baz" c n) = unpackFoldr "foobaz" c n
8+
9+ #-}
data/examples/declaration/rewrite-rule/type-signature-out.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# RULES
2+"fold/build" forall k z (g :: forall b. (a -> b -> b) -> b -> b). foldr k z (build g) = g k z
3+ #-}
4+
5+{-# RULES
6+"fold/build" forall
7+ k
8+ z
9+ ( g ::
10+ forall b.
11+ (a -> b -> b) ->
12+ b ->
13+ b
14+ ).
15+ foldr k z (build g) =
16+ g k z
17+ #-}
data/examples/declaration/rewrite-rule/type-signature.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# RULES
2+"fold/build" forall k z (g :: forall b. (a -> b -> b) -> b -> b). foldr k z (build g) = g k z
3+ #-}
4+
5+{-# RULES
6+"fold/build"
7+ forall k z
8+ (g :: forall b.
9+ (a -> b -> b) -> b -> b).
10+ foldr k z (build g) =
11+ g k z
12+ #-}
data/examples/declaration/role-annotation/multi-line-out.hsnew file+15
@@ -0,0 +1,15 @@
1+type role
2+ D
3+ phantom
4+ nominal
5+
6+type role
7+ E
8+ _
9+ nominal
10+
11+type role
12+ E
13+ _
14+ nominal
15+ phantom
data/examples/declaration/role-annotation/multi-line.hsnew file+15
@@ -0,0 +1,15 @@
1+type role
2+ D phantom nominal
3+
4+type
5+ role
6+ E
7+ _
8+ nominal
9+
10+type
11+ role
12+ E
13+ _
14+ nominal
15+ phantom
data/examples/declaration/role-annotation/single-line-out.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE MagicHash #-}
2+{-# LANGUAGE RoleAnnotations #-}
3+
4+type role Ptr representational
5+
6+type role A nominal nominal
7+
8+type role B _ phantom
9+
10+type role C _ _
data/examples/declaration/role-annotation/single-line.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# LANGUAGE RoleAnnotations #-}
2+{-# LANGUAGE MagicHash #-}
3+
4+type role Ptr representational
5+
6+type role A nominal nominal
7+
8+type role B _ phantom
9+type role C _ _
data/examples/declaration/signature/complete/complete-out.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# COMPLETE A, B, C :: Foo #-}
2+
3+{-# COMPLETE A, B #-}
4+
5+{-# COMPLETE
6+ A,
7+ B,
8+ C ::
9+ Foo
10+ #-}
data/examples/declaration/signature/complete/complete.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# ComPlETe A , B, C:: Foo
2+
3+ #-}
4+
5+{-# COMPLETE A , B
6+ #-}
7+
8+{-# ComPlETE
9+ A ,
10+ B, C
11+
12+
13+ :: Foo#-}
data/examples/declaration/signature/fixity/infix-out.hsnew file+3
@@ -0,0 +1,3 @@
1+infix 0 <?>
2+
3+infix 9 <^-^>
data/examples/declaration/signature/fixity/infix.hsnew file+2
@@ -0,0 +1,2 @@
1+infix 0 <?>
2+infix 9 <^-^>
data/examples/declaration/signature/fixity/infixl-out.hsnew file+3
@@ -0,0 +1,3 @@
1+infixl 8 ***
2+
3+infixl 0 $, *, +, &&, **
data/examples/declaration/signature/fixity/infixl.hsnew file+2
@@ -0,0 +1,2 @@
1+infixl 8 ***
2+infixl 0 $, *, +, &&, **
data/examples/declaration/signature/fixity/infixr-out.hsnew file+3
@@ -0,0 +1,3 @@
1+infixr 8 `Foo`
2+
3+infixr 0 ***, &&&
data/examples/declaration/signature/fixity/infixr.hsnew file+2
@@ -0,0 +1,2 @@
1+infixr 8 `Foo`
2+infixr 0 ***, &&&
data/examples/declaration/signature/inline/conlike-out.hsnew file+7
@@ -0,0 +1,7 @@
1+foo :: Int
2+foo = 5
3+{-# INLINE CONLIKE foo #-}
4+
5+bar :: Int
6+bar = 6
7+{-# INLINE CONLIKE bar #-}
data/examples/declaration/signature/inline/conlike.hsnew file+7
@@ -0,0 +1,7 @@
1+foo :: Int
2+foo = 5
3+{-# INLINE CONLIKE foo #-}
4+
5+bar :: Int
6+bar = 6
7+{-# INLINE CONLIKE bar #-}
data/examples/declaration/signature/inline/inline-out.hsnew file+15
@@ -0,0 +1,15 @@
1+foo :: Int -> Int
2+foo = id
3+{-# INLINE foo #-}
4+
5+{-# INLINE [2] bar #-}
6+bar :: Int -> Int
7+bar = id
8+
9+baz :: Int -> Int
10+baz = id
11+{-# INLINE [~2] baz #-}
12+
13+reVector :: Bundle u a -> Bundle v a
14+{-# INLINE reVector #-}
15+reVector = M.reVector
data/examples/declaration/signature/inline/inline.hsnew file+18
@@ -0,0 +1,18 @@
1+foo :: Int -> Int
2+foo = id
3+
4+{-# INLINE foo #-}
5+
6+{-# INLINE [2] bar #-}
7+
8+bar :: Int -> Int
9+bar = id
10+
11+baz :: Int -> Int
12+baz = id
13+{-# INLINE [~2] baz #-}
14+
15+reVector :: Bundle u a -> Bundle v a
16+
17+{-# INLINE reVector #-}
18+reVector = M.reVector
data/examples/declaration/signature/inline/inlineable-out.hsnew file+11
@@ -0,0 +1,11 @@
1+foo :: Int -> Int
2+foo = id
3+{-# INLINEABLE foo #-}
4+
5+{-# INLINEABLE [2] bar #-}
6+bar :: Int -> Int
7+bar = id
8+
9+baz :: Int -> Int
10+baz = id
11+{-# INLINEABLE [~2] baz #-}
data/examples/declaration/signature/inline/inlineable.hsnew file+13
@@ -0,0 +1,13 @@
1+foo :: Int -> Int
2+foo = id
3+
4+{-# INLINEABLE foo #-}
5+
6+{-# INLINEABLE [2] bar #-}
7+
8+bar :: Int -> Int
9+bar = id
10+
11+baz :: Int -> Int
12+baz = id
13+{-# INLINEABLE [~2] baz #-}
data/examples/declaration/signature/inline/noinline-out.hsnew file+11
@@ -0,0 +1,11 @@
1+foo :: Int -> Int
2+foo = id
3+{-# NOINLINE foo #-}
4+
5+{-# NOINLINE [2] bar #-}
6+bar :: Int -> Int
7+bar = id
8+
9+baz :: Int -> Int
10+baz = id
11+{-# NOINLINE [~2] baz #-}
data/examples/declaration/signature/inline/noinline.hsnew file+13
@@ -0,0 +1,13 @@
1+foo :: Int -> Int
2+foo = id
3+{-# NOINLINE foo #-}
4+
5+{-# NOINLINE [2] bar #-}
6+
7+bar :: Int -> Int
8+bar = id
9+
10+baz :: Int -> Int
11+baz = id
12+
13+{-# NOINLINE [~2] baz #-}
data/examples/declaration/signature/minimal/minimal-out.hsnew file+14
@@ -0,0 +1,14 @@
1+class Foo a where
2+ {-# MINIMAL (==) | ((/=), foo) #-}
3+
4+ {-# MINIMAL
5+ a
6+ | ( b, c, d
7+ | e,
8+ f
9+ )
10+ | g
11+ #-}
12+
13+ (==) :: a -> a -> Bool
14+ (/=) :: a -> a -> Bool
data/examples/declaration/signature/minimal/minimal.hsnew file+10
@@ -0,0 +1,10 @@
1+class Foo a where
2+
3+ {-# MINIMAL (==) |( (/=) , foo) #-}
4+
5+ {-# MINIMAL a | (b , c , d | e
6+ , f)
7+ | g #-}
8+
9+ (==) :: a -> a -> Bool
10+ (/=) :: a -> a -> Bool
data/examples/declaration/signature/pattern/multiline-out.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# LANGUAGE PatternSynonyms #-}
2+
3+pattern Arrow ::
4+ Type ->
5+ Type ->
6+ Type
7+
8+pattern
9+ Foo,
10+ Bar ::
11+ Type -> Type -> Type
12+
13+pattern
14+ TypeSignature,
15+ FunctionBody,
16+ PatternSignature,
17+ WarningPragma ::
18+ [RdrName] ->
19+ HsDecl GhcPs
data/examples/declaration/signature/pattern/multiline.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# LANGUAGE PatternSynonyms #-}
2+
3+pattern Arrow :: Type
4+ -> Type -> Type
5+
6+pattern Foo, Bar ::
7+ Type -> Type -> Type
8+
9+pattern TypeSignature
10+ , FunctionBody
11+ , PatternSignature
12+ , WarningPragma :: [RdrName]
13+ -> HsDecl GhcPs
data/examples/declaration/signature/pattern/single-line-out.hsnew file+5
@@ -0,0 +1,5 @@
1+{-# LANGUAGE PatternSynonyms #-}
2+
3+pattern Arrow :: Type -> Type -> Type
4+
5+pattern Foo, Bar :: Type -> Type -> Type
data/examples/declaration/signature/pattern/single-line.hsnew file+5
@@ -0,0 +1,5 @@
1+{-# LANGUAGE PatternSynonyms #-}
2+
3+pattern Arrow :: Type -> Type -> Type
4+
5+pattern Foo, Bar :: Type -> Type -> Type
data/examples/declaration/signature/set-cost-centre/set-cost-centre-out.hsnew file+14
@@ -0,0 +1,14 @@
1+f x y = g (x + y)
2+ where
3+ g z = z
4+ {-# SCC g #-}
5+{-# SCC f #-}
6+
7+withString x y = x + y
8+{-# SCC withString "cost_centre_name" #-}
9+
10+withString' x y = x + y
11+{-# SCC
12+ withString'
13+ "cost_centre_name"
14+ #-}
data/examples/declaration/signature/set-cost-centre/set-cost-centre.hsnew file+16
@@ -0,0 +1,16 @@
1+f x y = g (x + y)
2+ where
3+ g z = z
4+ {-# SCC g #-}
5+
6+{-# SCC f #-}
7+
8+withString x y = x + y
9+
10+{-# SCC withString "cost_centre_name" #-}
11+
12+withString' x y = x + y
13+
14+{-# SCC withString'
15+ "cost_centre_name"
16+ #-}
data/examples/declaration/signature/specialize/specialize-instance-out.hsnew file+14
@@ -0,0 +1,14 @@
1+data Foo a = Foo a
2+
3+data VT v m r = VT v m r
4+
5+instance (Eq a) => Eq (Foo a) where
6+ {-# SPECIALIZE instance Eq (Foo [(Int, Bar)]) #-}
7+ (==) (Foo a) (Foo b) = (==) a b
8+
9+instance (Num r, V.Vector v r, Factored m r) => Num (VT v m r) where
10+ {-# SPECIALIZE instance
11+ ( Factored m Int => Num (VT U.Vector m Int)
12+ )
13+ #-}
14+ VT x + VT y = VT $ V.zipWith (+) x y
data/examples/declaration/signature/specialize/specialize-instance.hsnew file+11
@@ -0,0 +1,11 @@
1+data Foo a = Foo a
2+data VT v m r = VT v m r
3+
4+instance (Eq a) => Eq (Foo a) where
5+ {-# SPECIALIZE instance Eq (Foo [(Int, Bar)]) #-}
6+ (==) (Foo a) (Foo b) = (==) a b
7+
8+instance (Num r, V.Vector v r, Factored m r) => Num (VT v m r) where
9+ {-# SPECIALIZE instance (
10+ Factored m Int => Num (VT U.Vector m Int)) #-}
11+ VT x + VT y = VT $ V.zipWith (+) x y
data/examples/declaration/signature/specialize/specialize-out.hsnew file+24
@@ -0,0 +1,24 @@
1+foo :: Num a => a -> a
2+foo = id
3+{-# SPECIALIZE foo :: Int -> Int #-}
4+{-# SPECIALIZE INLINE foo :: Float -> Float #-}
5+
6+{-# SPECIALIZE NOINLINE [2] bar :: Int -> Int #-}
7+bar :: Num a => a -> a
8+bar = id
9+
10+baz :: Num a => a -> a
11+baz = id
12+{-# SPECIALIZE [~2] baz ::
13+ Int ->
14+ Int
15+ #-}
16+
17+{-# SPECIALIZE fits13Bits :: Int -> Bool, Integer -> Bool #-}
18+{-# SPECIALIZE fits13Bits ::
19+ Int ->
20+ Bool,
21+ Integer -> Bool
22+ #-}
23+fits13Bits :: Integral a => a -> Bool
24+fits13Bits x = x >= -4096 && x < 4096
data/examples/declaration/signature/specialize/specialize.hsnew file+24
@@ -0,0 +1,24 @@
1+foo :: Num a => a -> a
2+foo = id
3+
4+{-# SPECIALIZE foo :: Int -> Int #-}
5+{-# SPECIALIZE INLINE foo :: Float -> Float #-}
6+
7+{-# SPECIALIZE NOINLINE [2] bar :: Int -> Int #-}
8+
9+bar :: Num a => a -> a
10+bar = id
11+
12+baz :: Num a => a -> a
13+baz = id
14+{-# SPECIALIZE [~2] baz
15+ :: Int
16+ -> Int #-}
17+
18+{-# SPECIALIZE fits13Bits :: Int -> Bool, Integer -> Bool #-}
19+{-# SPECIALIZE fits13Bits
20+ :: Int
21+ -> Bool
22+ , Integer -> Bool #-}
23+fits13Bits :: Integral a => a -> Bool
24+fits13Bits x = x >= -4096 && x < 4096
data/examples/declaration/signature/standalone-kind-out.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# LANGUAGE StandaloneKindSignatures #-}
2+
3+type T ::
4+ (k -> Type) ->
5+ k ->
6+ Type
7+data T m a = MkT (m a) (T Maybe (m a))
8+
9+type C1 :: Type -> Constraint
10+class C1 a
11+
12+type F :: Type -> Type
13+type family F
data/examples/declaration/signature/standalone-kind.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# LANGUAGE StandaloneKindSignatures #-}
2+
3+type T :: (k -> Type)
4+ -> k
5+ -> Type
6+
7+data T m a = MkT (m a) (T Maybe (m a))
8+
9+type C1 :: Type -> Constraint
10+class C1 a
11+
12+type F :: Type -> Type
13+type family F
data/examples/declaration/signature/type/arguments-out.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE RankNTypes #-}
2+
3+functionName ::
4+ (C1, C2, C3, C4, C5) =>
5+ a ->
6+ b ->
7+ ( forall a.
8+ (C6, C7) =>
9+ LongDataTypeName ->
10+ a ->
11+ AnotherLongDataTypeName ->
12+ b ->
13+ c
14+ ) ->
15+ (c -> d) ->
16+ (a, b, c, d)
data/examples/declaration/signature/type/arguments.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE RankNTypes #-}
2+
3+functionName
4+ :: (C1, C2, C3, C4, C5)
5+ => a
6+ -> b
7+ -> (forall a.
8+ (C6, C7)
9+ => LongDataTypeName
10+ -> a
11+ -> AnotherLongDataTypeName
12+ -> b
13+ -> c
14+ )
15+ -> (c -> d)
16+ -> (a, b, c, d)
data/examples/declaration/signature/type/context-multi-line-out.hsnew file+10
@@ -0,0 +1,10 @@
1+functionName ::
2+ ( C1,
3+ C2,
4+ C3
5+ ) =>
6+ a ->
7+ b ->
8+ c ->
9+ d ->
10+ (a, b, c, d)
data/examples/declaration/signature/type/context-multi-line.hsnew file+10
@@ -0,0 +1,10 @@
1+functionName
2+ :: ( C1
3+ , C2
4+ , C3
5+ )
6+ => a
7+ -> b
8+ -> c
9+ -> d
10+ -> (a, b, c, d)
data/examples/declaration/signature/type/context-single-line-out.hsnew file+7
@@ -0,0 +1,7 @@
1+functionName ::
2+ (C1, C2, C3) =>
3+ a ->
4+ b ->
5+ c ->
6+ d ->
7+ (a, b, c, d)
data/examples/declaration/signature/type/context-single-line.hsnew file+7
@@ -0,0 +1,7 @@
1+functionName
2+ :: (C1, C2, C3)
3+ => a
4+ -> b
5+ -> c
6+ -> d
7+ -> (a, b, c, d)
data/examples/declaration/signature/type/infix-promoted-type-constructor-out.hsnew file+2
@@ -0,0 +1,2 @@
1+fun1 :: Def ('[Ref s (Stored Uint32), IBool] 'T.:-> IBool)
2+fun2 :: Def ('[Ref s (Stored Uint32), IBool] ':-> IBool)
data/examples/declaration/signature/type/infix-promoted-type-constructor.hsnew file+2
@@ -0,0 +1,2 @@
1+fun1 :: Def ('[ Ref s (Stored Uint32), IBool] 'T.:-> IBool)
2+fun2 :: Def ('[ Ref s (Stored Uint32), IBool] ':-> IBool)
data/examples/declaration/signature/type/long-function-name-out.hsnew file+6
@@ -0,0 +1,6 @@
1+longFunctionName ::
2+ a ->
3+ b ->
4+ c ->
5+ d ->
6+ (a, b, c, d)
data/examples/declaration/signature/type/long-function-name.hsnew file+6
@@ -0,0 +1,6 @@
1+longFunctionName
2+ :: a
3+ -> b
4+ -> c
5+ -> d
6+ -> (a, b, c, d)
data/examples/declaration/signature/type/long-multiline-applications-out.hsnew file+16
@@ -0,0 +1,16 @@
1+functionName ::
2+ (C1, C2, C3, C4, C5) =>
3+ forall a b c.
4+ a ->
5+ b ->
6+ ( LongDataTypeName
7+ AnotherLongDataTypeName
8+ AnotherLongDataTypeName2
9+ AnotherLongDataTypeName3 ->
10+ a ->
11+ AnotherLongDataTypeName4 ->
12+ b ->
13+ c
14+ ) ->
15+ (c -> d) ->
16+ (a, b, c, d)
data/examples/declaration/signature/type/long-multiline-applications.hsnew file+16
@@ -0,0 +1,16 @@
1+functionName
2+ :: (C1, C2, C3, C4, C5)
3+ => forall a b c
4+ . a
5+ -> b
6+ -> ( LongDataTypeName
7+ AnotherLongDataTypeName
8+ AnotherLongDataTypeName2
9+ AnotherLongDataTypeName3
10+ -> a
11+ -> AnotherLongDataTypeName4
12+ -> b
13+ -> c
14+ )
15+ -> (c -> d)
16+ -> (a, b, c, d)
data/examples/declaration/signature/type/multi-value-out.hsnew file+15
@@ -0,0 +1,15 @@
1+foo, bar :: Int
2+foo = 1
3+bar = 2
4+
5+a, b, c :: Int
6+a = 1
7+b = 2
8+c = 3
9+
10+foo,
11+ bar,
12+ baz ::
13+ Int
14+bar = 2
15+baz = 3
data/examples/declaration/signature/type/multi-value.hsnew file+14
@@ -0,0 +1,14 @@
1+foo, bar :: Int
2+foo = 1
3+bar = 2
4+
5+a, b, c :: Int
6+a = 1
7+b = 2
8+c = 3
9+
10+foo,
11+ bar,
12+ baz :: Int
13+bar = 2
14+baz = 3
data/examples/declaration/signature/type/unicode-out.hsnew file+4
@@ -0,0 +1,4 @@
1+{-# LANGUAGE UnicodeSyntax #-}
2+
3+foo :: forall a. Show a => a -> String
4+foo = const ()
data/examples/declaration/signature/type/unicode.hsnew file+4
@@ -0,0 +1,4 @@
1+{-# LANGUAGE UnicodeSyntax #-}
2+
3+foo ∷ ∀a. Show a ⇒ a → String
4+foo = const ()
data/examples/declaration/signature/type/unrelated-out.hsnew file+4
@@ -0,0 +1,4 @@
1+clientFunc1 :: SomeType1
2+clientFunc2 :: SomeType2
3+clientFunc3 :: SomeType3
4+clientFunc1 :<|> clientFunc2 :<|> clientFunc3 = hoistClient foo bar baz
data/examples/declaration/signature/type/unrelated.hsnew file+4
@@ -0,0 +1,4 @@
1+clientFunc1 :: SomeType1
2+clientFunc2 :: SomeType2
3+clientFunc3 :: SomeType3
4+clientFunc1 :<|> clientFunc2 :<|> clientFunc3 = hoistClient foo bar baz
data/examples/declaration/splice/bracket-declaration-out.hsnew file+26
@@ -0,0 +1,26 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+[d|data T a where Foo :: T ()|]
4+
5+foo =
6+ [d|
7+ foo :: Int -> Char
8+
9+ bar = 42
10+ |]
11+
12+[d|
13+ data T = T
14+ deriving (Eq, Ord, Enum, Bounded, Show)
15+ |]
16+
17+$(do [d|baz = baz|])
18+
19+$(singletons [d|data T = T deriving (Eq, Ord, Enum, Bounded, Show)|])
20+
21+$( singletons
22+ [d|
23+ data T = T
24+ deriving (Eq, Ord, Enum, Bounded, Show)
25+ |]
26+ )
data/examples/declaration/splice/bracket-declaration.hsnew file+22
@@ -0,0 +1,22 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+[d| data T a where Foo :: T () |]
4+
5+foo = [d|
6+ foo:: Int -> Char
7+ bar = 42
8+ |]
9+
10+[d|
11+ data T = T
12+ deriving (Eq, Ord, Enum, Bounded, Show)
13+ |]
14+
15+$( do [d| baz = baz |] )
16+
17+$(singletons [d| data T = T deriving (Eq, Ord, Enum, Bounded, Show) |])
18+
19+$(singletons [d|
20+ data T = T
21+ deriving (Eq, Ord, Enum, Bounded, Show)
22+ |])
data/examples/declaration/splice/bracket-out.hsnew file+18
@@ -0,0 +1,18 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+foo =
4+ [|
5+ foo bar
6+ |]
7+
8+foo =
9+ [e|
10+ foo bar
11+ |]
12+
13+foo = [t|Char|]
14+
15+foo =
16+ [||
17+ foo bar
18+ ||]
data/examples/declaration/splice/bracket.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+foo = [| foo bar
4+ |]
5+
6+foo = [e| foo bar
7+ |]
8+
9+foo = [t| Char |]
10+
11+foo = [|| foo bar
12+ ||]
data/examples/declaration/splice/grouped-splices-out.hsnew file+3
@@ -0,0 +1,3 @@
1+$(deriveJSON fieldLabelMod ''A)
2+$(deriveJSON fieldLabelMod ''B)
3+$(deriveJSON fieldLabelMod ''C)
data/examples/declaration/splice/grouped-splices.hsnew file+3
@@ -0,0 +1,3 @@
1+$(deriveJSON fieldLabelMod ''A)
2+$(deriveJSON fieldLabelMod ''B)
3+$(deriveJSON fieldLabelMod ''C)
data/examples/declaration/splice/quasiquote-out.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE QuasiQuotes #-}
2+
3+x = [foo| foo bar |]
4+
5+x =
6+ [e| foo
7+ bar {- -}
8+ |]
9+
10+[d| foo bar
11+
12+|]
data/examples/declaration/splice/quasiquote.hsnew file+11
@@ -0,0 +1,11 @@
1+{-# LANGUAGE QuasiQuotes #-}
2+
3+x = [foo| foo bar |]
4+
5+x = [e| foo
6+ bar {- -}
7+ |]
8+
9+[d| foo bar
10+
11+|]
data/examples/declaration/splice/quotes-out.hsnew file+17
@@ -0,0 +1,17 @@
1+foo = ''R
2+
3+bar = 'foo
4+
5+bar' = 'foo_bar
6+
7+baz = ''(:#)
8+
9+baz' = ''(Foo.Bar.:#)
10+
11+equals = ''(==)
12+
13+unit = ''()
14+
15+list = ''[]
16+
17+quolified = ''Semigroup.Option
data/examples/declaration/splice/quotes.hsnew file+17
@@ -0,0 +1,17 @@
1+foo = ''R
2+
3+bar = 'foo
4+
5+bar' = 'foo_bar
6+
7+baz = ''(:#)
8+
9+baz' = ''(Foo.Bar.:#)
10+
11+equals = ''(==)
12+
13+unit = ''()
14+
15+list = ''[]
16+
17+quolified = ''Semigroup.Option
data/examples/declaration/splice/splice-decl-out.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+$(foo bar)
4+
5+$foo
6+
7+$$(foo bar)
8+
9+$$foo
10+
11+foo bar
12+
13+[|booya|]
14+
15+-- TemplateHaskell allows Q () at the top level
16+do
17+ pure []
data/examples/declaration/splice/splice-decl.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+$( foo bar)
4+
5+$foo
6+
7+$$( foo bar)
8+
9+$$foo
10+
11+foo bar
12+
13+[|booya|]
14+
15+-- TemplateHaskell allows Q () at the top level
16+do
17+ pure []
data/examples/declaration/splice/typed-splice-out.hsnew file+7
@@ -0,0 +1,7 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+x =
4+ $$( foo bar
5+ )
6+
7+x = $$foo
data/examples/declaration/splice/typed-splice.hsnew file+6
@@ -0,0 +1,6 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+x = $$( foo bar
4+ )
5+
6+x = $$foo
data/examples/declaration/splice/untyped-splice-out.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+x = $(foo bar)
4+
5+x =
6+ $( foo
7+ bar
8+ )
9+
10+x = $foo
data/examples/declaration/splice/untyped-splice.hsnew file+8
@@ -0,0 +1,8 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+x = $( foo bar )
3+
4+x = $(
5+ foo
6+ bar )
7+
8+x = $foo
data/examples/declaration/type-families/closed-type-family/infix-out.hsnew file+11
@@ -0,0 +1,11 @@
1+type family (x :: N) + (y :: N) :: N where
2+ 'Zero + y = y
3+ 'Succ n + y = 'Succ (n + y)
4+
5+type family (x :: N) `LEQ` (y :: N) :: Bool where
6+ 'Zero `LEQ` y = 'True
7+ 'Succ n `LEQ` 'Zero = 'False
8+ 'Succ n `LEQ` 'Succ m = n `LEQ` m
9+
10+type family ((x :: N) `Weird` (y :: N)) (z :: N) :: Bool where
11+ 'Zero `Weird` 'Zero 'Zero = 'True
data/examples/declaration/type-families/closed-type-family/infix.hsnew file+11
@@ -0,0 +1,11 @@
1+type family (x :: N) + (y :: N) :: N where
2+ 'Zero + y = y
3+ 'Succ n + y = 'Succ (n + y)
4+
5+type family (x :: N) `LEQ` (y :: N) :: Bool where
6+ 'Zero `LEQ` y = 'True
7+ 'Succ n `LEQ` 'Zero = 'False
8+ 'Succ n `LEQ` 'Succ m = n `LEQ` m
9+
10+type family ((x :: N) `Weird` (y :: N)) (z :: N) :: Bool where
11+ 'Zero `Weird` 'Zero 'Zero = 'True
data/examples/declaration/type-families/closed-type-family/multi-line-out.hs+21−12
@@ -1,16 +1,25 @@
1−type family Id a
1+type family
2+ Id a =
2− = result | result -> a where
3+ result | result -> a
4+ where
3− Id a
5+ Id a =
4− = a
6+ a
5
7
6−type family G (a :: k) b c
8+type family
9+ G
10+ (a :: k)
11+ b
12+ c =
7− = foo | foo -> k b where
13+ foo | foo -> k b
14+ where
8− G a b c
15+ G a b c =
9− = (a, b)
16+ (a, b)
10
17
11−type family F a
18+type family
19+ F a ::
20+ * -> *
12− :: * -> * where
21+ where
13 F Int = Double
22 F Int = Double
14− F Bool
23+ F Bool =
15− = Char
24+ Char
16 F a = String
25 F a = String
data/examples/declaration/type-families/closed-type-family/simple-out.hs+2
@@ -1,3 +1,5 @@
1+module Main where
2+
1-- | Documentation.
3-- | Documentation.
2type family F a :: * -> * where
4type family F a :: * -> * where
3 F Int = Double
5 F Int = Double
data/examples/declaration/type-families/closed-type-family/simple.hs+2
@@ -1,3 +1,5 @@
1+module Main where
2+
1-- | Documentation.
3-- | Documentation.
2
4
3type family F a :: * -> * where
5type family F a :: * -> * where
data/examples/declaration/type-families/closed-type-family/with-equal-sign-out.hsnew file+2
@@ -0,0 +1,2 @@
1+type family TF a b = result where
2+ TF a b = Int
data/examples/declaration/type-families/closed-type-family/with-equal-sign.hsnew file+2
@@ -0,0 +1,2 @@
1+type family TF a b = result where
2+ TF a b = Int
data/examples/declaration/type-families/closed-type-family/with-forall-out.hsnew file+3
@@ -0,0 +1,3 @@
1+type family G a b where
2+ forall x y. G [x] (Proxy y) = Double
3+ forall z. z `G` z = Bool
data/examples/declaration/type-families/closed-type-family/with-forall.hsnew file+3
@@ -0,0 +1,3 @@
1+type family G a b where
2+ forall x y. G [x] (Proxy y) = Double
3+ forall z. z `G` z = Bool
data/examples/declaration/type-families/data-family/no-annotation-out.hs+2
@@ -1,2 +1,4 @@
1+module Main where
2+
1-- | Documentation.
3-- | Documentation.
2data family Array e
4data family Array e
data/examples/declaration/type-families/data-family/no-annotation.hs+2
@@ -1,3 +1,5 @@
1+module Main where
2+
1-- | Documentation.
3-- | Documentation.
2
4
3data family Array e
5data family Array e
data/examples/declaration/type-families/data-family/simple-out.hs+2
@@ -1,2 +1,4 @@
1+module Main where
2+
1-- | Documentation.
3-- | Documentation.
2data family GMap k :: Type -> Type
4data family GMap k :: Type -> Type
data/examples/declaration/type-families/data-family/simple.hs+2
@@ -1,3 +1,5 @@
1+module Main where
2+
1-- | Documentation.
3-- | Documentation.
2
4
3data family GMap k :: Type -> Type
5data family GMap k :: Type -> Type
data/examples/declaration/type-families/type-family/no-annotation-out.hs+2
@@ -1,2 +1,4 @@
1+module Main where
2+
1-- | Documentation.
3-- | Documentation.
2type family F a b :: Type -> Type
4type family F a b :: Type -> Type
data/examples/declaration/type-families/type-family/no-annotation.hs+2
@@ -1,3 +1,5 @@
1+module Main where
2+
1-- | Documentation.
3-- | Documentation.
2
4
3type family F a b :: Type -> Type
5type family F a b :: Type -> Type
data/examples/declaration/type-families/type-family/operator-out.hsnew file+3
@@ -0,0 +1,3 @@
1+type family a ! b
2+
3+type family a . b
data/examples/declaration/type-families/type-family/operator.hsnew file+2
@@ -0,0 +1,2 @@
1+type family a ! b
2+type family a . b
data/examples/declaration/type-families/type-family/simple-out.hs+2
@@ -1,2 +1,4 @@
1+module Main where
2+
1-- | Documentation.
3-- | Documentation.
2type family Elem c :: Type
4type family Elem c :: Type
data/examples/declaration/type-families/type-family/simple.hs+2
@@ -1,3 +1,5 @@
1+module Main where
2+
1-- | Documentation.
3-- | Documentation.
2
4
3type family Elem c :: Type
5type family Elem c :: Type
data/examples/declaration/type-synonyms/multi-line-out.hs+16−5
@@ -1,7 +1,18 @@
1−type Foo a b c
1+type Foo a b c =
2− = Bar c a b
2+ Bar c a b
3
3
4type Foo
4type Foo
5+ a
6+ b
7+ c =
8+ Bar c a b
9+
10+type Foo =
5− = Bar
11+ Bar
6− Baz
12+ Baz
7− Quux
13+ Quux
14+
15+type API =
16+ "route1" :> ApiRoute1
17+ :<|> "route2" :> ApiRoute2 -- comment here
18+ :<|> OmitDocs :> "i" :> ASomething API
data/examples/declaration/type-synonyms/multi-line.hs+10
@@ -1,7 +1,17 @@
1type Foo a b c
1type Foo a b c
2 = Bar c a b
2 = Bar c a b
3
3
4+type Foo
5+ a
6+ b c
7+ = Bar c a b
8+
4type Foo =
9type Foo =
5 Bar
10 Bar
6 Baz
11 Baz
7 Quux
12 Quux
13+
14+type API
15+ = "route1" :> ApiRoute1
16+ :<|> "route2" :> ApiRoute2 -- comment here
17+ :<|> OmitDocs :> "i" :> ASomething API
data/examples/declaration/type-synonyms/simple-out.hs+6
@@ -1,2 +1,8 @@
1+module Main where
2+
1-- | Documentation.
3-- | Documentation.
2type Foo a b c = Bar c a b
4type Foo a b c = Bar c a b
5+
6+type a ~> b = TyFun a b -> Type
7+
8+type (a :+: b) c d e = ()
data/examples/declaration/type-synonyms/simple.hs+6
@@ -1,3 +1,9 @@
1+module Main where
2+
1-- | Documentation.
3-- | Documentation.
2
4
3type Foo a b c = Bar c a b
5type Foo a b c = Bar c a b
6+
7+type a ~> b = TyFun a b -> Type
8+
9+type (a :+: b) c d e = ()
data/examples/declaration/type-synonyms/with-weird-haddock-out.hsnew file+3
@@ -0,0 +1,3 @@
1+type Elims =
2+ -- | eliminations ordered left-to-right.
3+ [Elim]
data/examples/declaration/type-synonyms/with-weird-haddock.hsnew file+1
@@ -0,0 +1 @@
1+type Elims = [Elim] -- ^ eliminations ordered left-to-right.
data/examples/declaration/type/forall-out.hsnew file+4
@@ -0,0 +1,4 @@
1+type CoerceLocalSig m m' =
2+ forall r a.
3+ LocalSig m r a ->
4+ LocalSig m' r a
data/examples/declaration/type/forall.hsnew file+4
@@ -0,0 +1,4 @@
1+type CoerceLocalSig m m' =
2+ forall r a.
3+ LocalSig m r a ->
4+ LocalSig m' r a
data/examples/declaration/type/lits-out.hsnew file+6
@@ -0,0 +1,6 @@
1+type A = "foo"
2+
3+type B =
4+ "foo\
5+ \bar" ->
6+ ()
data/examples/declaration/type/lits.hsnew file+4
@@ -0,0 +1,4 @@
1+type A = "foo"
2+
3+type B = "foo\
4+ \bar" -> ()
data/examples/declaration/type/misc-kind-signatures-out.hsnew file+5
@@ -0,0 +1,5 @@
1+instance DemoteNodeTypes ('[] :: [NodeType]) where
2+ demoteNodeTypes _ = []
3+
4+b :: (Bool :: *)
5+b = True
data/examples/declaration/type/misc-kind-signatures.hsnew file+5
@@ -0,0 +1,5 @@
1+instance DemoteNodeTypes ('[] :: [NodeType]) where
2+ demoteNodeTypes _ = []
3+
4+b :: (Bool :: *)
5+b = True
data/examples/declaration/type/promotion-out.hsnew file+19
@@ -0,0 +1,19 @@
1+type Foo = Cluster '[ 'NodeCore, 'NodeRelay', 'NodeEdge]
2+
3+data T = T' | T'T
4+
5+type S0 = ' T'
6+
7+type S1 = ' T'T
8+
9+type S2 = Proxy ('[ '[], '[]])
10+
11+type S4 = Proxy ('( 'Just, ' T'T))
12+
13+type S5 = Proxy ('[ 'Just, 'TT'T])
14+
15+type S6 = Proxy ('( '(), '()))
16+
17+type S7 = Proxy ('( 'a, 'b))
18+
19+type S8 = Proxy ('[Int, Bool])
data/examples/declaration/type/promotion.hsnew file+15
@@ -0,0 +1,15 @@
1+type Foo = Cluster '[ 'NodeCore, 'NodeRelay', 'NodeEdge ]
2+
3+data T = T' | T'T
4+
5+type S0 = ' T'
6+
7+type S1 = ' T'T
8+
9+type S2 = Proxy ( '[ '[], '[] ])
10+type S4 = Proxy ( '( 'Just, ' T'T))
11+type S5 = Proxy ( '[ 'Just, ' TT'T])
12+type S6 = Proxy ( '( '(), '() ))
13+type S7 = Proxy ( '( 'a, 'b ))
14+type S8 = Proxy ( '[ Int, Bool ])
15+
data/examples/declaration/type/splice-out.hsnew file+3
@@ -0,0 +1,3 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+type Foo = $(bar [t|Int|])
data/examples/declaration/type/splice.hsnew file+3
@@ -0,0 +1,3 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+type Foo = $( bar [t|Int|] )
data/examples/declaration/type/type-applications-out.hsnew file+3
@@ -0,0 +1,3 @@
1+{-# LANGUAGE TypeApplications #-}
2+
3+type P = K @Bool @(Bool :: *) 'True 'False
data/examples/declaration/type/type-applications.hsnew file+3
@@ -0,0 +1,3 @@
1+{-# LANGUAGE TypeApplications #-}
2+
3+type P = K @Bool @(Bool :: *) 'True 'False
data/examples/declaration/type/visible-forall-out.hsnew file+2
@@ -0,0 +1,2 @@
1+-- source: https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0081-forall-arrow.rst
2+data T :: forall k -> k -> Type
data/examples/declaration/type/visible-forall.hsnew file+2
@@ -0,0 +1,2 @@
1+-- source: https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0081-forall-arrow.rst
2+data T :: forall k -> k -> Type
data/examples/declaration/value/function/application-0-out.hsnew file+17
@@ -0,0 +1,17 @@
1+foo =
2+ f1
3+ p1
4+ p2
5+ p3
6+
7+foo' =
8+ f2
9+ p1
10+ p2
11+ p3
12+
13+foo'' =
14+ f3
15+ p1
16+ p2
17+ p3
data/examples/declaration/value/function/application-0.hsnew file+12
@@ -0,0 +1,12 @@
1+foo =
2+ f1
3+ p1
4+ p2 p3
5+
6+foo' = f2 p1
7+ p2
8+ p3
9+
10+foo'' =
11+ f3 p1 p2
12+ p3
data/examples/declaration/value/function/application-1-out.hsnew file+19
@@ -0,0 +1,19 @@
1+main =
2+ do
3+ x
4+ y
5+ z
6+
7+main =
8+ case foo of
9+ x -> a
10+ foo
11+ a
12+ b
13+
14+main =
15+ do
16+ if x then y else z
17+ foo
18+ a
19+ b
data/examples/declaration/value/function/application-1.hsnew file+14
@@ -0,0 +1,14 @@
1+main =
2+ do
3+ x
4+ y
5+ z
6+
7+main =
8+ case foo of
9+ x -> a
10+ foo a b
11+
12+main = do
13+ if x then y else z
14+ foo a b
data/examples/declaration/value/function/arg-breakpoints-out.hsnew file+3
@@ -0,0 +1,3 @@
1+foo
2+ bar =
3+ body
data/examples/declaration/value/function/arg-breakpoints.hsnew file+3
@@ -0,0 +1,3 @@
1+foo
2+ bar =
3+ body
data/examples/declaration/value/function/arithmetic-sequences-out.hsnew file+24
@@ -0,0 +1,24 @@
1+foo = [0 ..]
2+
3+foo' = [0 .. 5]
4+
5+bar x =
6+ [ 0
7+ .. x
8+ ]
9+
10+baz x =
11+ [ 1,
12+ 3
13+ .. x
14+ ]
15+
16+barbaz x = [0, 1 ..]
17+
18+arst = [0 :: Int ..]
19+
20+brst = [0, 1 :: Int ..]
21+
22+crst = [0 :: Int .. 10]
23+
24+drst = [0, 1 :: Int .. 10]
data/examples/declaration/value/function/arithmetic-sequences.hsnew file+15
@@ -0,0 +1,15 @@
1+foo = [0..]
2+foo' = [0..5]
3+bar x = [
4+ 0..x
5+ ]
6+baz x = [
7+ 1,
8+ 3 ..
9+ x
10+ ]
11+barbaz x = [ 0, 1.. ]
12+arst = [0 :: Int ..]
13+brst = [0, 1 :: Int ..]
14+crst = [0 :: Int .. 10]
15+drst = [0, 1 :: Int .. 10]
data/examples/declaration/value/function/arrow/multiline-case-out.hsnew file+8
@@ -0,0 +1,8 @@
1+{-# LANGUAGE Arrows #-}
2+
3+f = proc x -> do
4+ x <-
5+ case x of X -> x
6+ -<
7+ y
8+ a -< b
data/examples/declaration/value/function/arrow/multiline-case.hsnew file+7
@@ -0,0 +1,7 @@
1+{-# LANGUAGE Arrows #-}
2+
3+f = proc x -> do
4+ x
5+ <- case x of X -> x
6+ -< y
7+ a -< b
data/examples/declaration/value/function/arrow/proc-applications-out.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo x = proc a -> a -< x
4+
5+bar f x =
6+ proc
7+ ( y,
8+ z,
9+ w
10+ )
11+ ->
12+ f -- The value
13+ -<
14+ ( x, -- Foo
15+ w, -- Bar
16+ z -- Baz
17+ )
18+
19+baz x = proc a -> a -<< x
data/examples/declaration/value/function/arrow/proc-applications.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo x = proc a -> a -< x
4+
5+bar f x =
6+ proc (
7+ y,
8+ z,
9+ w
10+ ) -> f -- The value
11+ -< (
12+ x, -- Foo
13+ w, -- Bar
14+ z -- Baz
15+ )
16+
17+baz x = proc a -> a -<< x
data/examples/declaration/value/function/arrow/proc-cases-out.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo f = proc a -> case a of Left b -> f -< b
4+
5+bar f g h j =
6+ proc a -> case a of
7+ Left
8+ ( (a, b),
9+ (c, d)
10+ ) -> f (a <> c) -< b <> d
11+ Right
12+ (Left a) ->
13+ h -< a
14+ Right
15+ (Right b) ->
16+ j -< b
data/examples/declaration/value/function/arrow/proc-cases.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE Arrows #-}
2+foo f =proc a -> case a of Left b -> f -<b
3+
4+bar f g h j
5+ = proc a ->
6+ case a of
7+ Left (
8+ (a, b),
9+ (c, d)
10+ ) -> f (a <> c) -< b <> d
11+
12+ Right
13+ (Left a) ->
14+ h -< a
15+ Right
16+ (Right b) ->
17+ j -< b
data/examples/declaration/value/function/arrow/proc-do-complex-out.hsnew file+62
@@ -0,0 +1,62 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo
4+ f
5+ g
6+ h
7+ ma =
8+ proc
9+ ( (a, b),
10+ (c, d),
11+ (e, f)
12+ )
13+ -> do
14+ -- Begin do
15+ (x, y) <- -- GHC parser fails if layed out over multiple lines
16+ f -- Call into f
17+ ( a,
18+ c -- Tuple together arguments
19+ )
20+ ( b,
21+ d
22+ )
23+ -<
24+ ( b + 1, -- Funnel into arrow
25+ d * b
26+ )
27+ if x `mod` y == 0 -- Basic condition
28+ then case e of -- Only left case is relevant
29+ Left
30+ ( z,
31+ w
32+ ) -> \u -> -- Procs can have lambdas
33+ let v =
34+ u -- Actually never used
35+ ^ 2
36+ in ( returnA
37+ -<
38+ -- Just do the calculation
39+ (x + y * z)
40+ )
41+ else do
42+ let u = x -- Let bindings bind expressions, not commands
43+ -- Could pattern match directly on x
44+ i <- case u of
45+ 0 -> (g . h -< u)
46+ n ->
47+ ( ( h . g
48+ -<
49+ y -- First actual use of y
50+ )
51+ )
52+ returnA -< ()
53+ -- Sometimes execute effects
54+ if i > 0
55+ then ma -< ()
56+ else returnA -< ()
57+ returnA
58+ -<
59+ ( i
60+ + x
61+ * y -- Just do the calculation
62+ )
data/examples/declaration/value/function/arrow/proc-do-complex.hsnew file+49
@@ -0,0 +1,49 @@
1+{-# LANGUAGE Arrows #-}
2+foo
3+ f
4+ g
5+ h
6+ ma = proc (
7+ (a, b),
8+ (c, d),
9+ (e, f)
10+ ) ->
11+ do -- Begin do
12+ (x,y) -- GHC parser fails if layed out over multiple lines
13+ <- f -- Call into f
14+ (a,
15+ c) -- Tuple together arguments
16+ (b,
17+ d)
18+ -< (b + 1, -- Funnel into arrow
19+ d * b)
20+ if
21+ x `mod` y == 0 -- Basic condition
22+ then case e -- Only left case is relevant
23+ of Left (z,
24+ w) -> \u -> -- Procs can have lambdas
25+ let
26+ v
27+ = u -- Actually never used
28+ ^ 2
29+ in
30+ (returnA
31+ -< -- Just do the calculation
32+ (x + y * z))
33+ else do
34+ let u = x -- Let bindings bind expressions, not commands
35+ -- Could pattern match directly on x
36+ i <- case u of
37+ 0 -> (g . h -< u)
38+ n -> (
39+ (h . g
40+ -< y) -- First actual use of y
41+ )
42+ returnA -< ()
43+ -- Sometimes execute effects
44+ if i > 0
45+ then ma -< ()
46+ else returnA -< ()
47+ returnA -< (i +
48+ x *
49+ y) -- Just do the calculation
data/examples/declaration/value/function/arrow/proc-do-simple1-out.hsnew file+18
@@ -0,0 +1,18 @@
1+{-# LANGUAGE Arrows #-}
2+
3+bar f = proc a -> do
4+ b <- f -< a
5+
6+barbar f g = proc a -> do
7+ b <- f -< a
8+ returnA -< b
9+
10+barbaz f g = proc (a, b) -> do
11+ c <- f -< a
12+ d <- g -< b
13+
14+bazbar f = proc a -> do
15+ a <-
16+ f
17+ -<
18+ a
data/examples/declaration/value/function/arrow/proc-do-simple1.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE Arrows #-}
2+
3+bar f = proc a ->
4+ do b <- f -< a
5+
6+barbar f g = proc a ->
7+ do b <- f -< a
8+ returnA -< b
9+
10+barbaz f g = proc (a, b) ->
11+ do c <- f -< a
12+ d <- g -< b
13+
14+bazbar f = proc a ->
15+ do a
16+ <-
17+ f
18+ -<
19+ a
20+
data/examples/declaration/value/function/arrow/proc-do-simple2-out.hsnew file+22
@@ -0,0 +1,22 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo f = proc a -> do
4+ f -< a
5+
6+bazbaz f g h = proc (a, b, c) -> do
7+ x <-
8+ f b -< a
9+ y <-
10+ g b -< b
11+ z <-
12+ h
13+ x
14+ y
15+ -<
16+ ( a,
17+ b,
18+ c
19+ )
20+ returnA
21+ -<
22+ (x, y, z)
data/examples/declaration/value/function/arrow/proc-do-simple2.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE Arrows #-}
2+foo f = proc a ->
3+ do f -< a
4+
5+bazbaz f g h = proc (a, b, c) ->
6+ do x
7+ <- f b -< a
8+ y <-
9+ g b -< b
10+ z <-
11+ h
12+ x
13+ y
14+ -< (
15+ a,
16+ b,
17+ c
18+ )
19+ returnA -<
20+ (x, y, z)
data/examples/declaration/value/function/arrow/proc-forms1-out.hsnew file+21
@@ -0,0 +1,21 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo0 f g x y = proc _ -> (| f (g -< (x, y)) |)
4+
5+foo1 f g h x =
6+ proc (y, z) ->
7+ (|
8+ test
9+ ( h f
10+ . h g
11+ -<
12+ y x
13+ . y z
14+ )
15+ ( h g
16+ . h f
17+ -<
18+ y z
19+ . y x
20+ )
21+ |)
data/examples/declaration/value/function/arrow/proc-forms1.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo0 f g x y = proc _ -> (| f (g -< (x, y)) |)
4+
5+foo1 f g h x =
6+ proc (y, z) -> (|
7+ test ( h f
8+ . h g
9+ -<
10+ y x
11+ . y z
12+ )
13+ ( h g
14+ . h f
15+ -<
16+ y z
17+ . y x)
18+ |)
19+
data/examples/declaration/value/function/arrow/proc-forms2-out.hsnew file+22
@@ -0,0 +1,22 @@
1+{-# LANGUAGE Arrows #-}
2+
3+bar0 f g h x =
4+ proc (y, z) ->
5+ (| test (h f . (h g) -< (y x) . y z) ((h g) . h f -< y z . (y x)) |)
6+
7+bar1 f g x y = proc _ -> (f -< x) &&& (g -< y)
8+
9+bar2 f g h x =
10+ proc (y, z) ->
11+ (h f . (h g) -< (y x) . y z) ||| ((h g) . h f -< y z . (y x))
12+
13+bar3 f g h x =
14+ proc (y, z) ->
15+ ( (h f . h g)
16+ -<
17+ (y x) . y z
18+ ) |||
19+ ( (h g . h f)
20+ -<
21+ y z . (y x)
22+ )
data/examples/declaration/value/function/arrow/proc-forms2.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# LANGUAGE Arrows #-}
2+
3+bar0 f g h x =
4+ proc (y, z) ->
5+ (| test (h f.(h g) -< (y x).y z)((h g) . h f-<y z . (y x)) |)
6+
7+bar1 f g x y = proc _ -> (f -< x)&&&(g -< y)
8+
9+bar2 f g h x =
10+ proc (y, z) ->
11+ (h f.(h g) -< (y x).y z) ||| ((h g) . h f-<y z . (y x))
12+
13+bar3 f g h x =
14+ proc (y, z) ->
15+ ((h f.h g)
16+ -< (y x).y z)
17+ |||
18+ ((h g . h f)
19+ -<y z . (y x))
data/examples/declaration/value/function/arrow/proc-ifs-out.hsnew file+15
@@ -0,0 +1,15 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo f = proc a -> if a then f -< 0 else f -< 1
4+
5+bar f g = proc a ->
6+ if f a
7+ then
8+ f
9+ . g
10+ -<
11+ a
12+ else
13+ g
14+ -<
15+ b
data/examples/declaration/value/function/arrow/proc-ifs.hsnew file+14
@@ -0,0 +1,14 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo f = proc a -> if a then f-<0 else f-<1
4+
5+bar f g = proc a ->
6+ if
7+ f a
8+ then
9+ f
10+ . g -< a
11+ else
12+ g
13+ -<
14+ b
data/examples/declaration/value/function/arrow/proc-lambdas-out.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo = proc a -> \f b -> a -< f b -- Foo
4+
5+bar =
6+ proc x -> \f g h ->
7+ \() ->
8+ \(Left (x, y)) -> -- Tuple value
9+ f (g (h x)) -< y
data/examples/declaration/value/function/arrow/proc-lambdas.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo = proc a-> \f b->a-<f b -- Foo
4+
5+bar =
6+ proc x ->
7+ \f g h ->
8+ \() ->
9+ \( Left (x,y )) -> -- Tuple value
10+ f (g (h x)) -< y
data/examples/declaration/value/function/arrow/proc-lets-out.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo f = proc a -> let b = a in f -< b
4+
5+bar f g = proc a ->
6+ let h =
7+ f
8+ . g a
9+ j =
10+ g
11+ . h
12+ in id -< (h, j)
data/examples/declaration/value/function/arrow/proc-lets.hsnew file+14
@@ -0,0 +1,14 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo f = proc a -> let b = a in f -< b
4+
5+bar f g = proc a ->
6+ let
7+ h
8+ = f
9+ . g a
10+ j = g
11+ .
12+ h
13+ in
14+ id -< (h, j)
data/examples/declaration/value/function/arrow/proc-parentheses-out.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo f = proc a -> (f -< a)
4+
5+bar f g = proc a ->
6+ ( ( (f)
7+ ( g
8+ )
9+ )
10+ -<
11+ ( ( ( ( ( ( g
12+ a
13+ )
14+ )
15+ )
16+ )
17+ )
18+ )
19+ )
data/examples/declaration/value/function/arrow/proc-parentheses.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE Arrows #-}
2+foo f = proc a -> ( f -< a )
3+
4+bar f g = proc a ->
5+ ( ((f) (
6+ g
7+ ))
8+ -< (((((
9+ (g
10+ a)
11+ )))))
12+ )
data/examples/declaration/value/function/arrow/recursive-procs-out.hsnew file+23
@@ -0,0 +1,23 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo f g = proc (x, y) -> do
4+ rec a <- f y -< x
5+ b <-
6+ g x
7+ -<
8+ y
9+ bar
10+ -<
11+ ( a,
12+ b
13+ )
14+ rec p <-
15+ f
16+ p
17+ -<
18+ a
19+ rec q <-
20+ g
21+ q
22+ -<
23+ b
data/examples/declaration/value/function/arrow/recursive-procs.hsnew file+18
@@ -0,0 +1,18 @@
1+{-# LANGUAGE Arrows #-}
2+
3+foo f g = proc (x, y) -> do
4+ rec
5+ a <- f y -< x
6+ b
7+ <-
8+ g x
9+ -<
10+ y
11+ bar -< (
12+ a,
13+ b
14+ )
15+ rec p <- f
16+ p -< a
17+ rec q <- g
18+ q-< b
data/examples/declaration/value/function/awkward-comment-0-out.hsnew file+6
@@ -0,0 +1,6 @@
1+mergeErrorReply :: ParseError -> Reply s u a -> Reply s u a
2+mergeErrorReply err1 reply -- XXX where to put it?
3+ =
4+ case reply of
5+ Ok x state err2 -> Ok x state (mergeError err1 err2)
6+ Error err2 -> Error (mergeError err1 err2)
data/examples/declaration/value/function/awkward-comment-0.hsnew file+5
@@ -0,0 +1,5 @@
1+mergeErrorReply :: ParseError -> Reply s u a -> Reply s u a
2+mergeErrorReply err1 reply -- XXX where to put it?
3+ = case reply of
4+ Ok x state err2 -> Ok x state (mergeError err1 err2)
5+ Error err2 -> Error (mergeError err1 err2)
data/examples/declaration/value/function/awkward-comment-1-out.hsnew file+9
@@ -0,0 +1,9 @@
1+doForeign :: Vars -> [Name] -> [Term] -> Idris LExp
2+doForeign x = x
3+ where
4+ splitArg tm | (_, [_, _, l, r]) <- unApply tm -- pair, two implicits
5+ =
6+ do
7+ let l' = toFDesc l
8+ r' <- irTerm (sMN 0 "__foreignCall") vs env r
9+ return (l', r')
data/examples/declaration/value/function/awkward-comment-1.hsnew file+7
@@ -0,0 +1,7 @@
1+doForeign :: Vars -> [Name] -> [Term] -> Idris LExp
2+doForeign x = x
3+ where
4+ splitArg tm | (_, [_,_,l,r]) <- unApply tm -- pair, two implicits
5+ = do let l' = toFDesc l
6+ r' <- irTerm (sMN 0 "__foreignCall") vs env r
7+ return (l', r')
data/examples/declaration/value/function/backticks-lhs-out.hsnew file+7
@@ -0,0 +1,7 @@
1+x `op1` (Just 0) = True
2+op1 x (Just _) = False
3+op1 x Nothing = undefined
4+
5+op2 1 y = False
6+x `op2` y =
7+ True
data/examples/declaration/value/function/backticks-lhs.hsnew file+7
@@ -0,0 +1,7 @@
1+x `op1` (Just 0) = True
2+op1 x (Just _) = False
3+op1 x Nothing = undefined
4+
5+op2 1 y = False
6+x `op2` y =
7+ True
data/examples/declaration/value/function/backticks-out.hsnew file+1
@@ -0,0 +1 @@
1+foo x y = x `bar` y
data/examples/declaration/value/function/backticks.hsnew file+1
@@ -0,0 +1 @@
1+foo x y = x `bar` y
data/examples/declaration/value/function/blank-lines-let-out.hsnew file+6
@@ -0,0 +1,6 @@
1+foo =
2+ let x = 10
3+
4+ y = 11
5+ z = 12
6+ in x + y + z
data/examples/declaration/value/function/blank-lines-let.hsnew file+9
@@ -0,0 +1,9 @@
1+foo =
2+ let
3+
4+ x = 10
5+
6+ y = 11
7+ z = 12
8+
9+ in x + y + z
data/examples/declaration/value/function/blank-lines-where-out.hsnew file+6
@@ -0,0 +1,6 @@
1+foo = x + y + z
2+ where
3+ x = 10
4+
5+ y = 11
6+ z = 12
data/examples/declaration/value/function/blank-lines-where.hsnew file+7
@@ -0,0 +1,7 @@
1+foo = x + y + z
2+ where
3+
4+ x = 10
5+
6+ y = 11
7+ z = 12
data/examples/declaration/value/function/block-arguments-out.hsnew file+34
@@ -0,0 +1,34 @@
1+f1 = foo do bar
2+
3+f2 = foo do
4+ bar
5+
6+f3 = foo case True of
7+ True -> bar
8+ False -> baz
9+
10+f4 = foo let a = 3 in b
11+
12+f5 =
13+ foo
14+ let a = 3
15+ b = a
16+ in b
17+
18+f6 =
19+ foo
20+ if bar
21+ then baz
22+ else not baz
23+
24+f7 = foo \x -> y
25+
26+f8 = foo \x ->
27+ y
28+
29+f9 = foo do { bar } baz
30+
31+f10 = foo
32+ do a
33+ do b
34+ do c
data/examples/declaration/value/function/block-arguments.hsnew file+30
@@ -0,0 +1,30 @@
1+f1 = foo do bar
2+
3+f2 = foo do
4+ bar
5+
6+f3 = foo case True of
7+ True -> bar
8+ False -> baz
9+
10+f4 = foo let a = 3 in b
11+
12+f5 = foo let a = 3
13+ b = a
14+ in b
15+
16+f6 = foo if bar
17+ then baz
18+ else not baz
19+
20+f7 = foo \x -> y
21+
22+f8 = foo \x ->
23+ y
24+
25+f9 = foo do { bar } baz
26+
27+f10 = foo
28+ do { a }
29+ do { b }
30+ do c
data/examples/declaration/value/function/builtin-syntax-out.hsnew file+1
@@ -0,0 +1 @@
1+x = return ()
data/examples/declaration/value/function/builtin-syntax.hsnew file+1
@@ -0,0 +1 @@
1+x = return ()
data/examples/declaration/value/function/case-multi-line-guards-out.hsnew file+16
@@ -0,0 +1,16 @@
1+withGuards :: Int -> Int
2+withGuards x =
3+ case x of
4+ x
5+ | x > 10 ->
6+ foo
7+ + bar
8+ x | x > 5 -> 10
9+ _ -> 20
10+
11+case x of
12+ '-' | not isUrl -> case xs of
13+ _ -> emitc '-'
14+ '*' | not isUrl ->
15+ case xs of
16+ _ -> emitc '*'
data/examples/declaration/value/function/case-multi-line-guards.hsnew file+15
@@ -0,0 +1,15 @@
1+withGuards :: Int -> Int
2+withGuards x =
3+ case x of
4+ x | x > 10 ->
5+ foo +
6+ bar
7+ x | x > 5 -> 10
8+ _ -> 20
9+
10+case x of
11+ '-' | not isUrl -> case xs of
12+ _ -> emitc '-'
13+ '*' | not isUrl ->
14+ case xs of
15+ _ -> emitc '*'
data/examples/declaration/value/function/case-multi-line-out.hsnew file+27
@@ -0,0 +1,27 @@
1+foo :: Int -> Int
2+foo x = case x of
3+ 5 -> 10
4+ _ -> 12
5+
6+bar :: Int -> Int
7+bar x =
8+ case x of
9+ 5 ->
10+ if x > 5
11+ then 10
12+ else 12
13+ _ -> 12
14+
15+baz :: Int -> Int
16+baz x = case x of
17+ 5 -> 10
18+ _ -> 12
19+
20+quux :: Int -> Int
21+quux x = case x of
22+ x -> x
23+
24+funnyComment =
25+ -- comment
26+ case () of
27+ () -> ()
data/examples/declaration/value/function/case-multi-line.hsnew file+23
@@ -0,0 +1,23 @@
1+foo :: Int -> Int
2+foo x = case x of
3+ 5 -> 10
4+ _ -> 12
5+
6+bar :: Int -> Int
7+bar x =
8+ case x of
9+ 5 -> if x > 5
10+ then 10 else 12
11+ _ -> 12
12+
13+baz :: Int -> Int
14+baz x = case x of 5 -> 10
15+ _ -> 12
16+
17+quux :: Int -> Int
18+quux x = case x of
19+ x -> x
20+
21+funnyComment = -- comment
22+ case () of
23+ () -> ()
data/examples/declaration/value/function/case-single-line-out.hsnew file+6
@@ -0,0 +1,6 @@
1+foo :: Int -> Int
2+foo x = case x of x -> x
3+
4+foo :: IO ()
5+foo = case [1] of [_] -> "singleton"; _ -> "not singleton"
6+foo = case [1] of { [] -> foo; _ -> bar } `finally` baz
data/examples/declaration/value/function/case-single-line.hsnew file+6
@@ -0,0 +1,6 @@
1+foo :: Int -> Int
2+foo x = case x of x -> x
3+
4+foo :: IO ()
5+foo = case [1] of [_] -> "singleton"; _ -> "not singleton"
6+foo = case [1] of { [] -> foo; _ -> bar } `finally` baz
data/examples/declaration/value/function/complex-list-out.hsnew file+15
@@ -0,0 +1,15 @@
1+handleStuff =
2+ handle
3+ [ \ExceptionA ->
4+ something,
5+ \ExceptionB ->
6+ somethingElse
7+ ]
8+
9+handleStuff =
10+ handle
11+ [ foo
12+ bar,
13+ baz
14+ qux
15+ ]
data/examples/declaration/value/function/complex-list.hsnew file+15
@@ -0,0 +1,15 @@
1+handleStuff =
2+ handle
3+ [ \ExceptionA ->
4+ something
5+ , \ExceptionB ->
6+ somethingElse
7+ ]
8+
9+handleStuff =
10+ handle
11+ [ foo
12+ bar
13+ , baz
14+ qux
15+ ]
data/examples/declaration/value/function/comprehension/transform-multi-line1-out.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE TransformListComp #-}
2+
3+foo' xs ys =
4+ [ ( x,
5+ y
6+ )
7+ | x <- xs,
8+ y <- ys,
9+ then
10+ -- First comment
11+ reverse -- Second comment
12+ ]
data/examples/declaration/value/function/comprehension/transform-multi-line1.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE TransformListComp #-}
2+
3+foo' xs ys = [
4+ (x,
5+ y) |
6+ x <- xs,
7+ y <- ys,
8+ then -- First comment
9+ reverse -- Second comment
10+ ]
data/examples/declaration/value/function/comprehension/transform-multi-line2-out.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE TransformListComp #-}
2+
3+bar' xs ys =
4+ [ ( x,
5+ y
6+ )
7+ | x <- xs,
8+ y <- ys,
9+ then
10+ -- First comment
11+ sortWith
12+ by
13+ ( x
14+ + y -- Second comment
15+ )
16+ ]
data/examples/declaration/value/function/comprehension/transform-multi-line2.hsnew file+15
@@ -0,0 +1,15 @@
1+{-# LANGUAGE TransformListComp #-}
2+
3+bar' xs ys = [
4+ (x,
5+ y) |
6+ x <- xs,
7+ y <- ys,
8+ then -- First comment
9+ sortWith
10+ by
11+ (x
12+ + y) -- Second comment
13+ ]
14+
15+
data/examples/declaration/value/function/comprehension/transform-multi-line3-out.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE TransformListComp #-}
2+
3+baz' xs ys =
4+ [ ( x,
5+ y
6+ )
7+ | x <- xs,
8+ y <- ys,
9+ then group using
10+ -- First comment
11+ permutations -- Second comment
12+ ]
data/examples/declaration/value/function/comprehension/transform-multi-line3.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE TransformListComp #-}
2+
3+baz' xs ys = [
4+ (x,
5+ y) |
6+ x <- xs,
7+ y <- ys,
8+ then
9+ group
10+ using -- First comment
11+ permutations -- Second comment
12+ ]
data/examples/declaration/value/function/comprehension/transform-multi-line4-out.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE TransformListComp #-}
2+
3+quux' xs ys =
4+ [ ( x,
5+ y
6+ )
7+ | x <- xs,
8+ y <- ys,
9+ then group by
10+ -- First comment
11+ ( x
12+ + y
13+ )
14+ using
15+ -- Second comment
16+ groupWith -- Third comment
17+ ]
data/examples/declaration/value/function/comprehension/transform-multi-line4.hsnew file+15
@@ -0,0 +1,15 @@
1+{-# LANGUAGE TransformListComp #-}
2+
3+quux' xs ys = [
4+ (x,
5+ y) |
6+ x <- xs,
7+ y <- ys,
8+ then
9+ group
10+ by -- First comment
11+ (x
12+ + y)
13+ using -- Second comment
14+ groupWith -- Third comment
15+ ]
data/examples/declaration/value/function/comprehension/transform-single-line-out.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# LANGUAGE TransformListComp #-}
2+
3+foo xs ys = [(x, y) | x <- xs, y <- ys, then reverse]
4+
5+bar xs ys = [(x, y) | x <- xs, y <- ys, then sortWith by (x + y)]
6+
7+baz xs ys = [(x, y) | x <- xs, y <- ys, then group using permutations]
8+
9+quux xs ys = [(x, y) | x <- xs, y <- ys, then group by (x + y) using groupWith]
data/examples/declaration/value/function/comprehension/transform-single-line.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# LANGUAGE TransformListComp #-}
2+
3+foo xs ys = [(x, y) | x <- xs, y <- ys, then reverse]
4+
5+bar xs ys = [(x, y) | x <- xs, y <- ys, then sortWith by (x + y)]
6+
7+baz xs ys = [(x, y) | x <- xs, y <- ys, then group using permutations]
8+
9+quux xs ys = [(x, y) | x <- xs, y <- ys, then group by (x + y) using groupWith]
data/examples/declaration/value/function/do-single-multi-out.hsnew file+4
@@ -0,0 +1,4 @@
1+foo = do
2+ ( bar
3+ baz
4+ )
data/examples/declaration/value/function/do-single-multi.hsnew file+2
@@ -0,0 +1,2 @@
1+foo = do (bar
2+ baz)
data/examples/declaration/value/function/do-where-out.hsnew file+5
@@ -0,0 +1,5 @@
1+f :: Maybe Int
2+f = do
3+ return c
4+ where
5+ c = 0
data/examples/declaration/value/function/do-where.hsnew file+5
@@ -0,0 +1,5 @@
1+f :: Maybe Int
2+f = do
3+ return c
4+ where
5+ c = 0
data/examples/declaration/value/function/do/applications-and-parens-out.hsnew file+9
@@ -0,0 +1,9 @@
1+warningFor var place = do
2+ guard $ isVariableName var
3+ guard . not $ isInArray var place || isGuarded place
4+ ( if includeGlobals || isLocal var
5+ then warningForLocals
6+ else warningForGlobals
7+ )
8+ var
9+ place
data/examples/declaration/value/function/do/applications-and-parens.hsnew file+6
@@ -0,0 +1,6 @@
1+warningFor var place = do
2+ guard $ isVariableName var
3+ guard . not $ isInArray var place || isGuarded place
4+ (if includeGlobals || isLocal var
5+ then warningForLocals
6+ else warningForGlobals) var place
data/examples/declaration/value/function/do/blocks-out.hsnew file+19
@@ -0,0 +1,19 @@
1+foo = do bar
2+
3+foo = do bar; baz
4+
5+foo = do
6+ bar
7+ baz
8+
9+foo = do do { foo; bar }; baz
10+
11+readInClause = do
12+ do
13+ lookAhead g_Do
14+ parseNote ErrorC 1063 "You need a line feed or semicolon before the 'do'."
15+ <|> do
16+ optional g_Semi
17+ void allspacing
18+
19+ return things
data/examples/declaration/value/function/do/blocks.hsnew file+17
@@ -0,0 +1,17 @@
1+foo = do bar
2+foo = do { bar; baz }
3+foo = do { bar
4+ ; baz
5+ }
6+foo = do { do {foo; bar}; baz }
7+
8+readInClause = do
9+ do {
10+ lookAhead g_Do;
11+ parseNote ErrorC 1063 "You need a line feed or semicolon before the 'do'.";
12+ } <|> do {
13+ optional g_Semi;
14+ void allspacing;
15+ }
16+
17+ return things
data/examples/declaration/value/function/do/comment-alignment-out.hsnew file+9
@@ -0,0 +1,9 @@
1+main = do
2+ case blah of
3+ Nothing -> return ()
4+ Just xs -> do
5+ forM_ xs foo
6+ bar
7+ -- and here it goes
8+ unless bobla $
9+ quux
data/examples/declaration/value/function/do/comment-alignment.hsnew file+9
@@ -0,0 +1,9 @@
1+main = do
2+ case blah of
3+ Nothing -> return ()
4+ Just xs -> do
5+ forM_ xs foo
6+ bar
7+ -- and here it goes
8+ unless bobla $
9+ quux
data/examples/declaration/value/function/do/comment-spacing-out.hsnew file+7
@@ -0,0 +1,7 @@
1+foo = do
2+ bar
3+ -- foo
4+ baz
5+
6+ -- foo
7+ quux
data/examples/declaration/value/function/do/comment-spacing.hsnew file+7
@@ -0,0 +1,7 @@
1+foo = do
2+ bar
3+ -- foo
4+ baz
5+
6+ -- foo
7+ quux
data/examples/declaration/value/function/do/expr-out.hsnew file+10
@@ -0,0 +1,10 @@
1+quux = something $ do
2+ foo
3+ case x of
4+ 1 -> 10
5+ 2 -> 20
6+ bar
7+ if something
8+ then x
9+ else y
10+ baz
data/examples/declaration/value/function/do/expr.hsnew file+10
@@ -0,0 +1,10 @@
1+quux = something $ do
2+ foo
3+ case x of
4+ 1 -> 10
5+ 2 -> 20
6+ bar
7+ if something
8+ then x
9+ else y
10+ baz
data/examples/declaration/value/function/do/hang-rhs-arrow-out.hsnew file+9
@@ -0,0 +1,9 @@
1+foo = do
2+ something <- case bar of
3+ Foo -> return 1
4+ Bar -> return 2
5+ somethingElse <-
6+ case boom of
7+ Foo -> return 1
8+ Bar -> return 2
9+ quux something somethingElse
data/examples/declaration/value/function/do/hang-rhs-arrow.hsnew file+9
@@ -0,0 +1,9 @@
1+foo = do
2+ something <- case bar of
3+ Foo -> return 1
4+ Bar -> return 2
5+ somethingElse <-
6+ case boom of
7+ Foo -> return 1
8+ Bar -> return 2
9+ quux something somethingElse
data/examples/declaration/value/function/do/let-out.hsnew file+18
@@ -0,0 +1,18 @@
1+main = do
2+ a <- bar
3+ let a = b; c = d
4+ baz d
5+ let e = f
6+ g = h
7+ return c
8+
9+-- single line let-where
10+samples n f = do
11+ gen <- newQCGen
12+ let rands g = g1 : rands g2 where (g1, g2) = split g
13+ return $ rands gen
14+
15+trickyLet = do
16+ foo
17+ let x = 5
18+ in bar x
data/examples/declaration/value/function/do/let.hsnew file+18
@@ -0,0 +1,18 @@
1+main = do
2+ a <- bar
3+ let a = b; c = d
4+ baz d
5+ let e = f
6+ g = h
7+ return c
8+
9+-- single line let-where
10+samples n f = do
11+ gen <- newQCGen
12+ let rands g = g1 : rands g2 where (g1, g2) = split g
13+ return $ rands gen
14+
15+trickyLet = do
16+ foo
17+ let x = 5
18+ in bar x
data/examples/declaration/value/function/do/operator-and-parens-out.hsnew file+7
@@ -0,0 +1,7 @@
1+scientifically :: (Scientific -> a) -> Parser a
2+scientifically h = do
3+ something
4+ ( I.satisfy (\w -> w == 'e' || w == 'E')
5+ *> fmap (h . Sci.scientific signedCoeff . (e +)) (signed decimal)
6+ )
7+ <|> return (h $ Sci.scientific signedCoeff e)
data/examples/declaration/value/function/do/operator-and-parens.hsnew file+7
@@ -0,0 +1,7 @@
1+scientifically :: (Scientific -> a) -> Parser a
2+scientifically h = do
3+ something
4+ ( I.satisfy (\w -> w == 'e' || w == 'E')
5+ *> fmap (h . Sci.scientific signedCoeff . (e +)) (signed decimal)
6+ )
7+ <|> return (h $ Sci.scientific signedCoeff e)
data/examples/declaration/value/function/do/recursive-do-mdo-out.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE RecursiveDo #-}
2+
3+baz =
4+ mdo
5+ bar a
6+ a <- foo
7+ b <-
8+ bar
9+ 1
10+ 2
11+ 3
12+ return (a + b)
data/examples/declaration/value/function/do/recursive-do-mdo.hsnew file+8
@@ -0,0 +1,8 @@
1+{-# LANGUAGE RecursiveDo #-}
2+
3+baz =
4+ mdo bar a
5+ a <- foo
6+ b <- bar
7+ 1 2 3
8+ return (a + b)
data/examples/declaration/value/function/do/recursive-do-rec-out.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# LANGUAGE RecursiveDo #-}
2+
3+foo = do
4+ rec a <- b + 5
5+
6+ let d = c
7+
8+ b <- a * 5
9+
10+ something
11+
12+ c <- a + b
13+ print c
14+ rec something $ do
15+ x <- a
16+ print x
17+
18+ y <- c
19+ print y
data/examples/declaration/value/function/do/recursive-do-rec.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE RecursiveDo #-}
2+
3+foo = do
4+ rec
5+ a <- b + 5
6+
7+ let d = c
8+
9+ b <- a * 5
10+
11+ something
12+
13+ c <- a + b
14+ print c
15+ rec something $ do
16+ x <- a
17+ print x
18+
19+ y <- c
20+ print y
data/examples/declaration/value/function/equality-constraints-out.hsnew file+2
@@ -0,0 +1,2 @@
1+foo :: (a ~ b) => a -> b -> Int
2+foo = undefined
data/examples/declaration/value/function/equality-constraints.hsnew file+2
@@ -0,0 +1,2 @@
1+foo :: (a ~ b) => a -> b -> Int
2+foo = undefined
data/examples/declaration/value/function/explicit-type-out.hsnew file+5
@@ -0,0 +1,5 @@
1+foo = 5 :: Int
2+
3+bar =
4+ 5 ::
5+ Int
data/examples/declaration/value/function/explicit-type.hsnew file+4
@@ -0,0 +1,4 @@
1+foo = 5 :: Int
2+
3+bar = 5
4+ :: Int
data/examples/declaration/value/function/fancy-forall-0-out.hsnew file+10
@@ -0,0 +1,10 @@
1+wrapError ::
2+ forall outertag innertag t outer inner m a.
3+ ( forall x. Coercible (t m x) (m x),
4+ forall m'.
5+ HasCatch outertag outer m' =>
6+ HasCatch innertag inner (t m'),
7+ HasCatch outertag outer m
8+ ) =>
9+ (forall m'. HasCatch innertag inner m' => m' a) ->
10+ m a
data/examples/declaration/value/function/fancy-forall-0.hsnew file+6
@@ -0,0 +1,6 @@
1+wrapError :: forall outertag innertag t outer inner m a.
2+ ( forall x. Coercible (t m x) (m x)
3+ , forall m'. HasCatch outertag outer m'
4+ => HasCatch innertag inner (t m')
5+ , HasCatch outertag outer m )
6+ => (forall m'. HasCatch innertag inner m' => m' a) -> m a
data/examples/declaration/value/function/fancy-forall-1-out.hsnew file+10
@@ -0,0 +1,10 @@
1+magnify ::
2+ forall outertag innertag t outer inner m a.
3+ ( forall x. Coercible (t m x) (m x),
4+ forall m'.
5+ HasReader outertag outer m' =>
6+ HasReader innertag inner (t m'),
7+ HasReader outertag outer m
8+ ) =>
9+ (forall m'. HasReader innertag inner m' => m' a) ->
10+ m a
data/examples/declaration/value/function/fancy-forall-1.hsnew file+6
@@ -0,0 +1,6 @@
1+magnify :: forall outertag innertag t outer inner m a.
2+ ( forall x. Coercible (t m x) (m x)
3+ , forall m'. HasReader outertag outer m'
4+ => HasReader innertag inner (t m')
5+ , HasReader outertag outer m )
6+ => (forall m'. HasReader innertag inner m' => m' a) -> m a
data/examples/declaration/value/function/guards-out.hsnew file+12
@@ -0,0 +1,12 @@
1+baz :: Int -> Int
2+baz x | x < 0 = x
3+baz x | otherwise = x
4+
5+multi_baz :: Int -> Int
6+multi_baz x | x < 42 = x
7+multi_baz x | x < 0 = x
8+multi_baz x | otherwise = x
9+
10+quux :: Int -> Int
11+quux x | x < 0 = x
12+quux x = x
data/examples/declaration/value/function/guards.hsnew file+12
@@ -0,0 +1,12 @@
1+baz :: Int -> Int
2+baz x | x < 0 = x
3+baz x | otherwise = x
4+
5+multi_baz :: Int -> Int
6+multi_baz x | x < 42 = x
7+multi_baz x | x < 0 = x
8+multi_baz x | otherwise = x
9+
10+quux :: Int -> Int
11+quux x | x < 0 = x
12+quux x = x
data/examples/declaration/value/function/if-multi-line-out.hsnew file+23
@@ -0,0 +1,23 @@
1+foo :: Int -> Int
2+foo x =
3+ if x > 5
4+ then 10
5+ else 12
6+
7+bar :: Int -> Int
8+bar x =
9+ if x > 5
10+ then
11+ foo x
12+ + 100
13+ else case x of
14+ 1 -> 10
15+ _ -> 20
16+
17+baz :: Int -> Bar
18+baz x =
19+ if x > 5
20+ then \case
21+ Foo -> bar
22+ else do
23+ undefined
data/examples/declaration/value/function/if-multi-line.hsnew file+22
@@ -0,0 +1,22 @@
1+foo :: Int -> Int
2+foo x = if x > 5 then 10
3+ else 12
4+
5+bar :: Int -> Int
6+bar x =
7+ if x > 5
8+ then foo x
9+ + 100
10+ else case x of
11+ 1 -> 10
12+ _ -> 20
13+
14+baz :: Int -> Bar
15+baz x =
16+ if x > 5
17+ then
18+ \case
19+ Foo -> bar
20+ else
21+ do
22+ undefined
data/examples/declaration/value/function/if-single-line-out.hsnew file+6
@@ -0,0 +1,6 @@
1+foo :: Int -> Int
2+foo x = if x > 5 then 10 else 12
3+
4+bar :: Int -> Int
5+bar x =
6+ if x > 5 then 10 else 12
data/examples/declaration/value/function/if-single-line.hsnew file+6
@@ -0,0 +1,6 @@
1+foo :: Int -> Int
2+foo x = if x > 5 then 10 else 12
3+
4+bar :: Int -> Int
5+bar x =
6+ if x > 5 then 10 else 12
data/examples/declaration/value/function/if-with-comment-out.hsnew file+8
@@ -0,0 +1,8 @@
1+foo =
2+ if undefined
3+ then -- then comment
4+ undefined
5+ else -- else comment
6+
7+ do
8+ undefined
data/examples/declaration/value/function/if-with-comment.hsnew file+8
@@ -0,0 +1,8 @@
1+foo =
2+ if undefined
3+ -- then comment
4+ then undefined
5+ -- else comment
6+ else
7+ do
8+ undefined
data/examples/declaration/value/function/implicit-params-out.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE ImplicitParams #-}
2+
3+sortBy :: (a -> a -> Bool) -> [a] -> [a]
4+sortBy = undefined
5+
6+sort :: (?cmp :: a -> a -> Bool) => [a] -> [a]
7+sort = sortBy ?cmp
8+
9+sort' ::
10+ ( ?cmp ::
11+ a -> a -> Bool,
12+ ?foo :: Int
13+ ) =>
14+ [a] ->
15+ [a]
16+sort' = sort
data/examples/declaration/value/function/implicit-params.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE ImplicitParams #-}
2+sortBy :: (a -> a -> Bool) -> [a] -> [a]
3+
4+sortBy = undefined
5+
6+sort :: (?cmp :: a -> a -> Bool) => [a] -> [a]
7+sort = sortBy ?cmp
8+
9+sort' :: (?cmp
10+ :: a -> a -> Bool
11+ ,?foo :: Int) => [a] -> [a]
12+sort' = sort
data/examples/declaration/value/function/infix/applicative-out.hsnew file+4
@@ -0,0 +1,4 @@
1+f =
2+ Foo <$> bar
3+ <*> baz
4+ <*> baz'
data/examples/declaration/value/function/infix/applicative.hsnew file+4
@@ -0,0 +1,4 @@
1+f =
2+ Foo <$> bar
3+ <*> baz
4+ <*> baz'
data/examples/declaration/value/function/infix/comments-out.hsnew file+8
@@ -0,0 +1,8 @@
1+main =
2+ bar $ -- bar
3+ baz -- baz
4+
5+bar $
6+ {- foo
7+ -}
8+ bar
data/examples/declaration/value/function/infix/comments.hsnew file+8
@@ -0,0 +1,8 @@
1+main =
2+ bar $ -- bar
3+ baz -- baz
4+
5+bar $
6+ {- foo
7+ -}
8+ bar
data/examples/declaration/value/function/infix/do-out.hsnew file+13
@@ -0,0 +1,13 @@
1+main =
2+ do stuff
3+ `finally` do
4+ recover
5+
6+main = do stuff `finally` recover
7+
8+main = do { stuff } `finally` recover
9+
10+foo =
11+ do
12+ 1
13+ + 2
data/examples/declaration/value/function/infix/do.hsnew file+13
@@ -0,0 +1,13 @@
1+main =
2+ do stuff
3+ `finally` do
4+ recover
5+
6+main = do stuff `finally` recover
7+
8+main = do { stuff } `finally` recover
9+
10+foo = do
11+ 1
12+ +
13+ 2
data/examples/declaration/value/function/infix/dollar-chains-out.hsnew file+22
@@ -0,0 +1,22 @@
1+module Main where
2+
3+foo =
4+ fmap escapeLeadingDollar
5+ . dropPaddingSpace
6+ . dropWhileEnd T.null
7+ . fmap (T.stripEnd . T.pack)
8+ . lines
9+ $ unpackHDS docStr
10+
11+foo =
12+ when (GHC.xopt Cpp dynFlags && not cfgTolerateCpp) $
13+ throwIO (OrmoluCppEnabled path)
14+
15+foo =
16+ bar $
17+ baz $
18+ quux
19+
20+x =
21+ case l of { A -> B } $
22+ case q of r -> s
data/examples/declaration/value/function/infix/dollar-chains.hsnew file+22
@@ -0,0 +1,22 @@
1+module Main where
2+
3+foo =
4+ fmap escapeLeadingDollar
5+ . dropPaddingSpace
6+ . dropWhileEnd T.null
7+ . fmap (T.stripEnd . T.pack)
8+ . lines
9+ $ unpackHDS docStr
10+
11+foo =
12+ when (GHC.xopt Cpp dynFlags && not cfgTolerateCpp) $
13+ throwIO (OrmoluCppEnabled path)
14+
15+foo =
16+ bar
17+ $ baz
18+ $ quux
19+
20+x =
21+ case l of { A -> B } $
22+ case q of r -> s
data/examples/declaration/value/function/infix/hanging-out.hsnew file+23
@@ -0,0 +1,23 @@
1+f = unFoo . foo bar baz 3 $ do
2+ act
3+ ret
4+
5+g = unFoo
6+ . foo
7+ bar
8+ baz
9+ 3
10+ $ do
11+ act
12+ ret
13+
14+update =
15+ do
16+ foobar
17+ `catch` \case
18+ a -> a
19+
20+foo =
21+ bar
22+ ++ case foo of
23+ a -> a
data/examples/declaration/value/function/infix/hanging.hsnew file+19
@@ -0,0 +1,19 @@
1+f = unFoo . foo bar baz 3 $ do
2+ act
3+ ret
4+
5+g = unFoo . foo
6+ bar
7+ baz 3 $ do
8+ act
9+ ret
10+
11+update =
12+ do
13+ foobar
14+ `catch` \case
15+ a -> a
16+
17+foo = bar ++
18+ case foo of
19+ a -> a
data/examples/declaration/value/function/infix/lenses-out.hsnew file+21
@@ -0,0 +1,21 @@
1+lenses =
2+ Just $
3+ M.fromList $
4+ "type" .= ("user.connection" :: Text)
5+ # "connection" .= uc
6+ # "user" .= case name of
7+ Just n -> Just $ object ["name" .= n]
8+ Nothing -> Nothing
9+ # []
10+
11+foo =
12+ a
13+ & b .~ 2
14+ & c .~ 3
15+
16+wreq =
17+ let opts =
18+ defaults & auth ?~ awsAuth AWSv4 "key" "secret"
19+ & header "Accept" .~ ["application/json"]
20+ & header "Runscope-Bucket-Auth" .~ ["1example-1111-4yyyy-zzzz-xxxxxxxx"]
21+ in getWith opts
data/examples/declaration/value/function/infix/lenses.hsnew file+16
@@ -0,0 +1,16 @@
1+lenses = Just $ M.fromList
2+ $ "type" .= ("user.connection" :: Text)
3+ # "connection" .= uc
4+ # "user" .= case name of
5+ Just n -> Just $ object ["name" .= n]
6+ Nothing -> Nothing
7+ # []
8+
9+foo = a
10+ & b .~ 2 & c .~ 3
11+
12+wreq =
13+ let opts = defaults & auth ?~ awsAuth AWSv4 "key" "secret"
14+ & header "Accept" .~ ["application/json"]
15+ & header "Runscope-Bucket-Auth" .~ ["1example-1111-4yyyy-zzzz-xxxxxxxx"]
16+ in getWith opts
data/examples/declaration/value/function/infix/simple-out.hsnew file+12
@@ -0,0 +1,12 @@
1+(*) :: Int -> Int -> Int
2+x * y = z
3+
4+foo :: Int -> Int -> Int
5+x `foo` y = z
6+
7+bar :: Int -> Int -> Int -> Int
8+(x `bar` y) z = z
9+
10+multiline :: Int -> Int -> Int
11+x
12+ `multiline` y = z
data/examples/declaration/value/function/infix/simple.hsnew file+12
@@ -0,0 +1,12 @@
1+(*) :: Int -> Int -> Int
2+x * y = z
3+
4+foo :: Int -> Int -> Int
5+x `foo` y = z
6+
7+bar :: Int -> Int -> Int -> Int
8+(x `bar` y) z = z
9+
10+multiline :: Int -> Int -> Int
11+x `multiline`
12+ y = z
data/examples/declaration/value/function/infix/unicode-out.hsnew file+3
@@ -0,0 +1,3 @@
1+main = print ('a' → 'a')
2+ where
3+ (→) = (,)
data/examples/declaration/value/function/infix/unicode.hsnew file+3
@@ -0,0 +1,3 @@
1+main = print ('a' → 'a')
2+ where
3+ (→) = (,)
data/examples/declaration/value/function/lambda-case-out.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# LANGUAGE LambdaCase #-}
2+
3+foo = bar (\case JKey {} -> True; _ -> False)
4+
5+foo :: Int -> Int
6+foo = \case
7+ 5 -> 10
8+ i | i > 5 -> 11
9+ _ -> 12
data/examples/declaration/value/function/lambda-case.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# LANGUAGE LambdaCase #-}
2+
3+foo = bar (\case JKey{} -> True; _ -> False)
4+
5+foo :: Int -> Int
6+foo = \case
7+ 5 -> 10
8+ i | i > 5 -> 11
9+ _ -> 12
data/examples/declaration/value/function/lambda-multi-line1-out.hsnew file+15
@@ -0,0 +1,15 @@
1+foo :: a -> a -> a
2+foo x = \y ->
3+ x
4+
5+bar :: Int -> Int -> Int
6+bar x = \y ->
7+ if x > y
8+ then 10
9+ else 12
10+
11+foo =
12+ prop "is inverse to closure" $
13+ \(f :: StaticPtr (Int -> Int))
14+ (x :: Int) ->
15+ (unclosure . closure) f x == deRefStaticPtr f x
data/examples/declaration/value/function/lambda-multi-line1.hsnew file+14
@@ -0,0 +1,14 @@
1+foo :: a -> a -> a
2+foo x = \y ->
3+ x
4+
5+bar :: Int -> Int -> Int
6+bar x = \y ->
7+ if x > y
8+ then 10
9+ else 12
10+
11+foo =
12+ prop "is inverse to closure" $ \(f :: StaticPtr (Int -> Int))
13+ (x :: Int) ->
14+ (unclosure . closure) f x == deRefStaticPtr f x
data/examples/declaration/value/function/lambda-multi-line2-out.hsnew file+12
@@ -0,0 +1,12 @@
1+tricky0 =
2+ flip all (zip ws gs) $ \(wt, gt) ->
3+ canUnify poly_given_ok wt gt || go False wt gt
4+
5+tricky1 =
6+ flip all (zip ws gs) $
7+ \(wt, gt) -> canUnify poly_given_ok wt gt || go False wt gt
8+
9+tricky2 =
10+ flip all (zip ws gs) $
11+ \(wt, gt) ->
12+ canUnify poly_given_ok wt gt || go False wt gt
data/examples/declaration/value/function/lambda-multi-line2.hsnew file+12
@@ -0,0 +1,12 @@
1+tricky0 =
2+ flip all (zip ws gs) $ \(wt, gt) ->
3+ canUnify poly_given_ok wt gt || go False wt gt
4+
5+tricky1 =
6+ flip all (zip ws gs) $
7+ \(wt, gt) -> canUnify poly_given_ok wt gt || go False wt gt
8+
9+tricky2 =
10+ flip all (zip ws gs) $
11+ \(wt, gt) ->
12+ canUnify poly_given_ok wt gt || go False wt gt
data/examples/declaration/value/function/lambda-single-line-out.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE BangPatterns #-}
2+
3+foo :: a -> a -> a
4+foo x = \y -> x
5+
6+bar :: a -> a -> a
7+bar x =
8+ \y -> x
9+
10+baz :: a -> a -> a
11+baz = \ ~x ~y -> x
12+
13+zag :: a -> a -> a
14+zag = \ !x !y -> x
15+
16+spl :: a -> a
17+spl = \ $([p|x|]) -> x
data/examples/declaration/value/function/lambda-single-line.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE BangPatterns #-}
2+
3+foo :: a -> a -> a
4+foo x = \y -> x
5+
6+bar :: a -> a -> a
7+bar x =
8+ \y -> x
9+
10+baz :: a -> a -> a
11+baz = \ ~x ~y -> x
12+
13+zag :: a -> a -> a
14+zag = \ !x !y -> x
15+
16+spl :: a -> a
17+spl = \ $([p|x|]) -> x
data/examples/declaration/value/function/let-multi-line-out.hsnew file+28
@@ -0,0 +1,28 @@
1+foo :: Int -> Int
2+foo x =
3+ let z = y
4+ y = x
5+ in z + 100
6+
7+bar :: Int -> Int
8+bar x =
9+ let z = y
10+ y = x
11+ in z
12+ + 100
13+
14+inlineComment :: Int -> Int
15+inlineComment =
16+ let {- join -} go = case () of
17+ () -> undefined
18+ in go
19+
20+implicitParams :: HasCallStack => Int
21+implicitParams =
22+ let ?cs = ?callstack
23+ in foo cs
24+
25+sitting =
26+ foo $
27+ let x = 20
28+ in x
data/examples/declaration/value/function/let-multi-line.hsnew file+27
@@ -0,0 +1,27 @@
1+foo :: Int -> Int
2+foo x =
3+ let z = y
4+ y = x
5+ in z + 100
6+
7+bar :: Int -> Int
8+bar x =
9+ let z = y
10+ y = x
11+ in z
12+ + 100
13+
14+inlineComment :: Int -> Int
15+inlineComment =
16+ let {- join -} go = case () of
17+ () -> undefined
18+ in go
19+
20+implicitParams :: HasCallStack => Int
21+implicitParams =
22+ let ?cs = ?callstack
23+ in foo cs
24+
25+sitting =
26+ foo $ let x = 20
27+ in x
data/examples/declaration/value/function/let-nested-out.hsnew file+3
@@ -0,0 +1,3 @@
1+_ = _
2+ where
3+ _ = [_ | let _ = _]
data/examples/declaration/value/function/let-nested.hsnew file+3
@@ -0,0 +1,3 @@
1+_ = _
2+ where
3+ _ = [_ | let _ = _]
data/examples/declaration/value/function/let-single-line-out.hsnew file+10
@@ -0,0 +1,10 @@
1+foo :: a -> a
2+foo x = let x = x in x
3+foo x = let x = z where z = 2 in x
4+foo x = let x = z where { z = 2 }; a = 3 in x
5+foo x = let g :: Int -> Int; g = id in ()
6+
7+let a = b; c = do { foo; bar }; d = baz in b
8+let a = case True of { True -> foo; False -> bar }; b = foo a in b
9+
10+foo x = let ?g = id; ?f = g in x
data/examples/declaration/value/function/let-single-line.hsnew file+8
@@ -0,0 +1,8 @@
1+foo :: a -> a
2+foo x = let x = x in x
3+foo x = let x = z where z = 2 in x
4+foo x = let x = z where { z = 2; }; a = 3 in x
5+foo x = let {g :: Int -> Int; g = id} in ()
6+let a = b; c = do { foo; bar }; d = baz in b
7+let a = case True of { True -> foo; False -> bar }; b = foo a in b
8+foo x = let {?g = id; ?f = g} in x
data/examples/declaration/value/function/list-comprehensions-out.hsnew file+24
@@ -0,0 +1,24 @@
1+foo x = [a | a <- x]
2+
3+bar x y = [(a, b) | a <- x, even a, b <- y, a != b]
4+
5+barbaz x y z w =
6+ [ (a, b, c, d) -- Foo
7+ | a <-
8+ x, -- Bar
9+ b <- y, -- Baz
10+ any even [a, b],
11+ c <-
12+ z
13+ * z ^ 2, -- Bar baz
14+ d <-
15+ w
16+ + w, -- Baz bar
17+ all
18+ even
19+ [ a,
20+ b,
21+ c,
22+ d
23+ ]
24+ ]
data/examples/declaration/value/function/list-comprehensions.hsnew file+22
@@ -0,0 +1,22 @@
1+foo x = [a |a<-x]
2+
3+bar x y = [ (a, b) | a<-x, even a , b<-y, a != b ]
4+
5+barbaz x y z w = [
6+ (a, b, c, d) | -- Foo
7+ a <-
8+ x, -- Bar
9+ b<-y, -- Baz
10+ any even [a, b],
11+ c <- z *
12+ z ^ 2, -- Bar baz
13+ d <-
14+ w
15+ +
16+ w, -- Baz bar
17+ all
18+ even [
19+ a, b,
20+ c, d
21+ ]
22+ ]
data/examples/declaration/value/function/list-notation-0-out.hsnew file+5
@@ -0,0 +1,5 @@
1+foo =
2+ testCase "Foo" testFoo :
3+ testCase "Bar" testBar :
4+ testCase "Baz" testBaz :
5+ []
data/examples/declaration/value/function/list-notation-0.hsnew file+5
@@ -0,0 +1,5 @@
1+foo =
2+ testCase "Foo" testFoo :
3+ testCase "Bar" testBar :
4+ testCase "Baz" testBaz :
5+ []
data/examples/declaration/value/function/list-notation-1-out.hsnew file+8
@@ -0,0 +1,8 @@
1+instance A.ToJSON UpdateTable where
2+ toJSON a =
3+ A.object $
4+ "TableName" .= updateTableName a :
5+ "ProvisionedThroughput" .= updateProvisionedThroughput a :
6+ case updateGlobalSecondaryIndexUpdates a of
7+ [] -> []
8+ l -> ["GlobalSecondaryIndexUpdates" .= l]
data/examples/declaration/value/function/list-notation-1.hsnew file+7
@@ -0,0 +1,7 @@
1+instance A.ToJSON UpdateTable where
2+ toJSON a = A.object
3+ $ "TableName" .= updateTableName a
4+ : "ProvisionedThroughput" .= updateProvisionedThroughput a
5+ : case updateGlobalSecondaryIndexUpdates a of
6+ [] -> []
7+ l -> [ "GlobalSecondaryIndexUpdates" .= l ]
data/examples/declaration/value/function/list-notation-2-out.hsnew file+6
@@ -0,0 +1,6 @@
1+-- A list of the element and all its parents up to the root node.
2+getPath tree t =
3+ t :
4+ case Map.lookup (getId t) tree of
5+ Nothing -> []
6+ Just parent -> getPath tree parent
data/examples/declaration/value/function/list-notation-2.hsnew file+5
@@ -0,0 +1,5 @@
1+-- A list of the element and all its parents up to the root node.
2+getPath tree t = t :
3+ case Map.lookup (getId t) tree of
4+ Nothing -> []
5+ Just parent -> getPath tree parent
data/examples/declaration/value/function/list-notation-3-out.hsnew file+12
@@ -0,0 +1,12 @@
1+foo =
2+ reportSDoc "tc.cc" 30 $
3+ sep $ do
4+ (prettyTCM q <+> " before compilation") : do
5+ map (prettyTCM . map unArg . clPats) cls
6+
7+foo =
8+ reportSDoc "tc.cc" 30 $
9+ sep $ do
10+ (prettyTCM q <+> " before compilation") :
11+ do
12+ map (prettyTCM . map unArg . clPats) cls
data/examples/declaration/value/function/list-notation-3.hsnew file+10
@@ -0,0 +1,10 @@
1+foo =
2+ reportSDoc "tc.cc" 30 $ sep $ do
3+ (prettyTCM q <+> " before compilation") : do
4+ map (prettyTCM . map unArg . clPats) cls
5+
6+foo =
7+ reportSDoc "tc.cc" 30 $ sep $ do
8+ (prettyTCM q <+> " before compilation") :
9+ do
10+ map (prettyTCM . map unArg . clPats) cls
data/examples/declaration/value/function/multi-way-if-out.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE MultiWayIf #-}
2+
3+foo x = if | x == 5 -> 5
4+
5+bar x y =
6+ if
7+ | x > y -> x
8+ | x < y ->
9+ y
10+ | otherwise -> x
11+
12+baz =
13+ if
14+ | p -> f
15+ | otherwise -> g
16+ x
data/examples/declaration/value/function/multi-way-if.hsnew file+14
@@ -0,0 +1,14 @@
1+{-# LANGUAGE MultiWayIf #-}
2+
3+foo x = if | x == 5 -> 5
4+
5+bar x y = if
6+ | x > y -> x
7+ | x < y
8+ -> y
9+ | otherwise -> x
10+
11+baz =
12+ if | p -> f
13+ | otherwise -> g
14+ x
data/examples/declaration/value/function/multiline-arguments-out.hsnew file+8
@@ -0,0 +1,8 @@
1+foo :: Int -> Int -> Int -> Int
2+foo
3+ (Foo g o)
4+ ( Bar
5+ x
6+ y
7+ )
8+ z = x
data/examples/declaration/value/function/multiline-arguments.hsnew file+4
@@ -0,0 +1,4 @@
1+foo :: Int -> Int -> Int -> Int
2+foo (Foo g o)
3+ (Bar
4+ x y) z = x
data/examples/declaration/value/function/multiple-guards-out.hsnew file+14
@@ -0,0 +1,14 @@
1+foo :: Int -> Int
2+foo x
3+ | x == 5 = 10
4+ | otherwise = 12
5+
6+bar :: Int -> Int
7+bar x
8+ | x == 5 =
9+ foo x
10+ + foo 10
11+ | x == 6 =
12+ foo x
13+ + foo 20
14+ | otherwise = foo 100
data/examples/declaration/value/function/multiple-guards.hsnew file+13
@@ -0,0 +1,13 @@
1+foo :: Int -> Int
2+foo x
3+ | x == 5 = 10
4+ | otherwise = 12
5+
6+bar :: Int -> Int
7+bar x
8+ | x == 5 = foo x
9+ + foo 10
10+ | x == 6 = foo x
11+ + foo 20
12+ | otherwise = foo 100
13+
data/examples/declaration/value/function/multiple-matches-out.hsnew file+3
@@ -0,0 +1,3 @@
1+foo :: Int -> Int
2+foo 5 = 10
3+foo _ = 12
data/examples/declaration/value/function/multiple-matches.hsnew file+3
@@ -0,0 +1,3 @@
1+foo :: Int -> Int
2+foo 5 = 10
3+foo _ = 12
data/examples/declaration/value/function/negation-out.hsnew file+8
@@ -0,0 +1,8 @@
1+foo :: Int
2+foo = (-2)
3+
4+bar :: Int
5+bar = -2
6+
7+baz :: Int
8+baz = - 2
data/examples/declaration/value/function/negation.hsnew file+8
@@ -0,0 +1,8 @@
1+foo :: Int
2+foo = (-2)
3+
4+bar :: Int
5+bar = -2
6+
7+baz :: Int
8+baz = - 2
data/examples/declaration/value/function/newline-single-line-body-out.hsnew file+10
@@ -0,0 +1,10 @@
1+function :: Int -> Int
2+function a =
3+ aReallyLongFunctionNameThatShouldStayOnThisLineToAvoidOverflowing 10000 a
4+
5+function' :: String -> String
6+function' s = case s of
7+ "ThisString" ->
8+ -- And a comment here is okay
9+ "Yay"
10+ _ -> "Boo"
data/examples/declaration/value/function/newline-single-line-body.hsnew file+10
@@ -0,0 +1,10 @@
1+function :: Int -> Int
2+function a =
3+ aReallyLongFunctionNameThatShouldStayOnThisLineToAvoidOverflowing 10000 a
4+
5+function' :: String -> String
6+function' s = case s of
7+ "ThisString" -> -- And a comment here is okay
8+ "Yay"
9+
10+ _ -> "Boo"
data/examples/declaration/value/function/operator-comments-0-out.hsnew file+16
@@ -0,0 +1,16 @@
1+foo =
2+ bar
3+ ++
4+ {- some comment -}
5+ case foo of
6+ a -> a
7+
8+foo =
9+ bar
10+ ++ {- some comment -} case foo of
11+ a -> a
12+
13+foo =
14+ bar
15+ ++ case foo {- some comment -} of
16+ a -> a
data/examples/declaration/value/function/operator-comments-0.hsnew file+17
@@ -0,0 +1,17 @@
1+foo =
2+ bar
3+ ++
4+ {- some comment -}
5+ case foo of
6+ a -> a
7+
8+foo =
9+ bar
10+ ++ {- some comment -}
11+ case foo of
12+ a -> a
13+
14+foo =
15+ bar
16+ ++ case foo of {- some comment -}
17+ a -> a
data/examples/declaration/value/function/operator-comments-1-out.hsnew file+16
@@ -0,0 +1,16 @@
1+foo =
2+ bar
3+ ++
4+ -- some comment
5+ case foo of
6+ a -> a
7+
8+foo =
9+ bar
10+ ++ case foo of -- some comment
11+ a -> a
12+
13+foo =
14+ bar
15+ ++ case foo of -- some comment
16+ a -> a
data/examples/declaration/value/function/operator-comments-1.hsnew file+17
@@ -0,0 +1,17 @@
1+foo =
2+ bar
3+ ++
4+ -- some comment
5+ case foo of
6+ a -> a
7+
8+foo =
9+ bar
10+ ++ -- some comment
11+ case foo of
12+ a -> a
13+
14+foo =
15+ bar
16+ ++ case foo of -- some comment
17+ a -> a
data/examples/declaration/value/function/operator-comments-2-out.hsnew file+5
@@ -0,0 +1,5 @@
1+x =
2+ y
3+ ++ f g -- commentA
4+ -- commentB
5+ -- commentC
data/examples/declaration/value/function/operator-comments-2.hsnew file+4
@@ -0,0 +1,4 @@
1+x =
2+ y ++ -- commentA
3+-- commentB
4+ f g -- commentC
data/examples/declaration/value/function/operator-sections-out.hsnew file+13
@@ -0,0 +1,13 @@
1+foo = (0 +)
2+
3+bar = (<> "hello")
4+
5+baz =
6+ ( 1 * 2
7+ +
8+ )
9+ ( *
10+ 3 ^ 5
11+ )
12+
13+quux = (,) <$> foo <$> bar
data/examples/declaration/value/function/operator-sections.hsnew file+9
@@ -0,0 +1,9 @@
1+foo = (0 +)
2+bar = ( <> "hello" )
3+baz =
4+ ( 1 * 2
5+ + )
6+ ( *
7+ 3 ^ 5)
8+
9+quux = (,) <$> foo <$> bar
data/examples/declaration/value/function/operators-0-out.hsnew file+5
@@ -0,0 +1,5 @@
1+a =
2+ b & c .~ d
3+ & e
4+ %~ f
5+ g
data/examples/declaration/value/function/operators-0.hsnew file+4
@@ -0,0 +1,4 @@
1+a =
2+ b & c .~ d
3+ & e %~ f
4+ g
data/examples/declaration/value/function/operators-1-out.hsnew file+4
@@ -0,0 +1,4 @@
1+foo =
2+ f
3+ . g
4+ =<< h . i
data/examples/declaration/value/function/operators-1.hsnew file+3
@@ -0,0 +1,3 @@
1+foo = f
2+ . g
3+ =<< h . i
data/examples/declaration/value/function/operators-2-out.hsnew file+4
@@ -0,0 +1,4 @@
1+foo n
2+ | x || y && z || n ** x
3+ || x && n =
4+ 42
data/examples/declaration/value/function/operators-2.hsnew file+4
@@ -0,0 +1,4 @@
1+foo n
2+ | x || y && z || n ** x
3+ || x && n =
4+ 42
data/examples/declaration/value/function/operators-3-out.hsnew file+3
@@ -0,0 +1,3 @@
1+foo =
2+ op <> n <+> colon <+> prettySe <+> text "="
3+ <+> prettySe <> text sc
data/examples/declaration/value/function/operators-3.hsnew file+3
@@ -0,0 +1,3 @@
1+foo =
2+ op <> n <+> colon <+> prettySe <+> text "=" <+>
3+ prettySe <> text sc
data/examples/declaration/value/function/operators-4-out.hsnew file+3
@@ -0,0 +1,3 @@
1+foo =
2+ line <> bindingOf <+> text "=" <+> tPretty <+> colon
3+ <+> align <> prettyPs
data/examples/declaration/value/function/operators-4.hsnew file+3
@@ -0,0 +1,3 @@
1+foo =
2+ line <> bindingOf <+> text "=" <+> tPretty <+> colon <+>
3+ align <> prettyPs
data/examples/declaration/value/function/operators-5-out.hsnew file+5
@@ -0,0 +1,5 @@
1+foo =
2+ map bar $
3+ [ baz
4+ ]
5+ ++ quux
data/examples/declaration/value/function/operators-5.hsnew file+4
@@ -0,0 +1,4 @@
1+foo =
2+ map bar $
3+ [ baz
4+ ] ++ quux
data/examples/declaration/value/function/operators-6-out.hsnew file+9
@@ -0,0 +1,9 @@
1+type PermuteRef =
2+ "a"
3+ :> ( "b" :> "c" :> End
4+ :<|> "c" :> "b" :> End
5+ )
6+ :<|> "b"
7+ :> ( "a" :> "c" :> End
8+ :<|> "c" :> "a" :> End
9+ )
data/examples/declaration/value/function/operators-6.hsnew file+7
@@ -0,0 +1,7 @@
1+type PermuteRef =
2+ "a" :> ( "b" :> "c" :> End
3+ :<|> "c" :> "b" :> End
4+ )
5+ :<|> "b" :> ( "a" :> "c" :> End
6+ :<|> "c" :> "a" :> End
7+ )
data/examples/declaration/value/function/overindentation-out.hsnew file+11
@@ -0,0 +1,11 @@
1+reallyincrediblyLongName =
2+ f
3+ a
4+ A
5+ { reallyincrediblyLongName =
6+ f
7+ a
8+ A
9+ { reallyincrediblyLongName
10+ }
11+ }
data/examples/declaration/value/function/overindentation.hsnew file+9
@@ -0,0 +1,9 @@
1+reallyincrediblyLongName = f
2+ a
3+ A
4+ { reallyincrediblyLongName = f
5+ a
6+ A
7+ { reallyincrediblyLongName
8+ }
9+ }
data/examples/declaration/value/function/overloaded-labels-out.hsnew file+5
@@ -0,0 +1,5 @@
1+{-# LANGUAGE OverloadedLabels #-}
2+
3+foo = #field
4+
5+bar = (#this) (#that)
data/examples/declaration/value/function/overloaded-labels.hsnew file+4
@@ -0,0 +1,4 @@
1+{-# LANGUAGE OverloadedLabels #-}
2+
3+foo = #field
4+bar = (#this ) ( #that)
data/examples/declaration/value/function/parallel-comprehensions-complex-out.hsnew file+35
@@ -0,0 +1,35 @@
1+baz x y z w =
2+ [ ( a,
3+ b,
4+ c,
5+ d,
6+ e,
7+ f,
8+ g,
9+ h,
10+ i,
11+ j
12+ )
13+ | a <- -- Foo 1
14+ x, -- Foo 2
15+ b <- -- Bar 1
16+ y, -- Bar 2
17+ a
18+ `mod` b -- Value
19+ == 0
20+ | c <- -- Baz 1
21+ z
22+ * z -- Baz 2
23+ -- Baz 3
24+ | d <- w -- Other
25+ | e <- x * x -- Foo bar
26+ | f <- -- Foo baz 1
27+ y + y -- Foo baz 2
28+ | h <- z + z * w ^ 2 -- Bar foo
29+ | i <- -- Bar bar 1
30+ a
31+ + b, -- Bar bar 2
32+ -- Bar bar 3
33+ j <- -- Bar baz 1
34+ a + b -- Bar baz 2
35+ ]
data/examples/declaration/value/function/parallel-comprehensions-complex.hsnew file+24
@@ -0,0 +1,24 @@
1+baz x y z w = [
2+ (a,b,c,d,e,
3+ f,g,h,i,j) |
4+ a<- -- Foo 1
5+ x, -- Foo 2
6+ b<- -- Bar 1
7+ y, -- Bar 2
8+ a
9+ `mod` b -- Value
10+ == 0|
11+ c<- -- Baz 1
12+ z * -- Baz 2
13+ z| -- Baz 3
14+ d<- w | -- Other
15+ e <- x * x | -- Foo bar
16+ f -- Foo baz 1
17+ <- y + y | -- Foo baz 2
18+ h <- z + z * w ^ 2 | -- Bar foo
19+ i <- -- Bar bar 1
20+ a + -- Bar bar 2
21+ b, -- Bar bar 3
22+ j <- -- Bar baz 1
23+ a + b -- Bar baz 2
24+ ]
data/examples/declaration/value/function/parallel-comprehensions-single-line-out.hsnew file+3
@@ -0,0 +1,3 @@
1+foo x y = [(a, b) | a <- x | b <- y]
2+
3+bar x y z w = [(a, b, c, d) | a <- x, b <- y, a `mod` b == 0 | c <- z | d <- w]
data/examples/declaration/value/function/parallel-comprehensions-single-line.hsnew file+4
@@ -0,0 +1,4 @@
1+foo x y = [(a,b) | a<-x | b<-y]
2+
3+bar x y z w = [(a,b,c,d) | a<-x, b<-y, a`mod`b == 0|c<-z|d<-w ]
4+
data/examples/declaration/value/function/parens-out.hsnew file+1
@@ -0,0 +1 @@
1+f = p (do foo; bar) baz
data/examples/declaration/value/function/parens.hsnew file+1
@@ -0,0 +1 @@
1+f = p (do foo; bar) baz
data/examples/declaration/value/function/parenthesis-lhs-out.hsnew file+9
@@ -0,0 +1,9 @@
1+(!=!) 2 y = 1
2+x !=! y = 2
3+
4+x ?=? [] = 123
5+(?=?) x (_ : []) = 456
6+x ?=? _ = f x x
7+ where
8+ f x 7 = 789
9+ x `f` _ = 101
data/examples/declaration/value/function/parenthesis-lhs.hsnew file+9
@@ -0,0 +1,9 @@
1+(!=!) 2 y = 1
2+x !=! y = 2
3+
4+x ?=? [] = 123
5+(?=?) x (_:[]) = 456
6+x ?=? _ = f x x
7+ where
8+ f x 7 = 789
9+ x `f` _ = 101
data/examples/declaration/value/function/pattern/as-pattern-out.hsnew file+3
@@ -0,0 +1,3 @@
1+main = case [1] of
2+ xs@(x : _) -> print (x, xs)
3+ xs@[] -> print xs
data/examples/declaration/value/function/pattern/as-pattern.hsnew file+3
@@ -0,0 +1,3 @@
1+main = case [1] of
2+ xs @ (x:_) -> print (x, xs)
3+ xs@[] -> print xs
data/examples/declaration/value/function/pattern/famous-cardano-pattern-out.hsnew file+8
@@ -0,0 +1,8 @@
1+( getNodeSettingsR
2+ :<|> getNodeInfoR
3+ :<|> getNextUpdateR
4+ :<|> restartNodeR
5+ )
6+ :<|> ( getUtxoR
7+ :<|> getConfirmedProposalsR
8+ ) = client nodeV1Api
data/examples/declaration/value/function/pattern/famous-cardano-pattern.hsnew file+7
@@ -0,0 +1,7 @@
1+( getNodeSettingsR
2+ :<|> getNodeInfoR
3+ :<|> getNextUpdateR
4+ :<|> restartNodeR
5+ ):<|>( getUtxoR
6+ :<|> getConfirmedProposalsR
7+ ) = client nodeV1Api
data/examples/declaration/value/function/pattern/multiline-case-pattern-out.hsnew file+15
@@ -0,0 +1,15 @@
1+readerBench doc name =
2+ runPure $ case (getReader name, getWriter name) of
3+ ( Right (TextReader r, rexts),
4+ Right (TextWriter w, wexts)
5+ ) -> undefined
6+
7+f xs = case xs of
8+ [ a,
9+ b
10+ ] -> a + b
11+
12+g xs = case xs of
13+ ( a
14+ : bs
15+ ) -> a + b
data/examples/declaration/value/function/pattern/multiline-case-pattern.hsnew file+12
@@ -0,0 +1,12 @@
1+readerBench doc name =
2+ runPure $ case (getReader name, getWriter name) of
3+ (Right (TextReader r, rexts),
4+ Right (TextWriter w, wexts)) -> undefined
5+
6+f xs = case xs of
7+ [ a,
8+ b ] -> a + b
9+
10+g xs = case xs of
11+ (a:
12+ bs) -> a + b
data/examples/declaration/value/function/pattern/n-plus-k-pattern-out.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# LANGUAGE NPlusKPatterns #-}
2+
3+singleline :: Int
4+singleline (n + 1) = n
5+
6+multiline :: Int
7+multiline
8+ ( n
9+ + 1
10+ ) = n
11+
12+n :: Int
13+(n + 1) = 3
data/examples/declaration/value/function/pattern/n-plus-k-pattern.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE NPlusKPatterns #-}
2+singleline :: Int
3+singleline (n + 1) = n
4+
5+multiline :: Int
6+multiline(n
7+ + 1) = n
8+
9+n :: Int
10+(n + 1) = 3
data/examples/declaration/value/function/pattern/pattern-bind-out.hsnew file+9
@@ -0,0 +1,9 @@
1+foo = bar
2+ where
3+ Foo bar baz = quux
4+ Baz
5+ quux = zoo
6+
7+foo = bar
8+ where
9+ Foo bar baz = quux
data/examples/declaration/value/function/pattern/pattern-bind.hsnew file+9
@@ -0,0 +1,9 @@
1+foo = bar
2+ where
3+ Foo bar baz = quux
4+ Baz
5+ quux = zoo
6+
7+foo = bar
8+ where Foo bar baz = quux
9+
data/examples/declaration/value/function/pattern/quasi-quotes-pattern-out.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE QuasiQuotes #-}
2+
3+singleline :: ()
4+singleline [yamlQQ|something|] = ()
5+
6+multiline :: ()
7+multiline = case y of
8+ [yamlQQ| name: John Doe
9+age: 23
10+|] -> ()
data/examples/declaration/value/function/pattern/quasi-quotes-pattern.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# LANGUAGE QuasiQuotes #-}
2+singleline :: ()
3+singleline [yamlQQ|something|] = ()
4+
5+multiline :: ()
6+multiline = case y of
7+ [yamlQQ| name: John Doe
8+age: 23
9+|] -> ()
data/examples/declaration/value/function/pattern/record-patterns-out.hsnew file+19
@@ -0,0 +1,19 @@
1+foo :: Boom -> Int
2+foo Boom {..} = 10
3+
4+bar0 :: Boom -> Int
5+bar0 Boom {boom} = boom
6+
7+bar1 :: Boom -> Int
8+bar1 Boom {boom = b} = b
9+
10+baz :: Boom -> Int
11+baz Boom {boom = b, ..} = b
12+
13+quux :: Boom -> Int
14+quux
15+ Boom
16+ { boom = a,
17+ foom = b,
18+ ..
19+ } = a + b
data/examples/declaration/value/function/pattern/record-patterns.hsnew file+18
@@ -0,0 +1,18 @@
1+foo :: Boom -> Int
2+foo Boom {..} = 10
3+
4+bar0 :: Boom -> Int
5+bar0 Boom {boom} = boom
6+
7+bar1 :: Boom -> Int
8+bar1 Boom { boom = b } = b
9+
10+baz :: Boom -> Int
11+baz Boom { boom = b, .. } = b
12+
13+quux :: Boom -> Int
14+quux Boom
15+ { boom = a
16+ , foom = b
17+ , ..
18+ } = a + b
data/examples/declaration/value/function/pattern/sig-pattern-out.hsnew file+7
@@ -0,0 +1,7 @@
1+f = do
2+ x :: a <- g
3+
4+f = do
5+ (x, y) ::
6+ (a, b) <-
7+ g
data/examples/declaration/value/function/pattern/sig-pattern.hsnew file+7
@@ -0,0 +1,7 @@
1+f = do
2+ x :: a <- g
3+
4+f = do
5+ (x, y)
6+ :: (a, b)
7+ <- g
data/examples/declaration/value/function/pattern/splice-pattern-out.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+singleLine = case () of
4+ $x -> ()
5+ $(y "something") -> ()
6+
7+multiline = case () of
8+ $( x
9+ + y
10+ ) -> ()
11+ $( y
12+ "something"
13+ ) -> ()
data/examples/declaration/value/function/pattern/splice-pattern.hsnew file+11
@@ -0,0 +1,11 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+singleLine = case () of
4+ $x -> ()
5+ $(y "something") -> ()
6+
7+multiline = case () of
8+ $(x
9+ + y) -> ()
10+ $(y
11+ "something") -> ()
data/examples/declaration/value/function/pattern/strictness-out.hsnew file+5
@@ -0,0 +1,5 @@
1+{-# LANGUAGE BangPatterns #-}
2+
3+!a = ()
4+
5+~b = ()
data/examples/declaration/value/function/pattern/strictness.hsnew file+4
@@ -0,0 +1,4 @@
1+{-# LANGUAGE BangPatterns #-}
2+
3+!a = ()
4+~b = ()
data/examples/declaration/value/function/pattern/unboxed-sum-pattern-out.hsnew file+26
@@ -0,0 +1,26 @@
1+{-# LANGUAGE UnboxedSums #-}
2+
3+v = True
4+ where
5+ (# _x #) = (# True #)
6+
7+p = True
8+ where
9+ (# _x | #) = (# | True #)
10+
11+q = True
12+ where
13+ (# | _x | #) = (# | True | #)
14+
15+z = True
16+ where
17+ (# | | _x #) = (# | | True #)
18+
19+z_multiline = True
20+ where
21+ (#
22+ | | _x
23+ #) =
24+ (#
25+ | | True
26+ #)
data/examples/declaration/value/function/pattern/unboxed-sum-pattern.hsnew file+23
@@ -0,0 +1,23 @@
1+{-# LANGUAGE UnboxedSums #-}
2+
3+v = True
4+ where
5+ (# _x #) = (# True #)
6+
7+p = True
8+ where
9+ (# _x | #) = (# | True #)
10+
11+q = True
12+ where
13+ (# | _x | #) = (# | True | #)
14+
15+z = True
16+ where
17+ (# | | _x #) = (# | | True #)
18+
19+z_multiline = True
20+ where
21+ (# |
22+ | _x #) = (# |
23+ | True #)
data/examples/declaration/value/function/pattern/view-pattern-out.hsnew file+15
@@ -0,0 +1,15 @@
1+{-# LANGUAGE ViewPatterns #-}
2+
3+example f (f -> 4) = True
4+
5+f (t -> Nothing) = "Nothing"
6+f (t -> Just _) = "Just"
7+
8+g ((f, _), f -> 4) = True
9+
10+multiline
11+ ( t ->
12+ Foo
13+ bar
14+ baz
15+ ) = True
data/examples/declaration/value/function/pattern/view-pattern.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE ViewPatterns #-}
2+
3+example f ( f -> 4 ) = True
4+
5+f (t -> Nothing) = "Nothing"
6+f (t -> Just _) = "Just"
7+
8+g ((f, _), f -> 4) = True
9+
10+multiline (t -> Foo
11+ bar
12+ baz) = True
data/examples/declaration/value/function/pragmas-out.hsnew file+11
@@ -0,0 +1,11 @@
1+sccfoo = {-# SCC foo #-} 1
2+
3+sccbar =
4+ {-# SCC "barbaz" #-}
5+ "hello"
6+
7+corefoo = {-# CORE "foo" #-} 1
8+
9+corebar =
10+ {-# CORE "bar baz" #-}
11+ "hello"
data/examples/declaration/value/function/pragmas.hsnew file+7
@@ -0,0 +1,7 @@
1+sccfoo = {-# SCC foo#-} 1
2+sccbar = {-# SCC "barbaz"#-}
3+ "hello"
4+
5+corefoo = {-# CORE "foo"#-} 1
6+corebar = {-# CORE "bar baz"#-}
7+ "hello"
data/examples/declaration/value/function/prefix-out.hsnew file+1
@@ -0,0 +1 @@
1+foo x y = (+) x y
data/examples/declaration/value/function/prefix.hsnew file+1
@@ -0,0 +1 @@
1+foo x y = (+) x y
data/examples/declaration/value/function/quasi-quotes-out.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE QuasiQuotes #-}
2+
3+singleline :: Value
4+singleline = [yamlQQ|something|]
5+
6+multiline :: Value
7+multiline =
8+ [yamlQQ| name: John Doe
9+age: 23
10+
11+something: foo
12+|]
data/examples/declaration/value/function/quasi-quotes.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE QuasiQuotes #-}
2+singleline :: Value
3+singleline = [yamlQQ|something|]
4+
5+multiline :: Value
6+multiline = [yamlQQ| name: John Doe
7+age: 23
8+
9+something: foo
10+|]
data/examples/declaration/value/function/record/constructors-out.hsnew file+31
@@ -0,0 +1,31 @@
1+foo = Foo {a = 3}
2+
3+bar =
4+ Bar
5+ { abc = foo,
6+ def = Foo {a = 10}
7+ }
8+
9+baz = Baz {}
10+
11+sym = Foo {(+) = 3}
12+
13+aLongVariableName =
14+ ALongRecordName
15+ { short = baz,
16+ aLongRecordFieldName =
17+ YetAnotherLongRecordName
18+ { yetAnotherLongRecordFieldName = "a long string"
19+ },
20+ aLongRecordFieldName2 =
21+ Just
22+ YetAnotherLongRecordName
23+ { yetAnotherLongRecordFieldName = "a long string",
24+ yetAnotherLongRecordFieldName =
25+ Just
26+ "a long string"
27+ },
28+ aLongRecordFieldName3 = do
29+ foo
30+ bar
31+ }
data/examples/declaration/value/function/record/constructors.hsnew file+22
@@ -0,0 +1,22 @@
1+foo = Foo { a = 3 }
2+bar = Bar {
3+ abc = foo,
4+ def = Foo {a = 10}
5+}
6+baz = Baz{ }
7+sym = Foo { (+) = 3 }
8+aLongVariableName =
9+ ALongRecordName
10+ { short = baz,
11+ aLongRecordFieldName = YetAnotherLongRecordName
12+ { yetAnotherLongRecordFieldName = "a long string"
13+ },
14+ aLongRecordFieldName2 = Just YetAnotherLongRecordName
15+ { yetAnotherLongRecordFieldName = "a long string",
16+ yetAnotherLongRecordFieldName = Just
17+ "a long string"
18+ },
19+ aLongRecordFieldName3 = do
20+ foo
21+ bar
22+ }
data/examples/declaration/value/function/record/dot-out.hsnew file+15
@@ -0,0 +1,15 @@
1+{-# OPTIONS_GHC -fplugin=RecordDotPreprocessor #-}
2+
3+data Foo = Foo {bar :: Int}
4+
5+mfoo = fmap (.bar) $ Nothing
6+
7+bar = (Foo 1).bar
8+
9+fooplus f n = f{foo = f.bar + n}
10+
11+fooplus' f n = f {foo = f.bar + n}
12+
13+fooplus'' f n = f {foo = f.bar + n}
14+
15+fooplus''' f n = f {foo = f.bar + n}
data/examples/declaration/value/function/record/dot.hsnew file+14
@@ -0,0 +1,14 @@
1+{-# OPTIONS_GHC -fplugin=RecordDotPreprocessor #-}
2+data Foo = Foo { bar :: Int }
3+
4+mfoo = fmap (.bar) $ Nothing
5+
6+bar = ( Foo 1).bar
7+
8+fooplus f n = f{foo = f.bar + n}
9+
10+fooplus' f n = f { foo = f.bar + n}
11+
12+fooplus'' f n = f {foo = f.bar + n}
13+
14+fooplus''' f n = f{ foo = f.bar + n}
data/examples/declaration/value/function/record/hanging-after-equal-con-out.hsnew file+8
@@ -0,0 +1,8 @@
1+foo =
2+ Foo
3+ { foo =
4+ -- Blah blah
5+ case x of
6+ Blah -> 1
7+ Blim -> 2
8+ }
data/examples/declaration/value/function/record/hanging-after-equal-con.hsnew file+7
@@ -0,0 +1,7 @@
1+foo = Foo
2+ { foo =
3+ -- Blah blah
4+ case x of
5+ Blah -> 1
6+ Blim -> 2
7+ }
data/examples/declaration/value/function/record/hanging-after-equal-update-out.hsnew file+8
@@ -0,0 +1,8 @@
1+foo =
2+ foo
3+ { foo =
4+ -- Blah blah
5+ case x of
6+ Blah -> 1
7+ Blim -> 2
8+ }
data/examples/declaration/value/function/record/hanging-after-equal-update.hsnew file+7
@@ -0,0 +1,7 @@
1+foo = foo
2+ { foo =
3+ -- Blah blah
4+ case x of
5+ Blah -> 1
6+ Blim -> 2
7+ }
data/examples/declaration/value/function/record/inter-comments-out.hsnew file+13
@@ -0,0 +1,13 @@
1+x =
2+ Just
3+ -- comment
4+ A
5+ { x
6+ }
7+
8+x =
9+ Just
10+ -- comment
11+ a
12+ { x
13+ }
data/examples/declaration/value/function/record/inter-comments.hsnew file+11
@@ -0,0 +1,11 @@
1+x = Just
2+ -- comment
3+ A
4+ { x
5+ }
6+
7+x = Just
8+ -- comment
9+ a
10+ { x
11+ }
data/examples/declaration/value/function/record/updaters-out.hsnew file+11
@@ -0,0 +1,11 @@
1+foo x = x {a = 3}
2+
3+bar x =
4+ x
5+ { abc = foo,
6+ def = Foo {a = 10}
7+ }
8+
9+baz x = x {}
10+
11+sym x = x {(+) = 4}
data/examples/declaration/value/function/record/updaters.hsnew file+7
@@ -0,0 +1,7 @@
1+foo x = x { a = 3 }
2+bar x = x {
3+ abc = foo,
4+ def = Foo {a = 10}
5+}
6+baz x = x{ }
7+sym x = x { (+) = 4 }
data/examples/declaration/value/function/record/wildcards-out.hsnew file+14
@@ -0,0 +1,14 @@
1+{-# LANGUAGE NamedFieldPuns #-}
2+{-# LANGUAGE RecordWildCards #-}
3+
4+foo x y = Foo {x, y}
5+
6+bar x y z =
7+ Bar
8+ { x,
9+ y,
10+ z,
11+ ..
12+ }
13+
14+baz = Baz {..}
data/examples/declaration/value/function/record/wildcards.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# LANGUAGE NamedFieldPuns #-}
2+{-# LANGUAGE RecordWildCards #-}
3+
4+foo x y = Foo { x, y }
5+
6+bar x y z = Bar {
7+ x,
8+ y,
9+ z,
10+ ..
11+}
12+
13+baz = Baz { .. }
data/examples/declaration/value/function/simple-out.hsnew file+3
@@ -0,0 +1,3 @@
1+bar x = x
2+
3+baz = x
data/examples/declaration/value/function/simple.hsnew file+2
@@ -0,0 +1,2 @@
1+bar x = x
2+baz = x
data/examples/declaration/value/function/splice-out.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+bar = $bar
4+
5+bar' = $(bar "something")
6+
7+baz = $$baz
8+
9+baz' = $$(baz "something")
data/examples/declaration/value/function/splice.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+bar = $bar
4+
5+bar' = $(bar "something")
6+
7+baz = $$baz
8+
9+baz' = $$(baz "something")
data/examples/declaration/value/function/static-pointers-out.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE StaticPointers #-}
2+
3+foo :: StaticPtr Int
4+foo = static 5
5+
6+bar :: StaticPtr [Int]
7+bar =
8+ static
9+ [ 1,
10+ 2,
11+ 3
12+ ]
13+
14+baz :: StaticPtr Bool
15+baz =
16+ static
17+ ( fun
18+ 1
19+ 2
20+ )
data/examples/declaration/value/function/static-pointers.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# LANGUAGE StaticPointers #-}
2+
3+foo :: StaticPtr Int
4+foo = static 5
5+
6+bar :: StaticPtr [Int]
7+bar = static [ 1
8+ , 2, 3
9+ ]
10+
11+baz :: StaticPtr Bool
12+baz = static (fun 1
13+ 2)
data/examples/declaration/value/function/strings-out.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE MagicHash #-}
2+
3+foo = "foobar"
4+
5+bar = "foo\&barbaz"
6+
7+baz =
8+ "foo\
9+ \bar\
10+ \baz"
data/examples/declaration/value/function/strings.hsnew file+7
@@ -0,0 +1,7 @@
1+{-# LANGUAGE MagicHash #-}
2+
3+foo = "foobar"
4+bar = "foo\&bar\ \baz"
5+baz = "foo\
6+ \bar\
7+ \baz"
data/examples/declaration/value/function/tricky-parens-out.hsnew file+4
@@ -0,0 +1,4 @@
1+handleStuff =
2+ ( let foo = foo
3+ in foo
4+ )
data/examples/declaration/value/function/tricky-parens.hsnew file+4
@@ -0,0 +1,4 @@
1+handleStuff =
2+ ( let foo = foo
3+ in foo
4+ )
data/examples/declaration/value/function/tuple-sections-out.hsnew file+8
@@ -0,0 +1,8 @@
1+{-# LANGUAGE TupleSections #-}
2+
3+foo = (,2)
4+
5+bar = (,5,)
6+
7+baz =
8+ (,,5,6,7,,,)
data/examples/declaration/value/function/tuple-sections.hsnew file+8
@@ -0,0 +1,8 @@
1+{-# LANGUAGE TupleSections #-}
2+
3+foo = (,2)
4+bar = (,5,)
5+baz = (
6+ ,,5,6,
7+ 7,,,
8+ )
data/examples/declaration/value/function/tuples-out.hsnew file+14
@@ -0,0 +1,14 @@
1+foo = (1, 2, 3)
2+
3+bar =
4+ ( 1,
5+ 2,
6+ 3
7+ )
8+
9+handleStuff =
10+ ( let foo = foo
11+ in foo,
12+ let bar = bar
13+ in bar
14+ )
data/examples/declaration/value/function/tuples.hsnew file+13
@@ -0,0 +1,13 @@
1+foo = ( 1,2,3 )
2+bar = (
3+ 1,
4+ 2,
5+ 3
6+ )
7+
8+handleStuff =
9+ ( let foo = foo
10+ in foo
11+ , let bar = bar
12+ in bar
13+ )
data/examples/declaration/value/function/type-applications-and-splice-out.hsnew file+4
@@ -0,0 +1,4 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+{-# LANGUAGE TypeApplications #-}
3+
4+staticKey name = [|sing @ $(symFQN name)|]
data/examples/declaration/value/function/type-applications-and-splice.hsnew file+4
@@ -0,0 +1,4 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+{-# LANGUAGE TypeApplications #-}
3+
4+staticKey name = [| sing @ $(symFQN name) |]
data/examples/declaration/value/function/type-applications-out.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE TypeApplications #-}
2+
3+foo = f @String a b c
4+
5+bar = f @(Maybe Int) a b
6+
7+baz =
8+ f @Int @String
9+ a
10+ b
11+
12+goo =
13+ hash
14+ @(HASH TPraosStandardCrypto)
15+ @ByteString
16+ "And the lamb lies down on Broadway"
data/examples/declaration/value/function/type-applications.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# LANGUAGE TypeApplications #-}
2+
3+foo = f @String a b c
4+
5+bar = f @(Maybe Int) a b
6+
7+baz = f @Int @String
8+ a b
9+
10+goo = hash
11+ @(HASH TPraosStandardCrypto)
12+ @ByteString
13+ "And the lamb lies down on Broadway"
data/examples/declaration/value/function/typed-expressions-out.hsnew file+5
@@ -0,0 +1,5 @@
1+foo x = x :: Int
2+
3+bar x =
4+ Just x ::
5+ Maybe String
data/examples/declaration/value/function/typed-expressions.hsnew file+3
@@ -0,0 +1,3 @@
1+foo x = x::Int
2+bar x = Just x ::
3+ Maybe String
data/examples/declaration/value/function/typed-hole-out.hsnew file+5
@@ -0,0 +1,5 @@
1+foo = 1 `_` 2
2+
3+bar = 1 `_a` 2
4+
5+baz = _ `something` _
data/examples/declaration/value/function/typed-hole.hsnew file+5
@@ -0,0 +1,5 @@
1+foo = 1 `_` 2
2+
3+bar = 1 `_a` 2
4+
5+baz = _ `something` _
data/examples/declaration/value/function/unboxed-string-lit-out.hsnew file+3
@@ -0,0 +1,3 @@
1+{-# LANGUAGE MagicHash #-}
2+
3+main = new "p"#
data/examples/declaration/value/function/unboxed-string-lit.hsnew file+3
@@ -0,0 +1,3 @@
1+{-# LANGUAGE MagicHash #-}
2+
3+main = new "p"#
data/examples/declaration/value/function/unboxed-sums-out.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE UnboxedSums #-}
2+
3+foo = (# 1 | #)
4+
5+bar = (# | | 2 | #)
6+
7+baz =
8+ (#
9+ | | | 10 | | | | |
10+ #)
data/examples/declaration/value/function/unboxed-sums.hsnew file+7
@@ -0,0 +1,7 @@
1+{-# LANGUAGE UnboxedSums #-}
2+
3+foo = (# 1 | #)
4+bar = (# | |2| #)
5+baz = (# |
6+ | | 10 | | | |
7+ | #)
data/examples/declaration/value/function/unboxed-tuples-out.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE UnboxedTuples #-}
2+
3+foo = (# 1, 2, 3 #)
4+
5+bar =
6+ (#
7+ 1,
8+ 2,
9+ 3
10+ #)
data/examples/declaration/value/function/unboxed-tuples.hsnew file+7
@@ -0,0 +1,7 @@
1+{-# LANGUAGE UnboxedTuples #-}
2+
3+foo = (# 1,2,3 #)
4+bar = (#
5+ 1,
6+ 2,
7+ 3 #)
data/examples/declaration/value/function/where-nested-out.hsnew file+12
@@ -0,0 +1,12 @@
1+foo = bar
2+ where
3+ f1 = f1
4+ where
5+ f1 = 3
6+ f2 = f2
7+ where
8+ f2 = 3
9+
10+foo2 = bar
11+ where
12+ f1 = f1 where { f1 = 3; f1' = 4 }; f2 = f2 where f2 = 3; f2' = 4
data/examples/declaration/value/function/where-nested.hsnew file+12
@@ -0,0 +1,12 @@
1+foo = bar
2+ where
3+ f1 = f1
4+ where
5+ f1 = 3
6+ f2 = f2
7+ where
8+ f2 = 3
9+
10+foo2 = bar
11+ where
12+ { f1 = f1 where { f1 = 3; f1' = 4 }; f2 = f2 where { f2 = 3; f2' = 4 } }
data/examples/declaration/value/function/where-out.hsnew file+19
@@ -0,0 +1,19 @@
1+foo :: Int -> Int
2+foo x = f x where f z = z
3+
4+bar :: Int -> Int
5+bar x = f x
6+ where
7+ f :: Int -> Int
8+ f z = z
9+
10+baz :: Int -> Int
11+baz x = q
12+ where
13+ y = x
14+ z = y
15+ q = z
16+
17+emptyWhere :: Int
18+emptyWhere = 5
19+ where
data/examples/declaration/value/function/where.hsnew file+19
@@ -0,0 +1,19 @@
1+foo :: Int -> Int
2+foo x = f x where f z = z
3+
4+bar :: Int -> Int
5+bar x = f x
6+ where
7+ f :: Int -> Int
8+ f z = z
9+
10+baz :: Int -> Int
11+baz x = q
12+ where
13+ y = x
14+ z = y
15+ q = z
16+
17+emptyWhere :: Int
18+emptyWhere = 5
19+ where
data/examples/declaration/value/other/comments-get-before-op-out.hsnew file+10
@@ -0,0 +1,10 @@
1+main :: IO ()
2+main = do
3+ migrateSchema
4+ [ migration1,
5+ migration1,
6+ migration3
7+ -- When adding migrations here, don't forget to update
8+ -- 'schemaVersion' in Galley.Data
9+ ]
10+ `finally` Log.close
data/examples/declaration/value/other/comments-get-before-op.hsnew file+11
@@ -0,0 +1,11 @@
1+main :: IO ()
2+main = do
3+ migrateSchema
4+ [ migration1
5+ , migration1
6+ , migration3
7+ -- When adding migrations here, don't forget to update
8+ -- 'schemaVersion' in Galley.Data
9+ ]
10+ `finally`
11+ Log.close
data/examples/declaration/value/other/line-multi-line-out.hsnew file+6
@@ -0,0 +1,6 @@
1+x :: [Int]
2+x =
3+ [ 1,
4+ 2,
5+ somethingSomething 3
6+ ]
data/examples/declaration/value/other/line-multi-line.hsnew file+6
@@ -0,0 +1,6 @@
1+x :: [Int]
2+x = [
3+ 1
4+ , 2
5+ , somethingSomething 3
6+ ]
data/examples/declaration/value/other/line-single-line-out.hsnew file+2
@@ -0,0 +1,2 @@
1+x :: [Int]
2+x = [1, 2, 3]
data/examples/declaration/value/other/line-single-line.hsnew file+2
@@ -0,0 +1,2 @@
1+x :: [Int]
2+x = [1,2,3]
data/examples/declaration/value/pattern-synonyms/bidirectional-out.hsnew file+28
@@ -0,0 +1,28 @@
1+{-# LANGUAGE NamedFieldPuns #-}
2+{-# LANGUAGE PatternSynonyms #-}
3+
4+pattern Arrow t1 t2 = App "->" [t1, t2]
5+
6+pattern Arrow {t1, t2} = App "->" [t1, t2]
7+
8+pattern Arrow
9+ { t1,
10+ t2
11+ } =
12+ App "->" [t1, t2]
13+
14+pattern Int =
15+ App "Int" []
16+
17+pattern Maybe {t} =
18+ App
19+ "Maybe"
20+ [t]
21+
22+pattern Maybe t =
23+ App
24+ "Maybe"
25+ [t]
26+
27+pattern a :< b <-
28+ (a, b)
data/examples/declaration/value/pattern-synonyms/bidirectional.hsnew file+21
@@ -0,0 +1,21 @@
1+{-# LANGUAGE PatternSynonyms #-}
2+{-# LANGUAGE NamedFieldPuns #-}
3+
4+pattern Arrow t1 t2 = App "->" [t1, t2]
5+pattern Arrow{t1,t2} = App "->" [t1,t2]
6+pattern Arrow{t1
7+ , t2} = App "->" [t1, t2]
8+pattern Int =
9+ App "Int" []
10+pattern Maybe{t} =
11+ App
12+ "Maybe"
13+ [t]
14+pattern Maybe t =
15+ App
16+ "Maybe"
17+ [t]
18+
19+pattern a :< b <-
20+ (a , b)
21+
data/examples/declaration/value/pattern-synonyms/explicitely-bidirectional-out.hsnew file+21
@@ -0,0 +1,21 @@
1+{-# LANGUAGE PatternSynonyms #-}
2+
3+pattern HeadC x <-
4+ x : xs
5+ where
6+ HeadC x = [x]
7+
8+pattern HeadC' x <-
9+ x : xs
10+ where
11+ HeadC' x = [x]
12+
13+pattern Simple <-
14+ "Simple"
15+ where
16+ Simple = "Complicated"
17+
18+pattern a :< b <-
19+ (a, b)
20+ where
21+ a :< b = (a, b)
data/examples/declaration/value/pattern-synonyms/explicitely-bidirectional.hsnew file+19
@@ -0,0 +1,19 @@
1+{-# LANGUAGE PatternSynonyms #-}
2+
3+pattern HeadC x <- x:xs where
4+ HeadC x = [x]
5+
6+pattern HeadC' x <-
7+ x:xs
8+ where
9+ HeadC' x = [x]
10+
11+pattern Simple <- "Simple"
12+ where
13+ Simple = "Complicated"
14+
15+pattern a :< b <-
16+ (a , b)
17+ where
18+ a :< b = (a, b)
19+
data/examples/declaration/value/pattern-synonyms/unidirectional-out.hsnew file+23
@@ -0,0 +1,23 @@
1+{-# LANGUAGE PatternSynonyms #-}
2+
3+pattern Head x <- x : xs
4+
5+pattern Head' x <-
6+ x : xs
7+
8+pattern Head'' {x} <-
9+ x : xs
10+
11+pattern FirstTwo {x, y} <-
12+ x : (y : xs)
13+
14+pattern FirstTwo'
15+ { x,
16+ y
17+ } <-
18+ x : (y : xs)
19+
20+pattern Simple <- "Simple"
21+
22+pattern WithTypeSig :: String
23+pattern WithTypeSig <- "WithTypeSig"
data/examples/declaration/value/pattern-synonyms/unidirectional.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE PatternSynonyms #-}
2+
3+pattern Head x <- x:xs
4+
5+pattern Head' x
6+ <- x:xs
7+
8+pattern Head''{x}
9+ <- x:xs
10+
11+pattern FirstTwo{x,y}
12+ <- x : (y : xs)
13+
14+pattern FirstTwo'{x
15+ , y} <- x : (y:xs)
16+
17+pattern Simple <- "Simple"
18+
19+pattern WithTypeSig :: String
20+pattern WithTypeSig <- "WithTypeSig"
data/examples/declaration/warning/warning-multiline-out.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# WARNING
2+ test,
3+ foo
4+ [ "These are bad functions",
5+ "Really bad!"
6+ ]
7+ #-}
8+test :: IO ()
9+test = pure ()
data/examples/declaration/warning/warning-multiline.hsnew file+4
@@ -0,0 +1,4 @@
1+{-# WArNING test,
2+ foo ["These are bad functions", "Really bad!"] #-}
3+test :: IO ()
4+test = pure ()
data/examples/declaration/warning/warning-single-line-out.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# DEPRECATED test, foo "This is a deprecation" #-}
2+{-# WARNING test "This is a warning" #-}
3+test :: IO ()
4+test = pure ()
5+
6+bar = 3
7+{-# DEPRECATED bar "Bar is deprecated" #-}
8+
9+{-# DEPRECATED baz "Baz is also deprecated" #-}
10+baz = 5
11+
12+data Number = Number Dobule
13+{-# DEPRECATED Number "Use Scientific instead." #-}
data/examples/declaration/warning/warning-single-line.hsnew file+15
@@ -0,0 +1,15 @@
1+{-# Deprecated test, foo "This is a deprecation"
2+ #-}
3+{-# WARNING test ["This is a warning" ] #-}
4+test :: IO ()
5+test = pure ()
6+
7+bar = 3
8+
9+{-# Deprecated bar "Bar is deprecated" #-}
10+
11+{-# DEPRECATED baz "Baz is also deprecated" #-}
12+baz = 5
13+
14+data Number = Number Dobule
15+{-# DEPRECATED Number "Use Scientific instead." #-}
data/examples/import/comments-inside-imports-out.hsnew file+7
@@ -0,0 +1,7 @@
1+-- x
2+
3+import qualified -- x
4+ Bar
5+import qualified -- x
6+ Baz
7+import Foo
data/examples/import/comments-inside-imports.hsnew file+9
@@ -0,0 +1,9 @@
1+import -- x
2+ Foo
3+
4+import -- x
5+ qualified Bar
6+
7+import qualified
8+ -- x
9+ Baz
data/examples/import/comments-per-import-out.hs+3−3
@@ -1,4 +1,4 @@
1+-- (1)
1−import Bar
2+import Bar -- (2)
2−import Baz
3+import Baz -- (3)
3import Foo
4import Foo
4−-- (3)
data/examples/import/deduplication-bug-out.hsnew file+6
@@ -0,0 +1,6 @@
1+import Foo1 (Bar1 (..), Baz1)
2+import Foo2 (Bar2 (..), Baz2)
3+import Foo3 (Bar3 (x1, x2, x3))
4+import Foo4 (Bar4 (x1, x2))
5+import Foo5 (Bar5 (x1))
6+import Foo6 (Bar6 (..))
data/examples/import/deduplication-bug.hsnew file+6
@@ -0,0 +1,6 @@
1+import Foo1 (Bar1, Baz1, Bar1(..))
2+import Foo2 (Bar2(..), Baz2, Bar2)
3+import Foo3 (Bar3(x1,x3), Bar3(x1, x2))
4+import Foo4 (Bar4(x1), Bar4(x2))
5+import Foo5 (Bar5, Bar5(x1))
6+import Foo6 (Bar6(x1), Bar6(..))
data/examples/import/explicit-imports-out.hs+10−10
@@ -1,12 +1,12 @@
1import qualified MegaModule as M
1import qualified MegaModule as M
2− ( (<<<)
3− , (>>>)
4− , Either
2+ ( Either,
5− , Maybe (Just, Nothing)
3+ Maybe (Just, Nothing),
6− , MaybeT (..)
4+ MaybeT (..),
7− , Monad ((>>), (>>=), return)
5+ Monad (return, (>>), (>>=)),
8− , MonadBaseControl
6+ MonadBaseControl,
9− , join
7+ join,
10− , liftIO
8+ liftIO,
11− , void
9+ void,
10+ (<<<),
11+ (>>>),
12 )
12 )
data/examples/import/explicit-imports-with-comments-out.hs+5−3
@@ -1,5 +1,7 @@
1import qualified MegaModule as M
1import qualified MegaModule as M
2+ ( -- (1)
3+ -- (2)
4+ Either, -- (3)
2− ( (<<<)
5+ (<<<),
3− , (>>>)
6+ (>>>),
4− , Either
5 )
7 )
data/examples/import/merging-0-out.hsnew file+3
@@ -0,0 +1,3 @@
1+import Foo
2+import Foo (bar, foo)
3+import Foo as F
data/examples/import/merging-0.hsnew file+4
@@ -0,0 +1,4 @@
1+import Foo
2+import Foo (foo)
3+import Foo (bar)
4+import Foo as F
data/examples/import/merging-1-out.hsnew file+2
@@ -0,0 +1,2 @@
1+import "bar" Foo (bar)
2+import "foo" Foo (baz, foo)
data/examples/import/merging-1.hsnew file+3
@@ -0,0 +1,3 @@
1+import "foo" Foo (foo)
2+import "bar" Foo (bar)
3+import "foo" Foo (baz)
data/examples/import/merging-2-out.hsnew file+2
@@ -0,0 +1,2 @@
1+import Foo hiding (bar4, foo2)
2+import qualified Foo (bar3, foo1)
data/examples/import/merging-2.hsnew file+4
@@ -0,0 +1,4 @@
1+import qualified Foo (foo1)
2+import Foo hiding (foo2)
3+import qualified Foo (bar3)
4+import Foo hiding (bar4)
data/examples/import/misc-out.hs+1−7
@@ -1,11 +1,5 @@
1import A hiding
1import A hiding
2− ( foobarbazqux
2+ ( foobarbazqux,
3− , foobarbazqux
4− , foobarbazqux
5− , foobarbazqux
6− , foobarbazqux
7− , foobarbazqux
8− , foobarbazqux
9 )
3 )
10import {-# SOURCE #-} safe qualified Module as M hiding (a, b, c, d, e, f)
4import {-# SOURCE #-} safe qualified Module as M hiding (a, b, c, d, e, f)
11import Name hiding ()
5import Name hiding ()
data/examples/import/nested-explicit-imports-out.hs+8−8
@@ -1,10 +1,10 @@
1import qualified MegaModule as M
1import qualified MegaModule as M
2− ( (<<<)
3− , (>>>)
4− , Either
2+ ( Either,
5− , Monad
3+ Monad
4+ ( return,
6− ( (>>)
5+ (>>),
7− , (>>=)
6+ (>>=)
8− , return
7+ ),
9− )
8+ (<<<),
9+ (>>>),
10 )
10 )
data/examples/import/qualified-post-out.hsnew file+5
@@ -0,0 +1,5 @@
1+{-# LANGUAGE ImportQualifiedPost #-}
2+
3+import Data.Text qualified (a, b, c)
4+import Data.Text qualified hiding (a, b, c)
5+import Data.Text qualified as T
data/examples/import/qualified-post.hsnew file+5
@@ -0,0 +1,5 @@
1+{-# LANGUAGE ImportQualifiedPost #-}
2+
3+import qualified Data.Text as T
4+import qualified Data.Text (a, c, b)
5+import Data.Text qualified hiding (c, b, a)
data/examples/import/qualified-prelude-out.hsnew file+4
@@ -0,0 +1,4 @@
1+module P where
2+
3+import Prelude hiding (id, (.))
4+import qualified Prelude
data/examples/import/qualified-prelude.hsnew file+4
@@ -0,0 +1,4 @@
1+module P where
2+
3+import Prelude hiding (id, (.))
4+import qualified Prelude
data/examples/import/simple-out.hs+2−3
@@ -1,6 +1,5 @@
1import Data.Text
1import Data.Text
2−import Data.Text
3−import qualified Data.Text as T
4−import qualified Data.Text (a, b, c)
5import Data.Text (a, b, c)
2import Data.Text (a, b, c)
6import Data.Text hiding (a, b, c)
3import Data.Text hiding (a, b, c)
4+import qualified Data.Text (a, b, c)
5+import qualified Data.Text as T
data/examples/import/simple.hs+2
@@ -4,3 +4,5 @@ import qualified Data.Text as T
4import qualified Data.Text (a, c, b)
4import qualified Data.Text (a, c, b)
5import Data.Text (a, b, c)
5import Data.Text (a, b, c)
6import Data.Text hiding (c, b, a)
6import Data.Text hiding (c, b, a)
7+import Data.Text (a, b, c, b, a)
8+import Data.Text hiding (c, b, a, b, c)
data/examples/import/sorted-export-list-out.hsnew file+1
@@ -0,0 +1 @@
1+import Linear.Vector (Additive (..), (*^), (^*))
data/examples/import/sorted-export-list.hsnew file+1
@@ -0,0 +1 @@
1+import Linear.Vector (Additive (..), (*^), (^*))
data/examples/module-header/double-dot-with-names-out.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE PatternSynonyms #-}
2+
3+module ExportSyntax (A (.., NoA), Q (F, ..), G (T, .., U)) where
4+
5+data A = A | B
6+
7+pattern NoA = B
8+
9+data Q a = Q a
10+
11+pattern F a = Q a
12+
13+data G = G | H
14+
15+pattern T = G
16+
17+pattern U = H
data/examples/module-header/double-dot-with-names.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE PatternSynonyms #-}
2+
3+module ExportSyntax ( A(.., NoA), Q(F,..), G(T,..,U)) where
4+
5+data A = A | B
6+
7+pattern NoA = B
8+
9+data Q a = Q a
10+
11+pattern F a = Q a
12+
13+data G = G | H
14+
15+pattern T = G
16+
17+pattern U = H
data/examples/module-header/leading-empty-line-out.hsnew file+11
@@ -0,0 +1,11 @@
1+-- |
2+-- Module : Text.Megaparsec
3+-- Copyright : © 2015–2019 Megaparsec contributors
4+-- © 2007 Paolo Martini
5+-- © 1999–2001 Daan Leijen
6+-- License : FreeBSD
7+--
8+-- Maintainer : Mark Karpov <markkarpov92@gmail.com>
9+-- Stability : experimental
10+-- Portability : portable
11+module Main where
data/examples/module-header/leading-empty-line.hsnew file+11
@@ -0,0 +1,11 @@
1+-- |
2+-- Module : Text.Megaparsec
3+-- Copyright : © 2015–2019 Megaparsec contributors
4+-- © 2007 Paolo Martini
5+-- © 1999–2001 Daan Leijen
6+-- License : FreeBSD
7+--
8+-- Maintainer : Mark Karpov <markkarpov92@gmail.com>
9+-- Stability : experimental
10+-- Portability : portable
11+module Main where
data/examples/module-header/multiline-empty-out.hsnew file+4
@@ -0,0 +1,4 @@
1+module Foo
2+ (
3+ )
4+where
data/examples/module-header/multiline-empty.hsnew file+2
@@ -0,0 +1,2 @@
1+module Foo (
2+ ) where
data/examples/module-header/multiline-out.hs+3−3
@@ -1,6 +1,6 @@
1module Foo
1module Foo
2− ( foo
2+ ( foo,
3− , bar
3+ bar,
4− , baz
4+ baz,
5 )
5 )
6where
6where
data/examples/module-header/multiline-with-comments-out.hs+13−12
@@ -1,20 +1,21 @@
1−-- | Header.
2−
3{-# LANGUAGE FlexibleContexts #-}
1{-# LANGUAGE FlexibleContexts #-}
4{-# LANGUAGE TypeFamilies #-}
2{-# LANGUAGE TypeFamilies #-}
3+
4+-- | Header.
5module My.Module
5module My.Module
6 ( -- * Something
6 ( -- * Something
7− foo
7+ foo,
8− , bar
8+ bar,
9+
9− , -- * Another thing
10+ -- * Another thing
10− (<?>)
11+ (<?>),
11− , {- some other thing -} foo2 -- yet another
12+ {- some other thing -} foo2, -- yet another
12− , foo3 -- third one
13+ foo3, -- third one
13− , baz
14+ baz,
14− , bar2 -- a multiline comment
15+ bar2, -- a multiline comment
15 -- the second line
16 -- the second line
16− , bar3
17+ bar3,
17− , module Foo.Bar.Baz
18+ module Foo.Bar.Baz,
18 )
19 )
19where
20where
20
21
data/examples/module-header/multiline2-out.hs+3−3
@@ -1,6 +1,6 @@
1module Foo
1module Foo
2− ( foo
2+ ( foo,
3− , bar
3+ bar,
4− , baz
4+ baz,
5 )
5 )
6where
6where
data/examples/module-header/multiline2.hs+2−2
@@ -1,2 +1,2 @@
1−module Foo
1+module Foo (
2− (foo, bar, baz) where
2+ foo, bar, baz) where
data/examples/module-header/named-section-out.hsnew file+13
@@ -0,0 +1,13 @@
1+module Magic
2+ ( -- * Something
3+ -- $explanation
4+
5+ -- ** Another level
6+ foo,
7+ bar,
8+ )
9+where
10+
11+-- $explanation
12+--
13+-- Here it goes.
data/examples/module-header/named-section.hsnew file+13
@@ -0,0 +1,13 @@
1+module Magic
2+ ( -- * Something
3+ -- $explanation
4+
5+ -- ** Another level
6+ foo
7+ , bar
8+ )
9+where
10+
11+-- $explanation
12+--
13+-- Here it goes.
data/examples/module-header/preceding-comment-with-haddock-out.hsnew file+8
@@ -0,0 +1,8 @@
1+{-
2+ Here we go.
3+-}
4+
5+-- | This is the module's Haddock.
6+module Main (main) where
7+
8+main = return ()
data/examples/module-header/preceding-comment-with-haddock.hsnew file+8
@@ -0,0 +1,8 @@
1+{-
2+ Here we go.
3+-}
4+
5+-- | This is the module's Haddock.
6+module Main (main) where
7+
8+main = return ()
data/examples/module-header/shebang-out.hsnew file+6
@@ -0,0 +1,6 @@
1+#! /usr/bin/env runhaskell
2+
3+import Prelude
4+
5+main :: IO ()
6+main = putStrLn "hello world"
data/examples/module-header/shebang-with-pragmas-out.hsnew file+5
@@ -0,0 +1,5 @@
1+#!/usr/bin/env stack
2+
3+{-# LANGUAGE OverloadedStrings #-}
4+
5+main = pure ()
data/examples/module-header/shebang-with-pragmas.hsnew file+5
@@ -0,0 +1,5 @@
1+#!/usr/bin/env stack
2+
3+{-# LANGUAGE OverloadedStrings #-}
4+
5+main = pure ()
data/examples/module-header/shebang.hsnew file+6
@@ -0,0 +1,6 @@
1+#! /usr/bin/env runhaskell
2+
3+import Prelude
4+
5+main :: IO ()
6+main = putStrLn "hello world"
data/examples/module-header/singleline-empty-out.hsnew file+2
@@ -0,0 +1,2 @@
1+-- | This demonstrates a BUG.
2+module Foo () where
data/examples/module-header/singleline-empty.hsnew file+2
@@ -0,0 +1,2 @@
1+-- | This demonstrates a BUG.
2+module Foo () where
data/examples/module-header/stack-header-0-out.hsnew file+7
@@ -0,0 +1,7 @@
1+-- stack runhaskell
2+
3+{-# LANGUAGE OverloadedStrings #-}
4+
5+main = return ()
6+
7+-- stack runhaskell
data/examples/module-header/stack-header-0.hsnew file+4
@@ -0,0 +1,4 @@
1+-- stack runhaskell
2+{-# LANGUAGE OverloadedStrings #-}
3+main = return ()
4+-- stack runhaskell
data/examples/module-header/stack-header-1-out.hsnew file+8
@@ -0,0 +1,8 @@
1+#!/usr/bin/env stack
2+-- stack runhaskell
3+
4+{-# LANGUAGE OverloadedStrings #-}
5+
6+main = return ()
7+
8+-- stack runhaskell
data/examples/module-header/stack-header-1.hsnew file+5
@@ -0,0 +1,5 @@
1+#!/usr/bin/env stack
2+-- stack runhaskell
3+{-# LANGUAGE OverloadedStrings #-}
4+main = return ()
5+-- stack runhaskell
data/examples/module-header/stack-header-2-out.hsnew file+12
@@ -0,0 +1,12 @@
1+#!/usr/bin/env stack
2+{- stack
3+ script
4+ --resolver lts-6.25
5+ --package turtle
6+ --package "stm async"
7+ --package http-client,http-conduit
8+-}
9+
10+{-# LANGUAGE OverloadedStrings #-}
11+
12+main = return ()
data/examples/module-header/stack-header-2.hsnew file+12
@@ -0,0 +1,12 @@
1+#!/usr/bin/env stack
2+{- stack
3+ script
4+ --resolver lts-6.25
5+ --package turtle
6+ --package "stm async"
7+ --package http-client,http-conduit
8+-}
9+
10+{-# LANGUAGE OverloadedStrings #-}
11+
12+main = return ()
data/examples/module-header/warning-pragma-list-multiline-out.hsnew file+11
@@ -0,0 +1,11 @@
1+module Test
2+ {-# DEPRECATED
3+ [ "This module is deprecated.",
4+ "Please use OtherModule instead."
5+ ]
6+ #-}
7+ ( foo,
8+ bar,
9+ baz,
10+ )
11+where
data/examples/module-header/warning-pragma-list-multiline.hsnew file+8
@@ -0,0 +1,8 @@
1+module Test {-# DEPRECATED ["This module is deprecated.",
2+ "Please use OtherModule instead."
3+ ]#-}
4+ ( foo
5+ , bar
6+ , baz
7+ )
8+where
data/examples/module-header/warning-pragma-multiline-out.hsnew file+6
@@ -0,0 +1,6 @@
1+module Test
2+ {-# DEPRECATED "This module is unstable" #-}
3+ (foo, bar, baz)
4+where
5+
6+import Blah
data/examples/module-header/warning-pragma-multiline.hsnew file+4
@@ -0,0 +1,4 @@
1+module Test {-# DEPRECATED "This module is unstable" #-}
2+ (foo, bar, baz) where
3+
4+import Blah
data/examples/module-header/warning-pragma-out.hsnew file+5
@@ -0,0 +1,5 @@
1+module Test
2+ {-# WARNING
3+ "This module is very internal"
4+ #-}
5+where
data/examples/module-header/warning-pragma-singleton-list-out.hsnew file+1
@@ -0,0 +1 @@
1+module Test {-# WARNING "There's only one line here." #-} where
data/examples/module-header/warning-pragma-singleton-list.hsnew file+1
@@ -0,0 +1 @@
1+module Test {-# WArnING ["There's only one line here."] #-} where
data/examples/module-header/warning-pragma.hsnew file+2
@@ -0,0 +1,2 @@
1+module Test {-# WARNING "This module is very internal"
2+ #-} where
data/examples/other/argument-comment-out.hsnew file+16
@@ -0,0 +1,16 @@
1+foo ::
2+ -- | Documentation
3+ Int ->
4+ Bool
5+foo _ = True
6+
7+foo ::
8+ Foo a =>
9+ -- | Foo
10+ Int ->
11+ Int
12+foo ::
13+ Foo a =>
14+ -- | Foo
15+ Int ->
16+ Int
data/examples/other/argument-comment.hsnew file+13
@@ -0,0 +1,13 @@
1+foo
2+ :: Int -- ^ Documentation
3+ -> Bool
4+foo _ = True
5+
6+foo :: Foo a
7+ => Int -- ^ Foo
8+ -> Int
9+
10+foo
11+ :: Foo a
12+ => Int -- ^ Foo
13+ -> Int
data/examples/other/ascii-out.hsnew file+9
@@ -0,0 +1,9 @@
1+{- -----------------------------------
2+ < What about ASCII art in comments? >
3+ -----------------------------------
4+ \ ^__^
5+ \ (oo)\_______
6+ (__)\ )\/\
7+ ||----w |
8+ || ||
9+-}
data/examples/other/ascii.hsnew file+9
@@ -0,0 +1,9 @@
1+{- -----------------------------------
2+ < What about ASCII art in comments? >
3+ -----------------------------------
4+ \ ^__^
5+ \ (oo)\_______
6+ (__)\ )\/\
7+ ||----w |
8+ || ||
9+-}
data/examples/other/comment-after-preceding-haddock-out.hsnew file+12
@@ -0,0 +1,12 @@
1+module Main where
2+
3+-- | A
4+
5+-- B
6+
7+type D = E
8+
9+-- | This is 'f'
10+
11+-- * Comment
12+f :: a -> b
data/examples/other/comment-after-preceding-haddock.hsnew file+12
@@ -0,0 +1,12 @@
1+module Main where
2+
3+-- | A
4+
5+-- B
6+
7+type D = E
8+
9+-- | This is 'f'
10+
11+-- * Comment
12+f :: a -> b
data/examples/other/comment-alignment-out.hsnew file+9
@@ -0,0 +1,9 @@
1+class Foo a where
2+ -- | Foo.
3+ foo ::
4+ Int ->
5+ -- | Something
6+ a
7+
8+ -- | Bar.
9+ bar :: a
data/examples/other/comment-alignment.hsnew file+11
@@ -0,0 +1,11 @@
1+class Foo a where
2+
3+ -- | Foo.
4+
5+ foo
6+ :: Int
7+ -> a -- ^ Something
8+
9+ -- | Bar.
10+
11+ bar :: a
data/examples/other/comment-before-hanging-out.hsnew file+5
@@ -0,0 +1,5 @@
1+x = Just
2+ -- comment
3+ do
4+ foo
5+ bar
data/examples/other/comment-before-hanging.hsnew file+5
@@ -0,0 +1,5 @@
1+x = Just
2+ -- comment
3+ do
4+ foo
5+ bar
data/examples/other/comment-following-preceding-gap-out.hsnew file+6
@@ -0,0 +1,6 @@
1+foo = bar
2+ where
3+ baz = return (quux) -- Foo
4+
5+ -- Bar
6+ meme = gege
data/examples/other/comment-following-preceding-gap.hsnew file+6
@@ -0,0 +1,6 @@
1+foo = bar
2+ where
3+ baz = return (quux) -- Foo
4+
5+ -- Bar
6+ meme = gege
data/examples/other/comment-glued-together-out.hsnew file+7
@@ -0,0 +1,7 @@
1+module Main (main) where
2+
3+-- | Foo.
4+
5+-- Bar
6+main :: IO ()
7+main = return ()
data/examples/other/comment-glued-together.hsnew file+6
@@ -0,0 +1,6 @@
1+module Main (main) where
2+
3+{- | Foo. -}
4+-- Bar
5+main :: IO ()
6+main = return ()
data/examples/other/comment-inside-construct-out.hsnew file+8
@@ -0,0 +1,8 @@
1+xs =
2+ [ outer list item,
3+ [ inner list first item,
4+ inner list second item
5+ -- inner list last item commented
6+ ],
7+ outer list item
8+ ]
data/examples/other/comment-inside-construct.hsnew file+9
@@ -0,0 +1,9 @@
1+xs =
2+ [ outer list item,
3+ [ inner list first item,
4+ inner list second item
5+ -- inner list last item commented
6+ ],
7+ outer list item
8+ ]
9+
data/examples/other/comment-multiline-after-out.hsnew file+7
@@ -0,0 +1,7 @@
1+foo ::
2+ -- | start index
3+ Int ->
4+ -- | length
5+ Int ->
6+ t a ->
7+ t a
data/examples/other/comment-multiline-after.hsnew file+1
@@ -0,0 +1 @@
1+foo :: Int {- ^ start index -} -> Int {- ^ length -} -> t a -> t a
data/examples/other/comment-style-transform-out.hsnew file+17
@@ -0,0 +1,17 @@
1+-- |
2+-- Module: Data.Aeson.TH
3+-- Copyright: (c) 2011-2016 Bryan O'Sullivan
4+-- (c) 2011 MailRank, Inc.
5+-- License: BSD3
6+-- Stability: experimental
7+-- Portability: portable
8+module Main where
9+
10+-- |
11+--
12+-- Here is a snippet:
13+--
14+-- @
15+-- x = y + 2
16+-- @
17+x = y + 2
data/examples/other/comment-style-transform.hsnew file+22
@@ -0,0 +1,22 @@
1+{-|
2+Module: Data.Aeson.TH
3+Copyright: (c) 2011-2016 Bryan O'Sullivan
4+ (c) 2011 MailRank, Inc.
5+License: BSD3
6+Stability: experimental
7+Portability: portable
8+-}
9+
10+module Main where
11+
12+{- |
13+
14+Here is a snippet:
15+
16+@
17+x = y + 2
18+@
19+
20+-}
21+
22+x = y + 2
data/examples/other/comment-trailing-space-out.hsnew file+9
@@ -0,0 +1,9 @@
1+data T
2+ = {-
3+
4+ some multi-line comment
5+
6+ with empty lines
7+
8+ -}
9+ A
data/examples/other/comment-trailing-space.hsnew file+9
@@ -0,0 +1,9 @@
1+data T
2+ = {-
3+
4+ some multi-line comment
5+
6+ with empty lines
7+
8+ -}
9+ A
data/examples/other/comment-two-blocks-out.hsnew file+8
@@ -0,0 +1,8 @@
1+newNames :: [(String, String)]
2+newNames =
3+ let (*) = flip (,)
4+ in [ "Control" * "Monad"
5+ -- Foo
6+
7+ -- Bar
8+ ]
data/examples/other/comment-two-blocks.hsnew file+9
@@ -0,0 +1,9 @@
1+newNames :: [(String, String)]
2+newNames = let (*) = flip (,) in
3+ ["Control" * "Monad"
4+
5+ -- Foo
6+
7+ -- Bar
8+
9+ ]
data/examples/other/consequetive-pipe-comments-out.hsnew file+7
@@ -0,0 +1,7 @@
1+module Main where
2+
3+-- | Foo.
4+
5+-- | Bar.
6+bar :: Int
7+bar = 5
data/examples/other/consequetive-pipe-comments.hsnew file+8
@@ -0,0 +1,8 @@
1+module Main where
2+
3+-- | Foo.
4+
5+-- | Bar.
6+
7+bar :: Int
8+bar = 5
data/examples/other/cpp/continuation-out.hsnew file+8
@@ -0,0 +1,8 @@
1+foo :: Int
2+foo = 5
3+
4+#define message_for(a, b) \
5+ printf(#a " and " #b ": We love you!\n")
6+
7+bar :: Int
8+bar = 6
data/examples/other/cpp/continuation.hsnew file+8
@@ -0,0 +1,8 @@
1+foo :: Int
2+foo = 5
3+
4+#define message_for(a, b) \
5+ printf(#a " and " #b ": We love you!\n")
6+
7+bar :: Int
8+bar = 6
data/examples/other/cpp/lonely-hash-out.hsnew file+14
@@ -0,0 +1,14 @@
1+module Main (main) where
2+
3+import Data.Void
4+import Test.Hspec
5+import Test.Hspec.Megaparsec
6+import Text.Megaparsec
7+import Text.Megaparsec.Char
8+
9+# if !MIN_VERSION_base(4,13,0)
10+import Data.Semigroup ((<>))
11+# endif
12+
13+main :: IO ()
14+main = return ()
data/examples/other/cpp/lonely-hash.hsnew file+14
@@ -0,0 +1,14 @@
1+module Main (main) where
2+
3+import Data.Void
4+import Test.Hspec
5+import Test.Hspec.Megaparsec
6+import Text.Megaparsec
7+import Text.Megaparsec.Char
8+
9+# if !MIN_VERSION_base(4,13,0)
10+import Data.Semigroup ((<>))
11+# endif
12+
13+main :: IO ()
14+main = return ()
data/examples/other/cpp/separation-0a-out.hsnew file+7
@@ -0,0 +1,7 @@
1+instance Stream s => Monad (ParsecT e s m) where
2+ return = pure
3+ (>>=) = pBind
4+
5+#if !(MIN_VERSION_base(4,13,0))
6+ fail = Fail.fail
7+#endif
data/examples/other/cpp/separation-0a.hsnew file+6
@@ -0,0 +1,6 @@
1+instance Stream s => Monad (ParsecT e s m) where
2+ return = pure
3+ (>>=) = pBind
4+#if !(MIN_VERSION_base(4,13,0))
5+ fail = Fail.fail
6+#endif
data/examples/other/cpp/separation-0b-out.hsnew file+10
@@ -0,0 +1,10 @@
1+instance Stream s => Monad (ParsecT e s m) where
2+ return = pure
3+ (>>=) = pBind
4+
5+#if !(MIN_VERSION_base(4,13,0))
6+ fail = Fail.fail
7+#endif
8+
9+foo :: Int
10+foo = undefined
data/examples/other/cpp/separation-0b.hsnew file+9
@@ -0,0 +1,9 @@
1+instance Stream s => Monad (ParsecT e s m) where
2+ return = pure
3+ (>>=) = pBind
4+#if !(MIN_VERSION_base(4,13,0))
5+ fail = Fail.fail
6+#endif
7+
8+foo :: Int
9+foo = undefined
data/examples/other/cpp/separation-1a-out.hsnew file+12
@@ -0,0 +1,12 @@
1+decompressingPipe ::
2+ (PrimMonad m, MonadThrow m, MonadResource m) =>
3+ CompressionMethod ->
4+ ConduitT ByteString ByteString m ()
5+decompressingPipe Store = C.awaitForever C.yield
6+decompressingPipe Deflate = Z.decompress $ Z.WindowBits (-15)
7+
8+#ifdef ENABLE_BZIP2
9+decompressingPipe BZip2 = BZ.bunzip2
10+#else
11+decompressingPipe BZip2 = throwM BZip2Unsupported
12+#endif
data/examples/other/cpp/separation-1a.hsnew file+11
@@ -0,0 +1,11 @@
1+decompressingPipe
2+ :: (PrimMonad m, MonadThrow m, MonadResource m)
3+ => CompressionMethod
4+ -> ConduitT ByteString ByteString m ()
5+decompressingPipe Store = C.awaitForever C.yield
6+decompressingPipe Deflate = Z.decompress $ Z.WindowBits (-15)
7+#ifdef ENABLE_BZIP2
8+decompressingPipe BZip2 = BZ.bunzip2
9+#else
10+decompressingPipe BZip2 = throwM BZip2Unsupported
11+#endif
data/examples/other/cpp/separation-1b-out.hsnew file+15
@@ -0,0 +1,15 @@
1+decompressingPipe ::
2+ (PrimMonad m, MonadThrow m, MonadResource m) =>
3+ CompressionMethod ->
4+ ConduitT ByteString ByteString m ()
5+decompressingPipe Store = C.awaitForever C.yield
6+decompressingPipe Deflate = Z.decompress $ Z.WindowBits (-15)
7+
8+#ifdef ENABLE_BZIP2
9+decompressingPipe BZip2 = BZ.bunzip2
10+#else
11+decompressingPipe BZip2 = throwM BZip2Unsupported
12+#endif
13+
14+foo :: Int
15+foo = undefined
data/examples/other/cpp/separation-1b.hsnew file+14
@@ -0,0 +1,14 @@
1+decompressingPipe
2+ :: (PrimMonad m, MonadThrow m, MonadResource m)
3+ => CompressionMethod
4+ -> ConduitT ByteString ByteString m ()
5+decompressingPipe Store = C.awaitForever C.yield
6+decompressingPipe Deflate = Z.decompress $ Z.WindowBits (-15)
7+#ifdef ENABLE_BZIP2
8+decompressingPipe BZip2 = BZ.bunzip2
9+#else
10+decompressingPipe BZip2 = throwM BZip2Unsupported
11+#endif
12+
13+foo :: Int
14+foo = undefined
data/examples/other/cpp/separation-2a-out.hsnew file+9
@@ -0,0 +1,9 @@
1+ffff, ffffffff :: Natural
2+
3+#ifdef HASKELL_ZIP_DEV_MODE
4+ffff = 200
5+ffffffff = 5000
6+#else
7+ffff = 0xffff
8+ffffffff = 0xffffffff
9+#endif
data/examples/other/cpp/separation-2a.hsnew file+8
@@ -0,0 +1,8 @@
1+ffff, ffffffff :: Natural
2+#ifdef HASKELL_ZIP_DEV_MODE
3+ffff = 200
4+ffffffff = 5000
5+#else
6+ffff = 0xffff
7+ffffffff = 0xffffffff
8+#endif
data/examples/other/cpp/separation-2b-out.hsnew file+11
@@ -0,0 +1,11 @@
1+ffff, ffffffff :: Natural
2+#ifdef HASKELL_ZIP_DEV_MODE
3+ffff = 200
4+ffffffff = 5000
5+#else
6+ffff = 0xffff
7+ffffffff = 0xffffffff
8+#endif
9+
10+foo :: Int
11+foo = undefined
data/examples/other/cpp/separation-2b.hsnew file+11
@@ -0,0 +1,11 @@
1+ffff, ffffffff :: Natural
2+#ifdef HASKELL_ZIP_DEV_MODE
3+ffff = 200
4+ffffffff = 5000
5+#else
6+ffff = 0xffff
7+ffffffff = 0xffffffff
8+#endif
9+
10+foo :: Int
11+foo = undefined
data/examples/other/cpp/shifted-out.hsnew file+21
@@ -0,0 +1,21 @@
1+sinkData h compression = do
2+ (uncompressedSize, crc32, compressedSize) <-
3+ case compression of
4+ Store ->
5+ withCompression
6+ dataSink
7+ Deflate ->
8+ withCompression $
9+ Z.compress 9 (Z.WindowBits (-15)) .| dataSink
10+#ifdef ENABLE_BZIP2
11+ BZip2 -> withCompression $
12+ BZ.bzip2 .| dataSink
13+#else
14+ BZip2 -> throwM BZip2Unsupported
15+#endif
16+ return
17+ DataDescriptor
18+ { ddCRC32 = fromIntegral crc32,
19+ ddCompressedSize = compressedSize,
20+ ddUncompressedSize = uncompressedSize
21+ }
data/examples/other/cpp/shifted.hsnew file+17
@@ -0,0 +1,17 @@
1+sinkData h compression = do
2+ (uncompressedSize, crc32, compressedSize) <-
3+ case compression of
4+ Store -> withCompression
5+ dataSink
6+ Deflate -> withCompression $
7+ Z.compress 9 (Z.WindowBits (-15)) .| dataSink
8+#ifdef ENABLE_BZIP2
9+ BZip2 -> withCompression $
10+ BZ.bzip2 .| dataSink
11+#else
12+ BZip2 -> throwM BZip2Unsupported
13+#endif
14+ return DataDescriptor
15+ { ddCRC32 = fromIntegral crc32
16+ , ddCompressedSize = compressedSize
17+ , ddUncompressedSize = uncompressedSize }
data/examples/other/cpp/simple-import-out.hsnew file+14
@@ -0,0 +1,14 @@
1+module Main (main) where
2+
3+import Data.Void
4+import Test.Hspec
5+import Test.Hspec.Megaparsec
6+import Text.Megaparsec
7+import Text.Megaparsec.Char
8+
9+#if !MIN_VERSION_base(4,13,0)
10+import Data.Semigroup ((<>))
11+#endif
12+
13+main :: IO ()
14+main = return ()
data/examples/other/cpp/simple-import.hsnew file+14
@@ -0,0 +1,14 @@
1+module Main (main) where
2+
3+import Data.Void
4+import Test.Hspec
5+import Test.Hspec.Megaparsec
6+import Text.Megaparsec
7+import Text.Megaparsec.Char
8+
9+#if !MIN_VERSION_base(4,13,0)
10+import Data.Semigroup ((<>))
11+#endif
12+
13+main :: IO ()
14+main = return ()
data/examples/other/disabling/indented-fragment-out.hsnew file+7
@@ -0,0 +1,7 @@
1+foo =
2+ {- ORMOLU_DISABLE -}
3+ testCase "Foo" testFoo :
4+ testCase "Bar" testBar :
5+ testCase "Baz" testBaz :
6+ {- ORMOLU_ENABLE -}
7+ []
data/examples/other/disabling/indented-fragment.hsnew file+7
@@ -0,0 +1,7 @@
1+foo =
2+ {- ORMOLU_DISABLE -}
3+ testCase "Foo" testFoo :
4+ testCase "Bar" testBar :
5+ testCase "Baz" testBaz :
6+ {- ORMOLU_ENABLE -}
7+ []
data/examples/other/disabling/single-definition-out.hsnew file+10
@@ -0,0 +1,10 @@
1+module Foo (foo, bar) where
2+
3+{- ORMOLU_DISABLE -}
4+foo :: Int -> Int
5+foo = (+5)
6+{- ORMOLU_ENABLE -}
7+
8+bar :: Bool -> Bool
9+bar True = True
10+bar False = True
data/examples/other/disabling/single-definition.hsnew file+10
@@ -0,0 +1,10 @@
1+module Foo (foo,bar) where
2+
3+{- ORMOLU_DISABLE -}
4+foo :: Int -> Int
5+foo = (+5)
6+{- ORMOLU_ENABLE -}
7+
8+bar :: Bool -> Bool
9+bar True = True
10+bar False = True
data/examples/other/disabling/whole-file-out.hsnew file+10
@@ -0,0 +1,10 @@
1+{- ORMOLU_DISABLE -}
2+
3+module Foo (foo,bar) where
4+
5+foo :: Int -> Int
6+foo = (+5)
7+
8+bar :: Bool -> Bool
9+bar True = True
10+bar False = True
data/examples/other/disabling/whole-file.hsnew file+10
@@ -0,0 +1,10 @@
1+{- ORMOLU_DISABLE -}
2+
3+module Foo (foo,bar) where
4+
5+foo :: Int -> Int
6+foo = (+5)
7+
8+bar :: Bool -> Bool
9+bar True = True
10+bar False = True
data/examples/other/empty-forall-out.hsnew file+18
@@ -0,0 +1,18 @@
1+-- Empty foralls are handled correctly in different situations.
2+
3+data D = forall. D Int
4+
5+data G where
6+ G :: forall. Int -> G
7+
8+f :: forall. a -> a
9+f x = x
10+
11+type family T x where
12+ forall. T x = x
13+
14+{-# RULES
15+"r"
16+ r a =
17+ ()
18+ #-}
data/examples/other/empty-forall.hsnew file+17
@@ -0,0 +1,17 @@
1+-- Empty foralls are handled correctly in different situations.
2+
3+data D = forall. D Int
4+
5+data G where
6+ G :: forall. Int -> G
7+
8+f :: forall. a -> a
9+f x = x
10+
11+type family T x where
12+ forall. T x = x
13+
14+{-# RULES
15+ "r"
16+ forall. r a = ()
17+#-}
data/examples/other/empty-haddock-out.hsnew file+5
@@ -0,0 +1,5 @@
1+module Main where
2+
3+-- |
4+foo :: Int
5+foo = 5
data/examples/other/empty-haddock.hsnew file+6
@@ -0,0 +1,6 @@
1+module Main where
2+
3+-- |
4+
5+foo :: Int
6+foo = 5
data/examples/other/following-comment-last-0-out.hsnew file+5
@@ -0,0 +1,5 @@
1+module Main where
2+
3+-- | Another datatype...
4+data D'
5+-- ^ ...with two docstrings.
data/examples/other/following-comment-last-0.hsnew file+5
@@ -0,0 +1,5 @@
1+module Main where
2+
3+-- | Another datatype...
4+data D'
5+-- ^ ...with two docstrings.
data/examples/other/following-comment-last-1-out.hsnew file+8
@@ -0,0 +1,8 @@
1+module Main where
2+
3+-- | Another datatype...
4+data D'
5+ deriving (Show)
6+-- ^ ...with two docstrings.
7+
8+-- more
data/examples/other/following-comment-last-1.hsnew file+8
@@ -0,0 +1,8 @@
1+module Main where
2+
3+-- | Another datatype...
4+data D'
5+ deriving (Show)
6+-- ^ ...with two docstrings.
7+
8+-- more
data/examples/other/following-comment-last-2-out.hsnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+-- | Another datatype...
4+data D'
5+ deriving (Show)
6+-- ^ ...with two docstrings.
7+
8+-- more
9+
10+data B
data/examples/other/following-comment-last-2.hsnew file+10
@@ -0,0 +1,10 @@
1+module Main where
2+
3+-- | Another datatype...
4+data D'
5+ deriving (Show)
6+-- ^ ...with two docstrings.
7+
8+-- more
9+
10+data B
data/examples/other/following-comment-last-3-out.hsnew file+6
@@ -0,0 +1,6 @@
1+module Main where
2+
3+-- | Another datatype...
4+data D'
5+-- ^ ...with two docstrings.
6+-- even on second line
data/examples/other/following-comment-last-3.hsnew file+6
@@ -0,0 +1,6 @@
1+module Main where
2+
3+-- | Another datatype...
4+data D'
5+-- ^ ...with two docstrings.
6+-- even on second line
data/examples/other/haddock-sections-out.hsnew file+7
@@ -0,0 +1,7 @@
1+-- $weird #anchor#
2+--
3+-- Section 1
4+
5+-- $normal
6+--
7+-- Section 2
data/examples/other/haddock-sections.hsnew file+7
@@ -0,0 +1,7 @@
1+-- $weird #anchor#
2+--
3+-- Section 1
4+
5+-- $normal
6+--
7+-- Section 2
data/examples/other/inline-comment-0-out.hsnew file+3
@@ -0,0 +1,3 @@
1+x = ({-a-} b, c)
2+
3+y = ({-a-} b)
data/examples/other/inline-comment-0.hsnew file+3
@@ -0,0 +1,3 @@
1+x = ({-a-}b, c)
2+
3+y = ({-a-}b)
data/examples/other/inline-comment-1-out.hsnew file+12
@@ -0,0 +1,12 @@
1+showPs env ((n, _, Let _ t v) : bs) =
2+ " " ++ show n ++ " : "
3+ ++ showEnv env ({- normalise ctxt env -} t)
4+ ++ " = "
5+ ++ showEnv env ({- normalise ctxt env -} v)
6+ ++ "\n"
7+ ++ showPs env bs
8+showPs env ((n, _, b) : bs) =
9+ " " ++ show n ++ " : "
10+ ++ showEnv env ({- normalise ctxt env -} (binderTy b))
11+ ++ "\n"
12+ ++ showPs env bs
data/examples/other/inline-comment-1.hsnew file+9
@@ -0,0 +1,9 @@
1+showPs env ((n, _, Let _ t v):bs)
2+ = " " ++ show n ++ " : " ++
3+ showEnv env ({- normalise ctxt env -} t) ++ " = " ++
4+ showEnv env ({- normalise ctxt env -} v) ++
5+ "\n" ++ showPs env bs
6+showPs env ((n, _, b):bs)
7+ = " " ++ show n ++ " : " ++
8+ showEnv env ({- normalise ctxt env -} (binderTy b)) ++
9+ "\n" ++ showPs env bs
data/examples/other/merging-comments-out.hsnew file+12
@@ -0,0 +1,12 @@
1+foo xs = baz
2+ where
3+ bar =
4+ catMaybes
5+ [ lookup langKey gets, -- 1
6+ lookup langKey cookies, -- 2
7+ lookupText langKey session -- 3
8+ ]
9+ ++ xs -- 4
10+
11+ -- Blah
12+ baz = addTwoLetters (id, Set.empty) bar
data/examples/other/merging-comments.hsnew file+9
@@ -0,0 +1,9 @@
1+foo xs = baz
2+ where
3+ bar = catMaybes [ lookup langKey gets -- 1
4+ , lookup langKey cookies -- 2
5+ , lookupText langKey session -- 3
6+ ] ++ xs -- 4
7+
8+ -- Blah
9+ baz = addTwoLetters (id, Set.empty) bar
data/examples/other/multiline-comments-reindent-out.hsnew file+6
@@ -0,0 +1,6 @@
1+{-
2+ And so here we have a
3+ multiline comment.
4+
5+ Indeed.
6+-}
data/examples/other/multiline-comments-reindent.hsnew file+6
@@ -0,0 +1,6 @@
1+ {-
2+ And so here we have a
3+ multiline comment.
4+
5+ Indeed.
6+ -}
data/examples/other/multiline-forall-out.hsnew file+58
@@ -0,0 +1,58 @@
1+{-# LANGUAGE GADTs #-}
2+{-# LANGUAGE PolyKinds #-}
3+{-# LANGUAGE RankNTypes #-}
4+{-# LANGUAGE TypeFamilies #-}
5+
6+-- Multiline foralls are consistent across all declarations
7+
8+data D
9+ = forall
10+ ( f ::
11+ * -> * -> *
12+ )
13+ (x :: *)
14+ (y :: *).
15+ D (f x y)
16+
17+data G where
18+ G ::
19+ forall
20+ ( f ::
21+ * -> * -> *
22+ )
23+ (x :: *)
24+ (y :: *).
25+ f x y ->
26+ G
27+
28+f ::
29+ forall
30+ ( f ::
31+ * -> * -> *
32+ )
33+ (x :: *)
34+ (y :: *).
35+ f x y ->
36+ ()
37+f = const ()
38+
39+type family T f x y where
40+ forall
41+ ( f ::
42+ * -> * -> *
43+ )
44+ (x :: *)
45+ (y :: *).
46+ T f x y =
47+ f x y
48+
49+{-# RULES
50+"r" forall
51+ ( f ::
52+ * -> * -> *
53+ )
54+ (x :: *)
55+ (y :: *).
56+ r (a :: f x y) =
57+ ()
58+ #-}
data/examples/other/multiline-forall.hsnew file+46
@@ -0,0 +1,46 @@
1+{-# LANGUAGE RankNTypes, PolyKinds, GADTs, TypeFamilies #-}
2+
3+-- Multiline foralls are consistent across all declarations
4+
5+data D =
6+ forall
7+ (f ::
8+ * -> * -> *)
9+ (x :: *)
10+ (y :: *)
11+ . D (f x y)
12+
13+data G where
14+ G :: forall
15+ (f ::
16+ * -> * -> *)
17+ (x :: *)
18+ (y :: *)
19+ . f x y -> G
20+
21+f :: forall
22+ (f ::
23+ * -> * -> *)
24+ (x :: *)
25+ (y :: *)
26+ . f x y -> ()
27+f = const ()
28+
29+type family T f x y where
30+ forall
31+ (f ::
32+ * -> * -> *)
33+ (x :: *)
34+ (y :: *)
35+ . T f x y = f x y
36+
37+{-# RULES
38+ "r"
39+ forall
40+ (f ::
41+ * -> * -> *)
42+ (x :: *)
43+ (y :: *)
44+ . r (a :: f x y) =
45+ ()
46+ #-}
data/examples/other/multiple-blank-line-comment-out.hsnew file+9
@@ -0,0 +1,9 @@
1+module A where
2+
3+a =
4+ b
5+ [ f
6+ {-,
7+
8+ -}
9+ ]
data/examples/other/multiple-blank-line-comment.hsnew file+10
@@ -0,0 +1,10 @@
1+module A where
2+
3+a =
4+ b
5+ [ f
6+ {-,
7+
8+
9+ -}
10+ ]
data/examples/other/overly-indented-out.hsnew file+11
@@ -0,0 +1,11 @@
1+tagCloudField ::
2+ -- | Destination key
3+ String ->
4+ -- | Smallest font size, in percent
5+ Double ->
6+ -- | Biggest font size, in percent
7+ Double ->
8+ -- | Input tags
9+ Tags ->
10+ -- | Context
11+ Context a
data/examples/other/overly-indented.hsnew file+10
@@ -0,0 +1,10 @@
1+tagCloudField :: String
2+ -- ^ Destination key
3+ -> Double
4+ -- ^ Smallest font size, in percent
5+ -> Double
6+ -- ^ Biggest font size, in percent
7+ -> Tags
8+ -- ^ Input tags
9+ -> Context a
10+ -- ^ Context
data/examples/other/pragma-comments-after-out.hsnew file+4
@@ -0,0 +1,4 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE ConstraintKinds #-}
3+-- TODO: Fix and delete this pragma
4+{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
data/examples/other/pragma-comments-after.hsnew file+3
@@ -0,0 +1,3 @@
1+{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} -- TODO: Fix and delete this pragma
2+{-# LANGUAGE AllowAmbiguousTypes #-}
3+{-# LANGUAGE ConstraintKinds #-}
data/examples/other/pragma-comments-out.hsnew file+8
@@ -0,0 +1,8 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+-- TODO This extension is probably too dangerous, remove it.
3+{-# LANGUAGE RecordWildCards #-}
4+-- Avoid warning produced by TH.
5+{-# OPTIONS_GHC -fno-warn-overlapping-patterns #-}
6+
7+-- | Header comment.
8+module Foo () where
data/examples/other/pragma-comments.hsnew file+11
@@ -0,0 +1,11 @@
1+-- | Header comment.
2+
3+{-# LANGUAGE OverloadedStrings #-}
4+
5+-- Avoid warning produced by TH.
6+{-# OPTIONS_GHC -fno-warn-overlapping-patterns #-}
7+
8+-- TODO This extension is probably too dangerous, remove it.
9+{-# LANGUAGE RecordWildCards #-}
10+
11+module Foo () where
data/examples/other/pragma-no-header-out.hsnew file+3
@@ -0,0 +1,3 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE LambdaCase #-}
3+{-# LANGUAGE ViewPatterns #-}
data/examples/other/pragma-no-header.hsnew file+3
@@ -0,0 +1,3 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGuagE ViewPatterns #-}
3+{-# language DataKinds, LambdaCase #-}
data/examples/other/pragma-out.hsnew file+12
@@ -0,0 +1,12 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE IncoherentInstances #-}
4+{-# LANGUAGE LambdaCase #-}
5+{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE ViewPatterns #-}
7+{-# OPTIONS_GHC -O2 -H 300 #-}
8+{-# OPTIONS_GHC -Wall -Werror #-}
9+{-# OPTIONS_HADDOCK prune, show-extensions #-}
10+
11+-- | Header comment.
12+module Foo () where
data/examples/other/pragma-sorting-out.hsnew file+11
@@ -0,0 +1,11 @@
1+{-# LANGUAGE NondecreasingIndentation #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+{-# LANGUAGE TypeFamilies #-}
4+-- This gap is necessary for stylish Haskell not to re-arrange
5+-- NoMonoLocalBinds before TypeFamilies
6+{-# LANGUAGE NoMonoLocalBinds #-}
7+
8+module Foo
9+ ( bar,
10+ )
11+where
data/examples/other/pragma-sorting.hsnew file+10
@@ -0,0 +1,10 @@
1+{-# LANGUAGE ScopedTypeVariables #-}
2+{-# LANGUAGE TypeFamilies #-}
3+{-# LANGUAGE NondecreasingIndentation #-}
4+-- This gap is necessary for stylish Haskell not to re-arrange
5+-- NoMonoLocalBinds before TypeFamilies
6+{-# LANGUAGE NoMonoLocalBinds #-}
7+
8+module Foo (
9+ bar
10+ ) where
data/examples/other/pragma.hsnew file+13
@@ -0,0 +1,13 @@
1+-- | Header comment.
2+
3+{-# LANGUAGE LambdaCase #-}
4+{-#LANGuagE ViewPatterns #-}
5+{-# LANGUAGE OverloadedStrings#-}
6+{-# OPTIONS_GHC -Wall -Werror #-}
7+{-# language DataKinds, LambdaCase #-}
8+{-# OPTIONS_HADDOCK prune, show-extensions #-}
9+{-# OPTIONS_GHC -O2 -H 300 #-}
10+{-# language IncoherentInstances
11+ , AllowAmbiguousTypes #-}
12+
13+module Foo () where
data/examples/other/trailing-whitespace-out.hsnew file+7
@@ -0,0 +1,7 @@
1+-- Here is a comment with trailing whitespace.
2+foo = 5
3+
4+{- Block comment with trailing whitespace.
5+ Bo.
6+ -}
7+bar = 6
data/examples/other/trailing-whitespace.hsnew file+7
@@ -0,0 +1,7 @@
1+-- Here is a comment with trailing whitespace.
2+foo = 5
3+
4+{- Block comment with trailing whitespace.
5+ Bo.
6+ -}
7+bar = 6
data/printer/list0-multi.hsdeleted−4
@@ -1,4 +0,0 @@
1−[ foo
2−, bar
3−, baz
4−]
data/printer/list0-single.hsdeleted−1
@@ -1 +0,0 @@
1−[foo, bar, baz]
data/printer/list1-multi.hsdeleted−8
@@ -1,8 +0,0 @@
1−[ foo
2−, bar
3−, foo
4− :: ( Int
5− -> Int
6− )
7− -> Bool
8−]
data/printer/list1-single.hsdeleted−1
@@ -1 +0,0 @@
1−[foo, bar, foo :: (Int -> Int) -> Bool]
data/printer/mhdr-multi.hsdeleted−7
@@ -1,7 +0,0 @@
1−module MyModule
2− ( R
3− , runR
4− , txt
5− , blah
6− )
7−where
data/printer/mhdr-single.hsdeleted−3
@@ -1,3 +0,0 @@
1−module MyModule
2− (R, runR, txt, blah)
3−where
data/printer/ssig-multi.hsdeleted−5
@@ -1,5 +0,0 @@
1−foo
2− :: ( Int
3− -> Int
4− )
5− -> Bool
data/printer/ssig-single.hsdeleted−1
@@ -1 +0,0 @@
1−foo :: (Int -> Int) -> Bool
default.nixnew file+169
@@ -0,0 +1,169 @@
1+{ pkgs ? (import ./nix/nixpkgs { inherit system; })
2+, system ? builtins.currentSystem
3+, ormoluCompiler ? "ghc884" # the shell doesn't work with ghc8101 yet
4+}:
5+
6+let
7+ source = pkgs.lib.sourceByRegex ./. [
8+ "^.*\.md$"
9+ "^app.*$"
10+ "^data.*$"
11+ "^ormolu\.cabal$"
12+ "^src.*$"
13+ "^tests.*$"
14+ ];
15+ haskellPackages = pkgs.haskell.packages.${ormoluCompiler}.override {
16+ overrides = ormoluOverlay;
17+ };
18+ ormoluOverlay = self: super: {
19+ "ormolu" = super.callCabal2nixWithOptions "ormolu" source "-fdev" { };
20+ };
21+ ormolize = import ./nix/ormolize {
22+ inherit pkgs;
23+ inherit haskellPackages;
24+ };
25+ expectedFailures = [
26+ "Agda"
27+ "aws"
28+ "distributed-process"
29+ "esqueleto"
30+ "fay"
31+ "hlint"
32+ "idris"
33+ "intero"
34+ "leksah"
35+ "pandoc"
36+ "pipes"
37+ "postgrest"
38+ "purescript"
39+ "tensorflow"
40+ ] ++ (if ormoluCompiler == "ghc8101" then [] else ["lens"]);
41+ ormolizedPackages = doCheck:
42+ pkgs.lib.mapAttrs (name: p: ormolize {
43+ package = p;
44+ inherit doCheck;
45+ expectedFailures =
46+ if pkgs.lib.lists.any (x: x == name) expectedFailures
47+ then ./expected-failures + "/${name}.txt"
48+ else null;
49+ }) haskellPackages;
50+in {
51+ ormolu = haskellPackages.ormolu;
52+ # We put the derivations in another attribute set to avoid building them
53+ # when nix-build is run.
54+ dev = {
55+ ormoluShell =
56+ haskellPackages.shellFor {
57+ packages = ps: [
58+ ps.ormolu
59+ ];
60+ buildInputs = [
61+ haskellPackages.cabal-install
62+ haskellPackages.ghcid
63+ ];
64+ };
65+ withOrmolu = haskellPackages.shellFor {
66+ packages = ps: [];
67+ buildInputs = [
68+ haskellPackages.cabal-install
69+ haskellPackages.ormolu
70+ ];
71+ };
72+ };
73+ inherit ormoluOverlay ormoluCompiler;
74+ hackage = ormolizedPackages false;
75+ hackageTests = with pkgs.lib; pkgs.recurseIntoAttrs (
76+ let ps = [
77+ "Agda"
78+ "QuickCheck"
79+ "ShellCheck"
80+ "aeson"
81+ "attoparsec"
82+ "aws"
83+ "brick"
84+ "capability"
85+ "cassava"
86+ "conduit"
87+ "cryptonite"
88+ "diagrams-core"
89+ "distributed-process"
90+ "esqueleto"
91+ "fay"
92+ "hakyll"
93+ "haxl"
94+ "hedgehog"
95+ "hledger"
96+ "hlint"
97+ "http-client"
98+ "idris"
99+ "intero"
100+ "leksah"
101+ "lens"
102+ "megaparsec"
103+ "optics"
104+ "ormolu"
105+ "pandoc"
106+ "parsec3"
107+ "pipes"
108+ "postgrest"
109+ "purescript"
110+ "servant"
111+ "servant-server"
112+ "stack"
113+ "tensorflow"
114+ "text_1_2_4_0"
115+ "tls"
116+ "yesod-core"
117+ ];
118+ in listToAttrs (map (p: nameValuePair p (ormolizedPackages true).${p}) ps)
119+ );
120+ regionTests = pkgs.stdenv.mkDerivation {
121+ name = "ormolu-region-tests";
122+ src = ./region-tests;
123+ buildInputs = [
124+ haskellPackages.ormolu
125+ pkgs.diffutils
126+ ];
127+ doCheck = true;
128+ buildPhase = ''
129+ cp src.hs result-all-implicit.hs
130+ ormolu --check-idempotence --mode inplace result-all-implicit.hs
131+ cp src.hs result-all-explicit.hs
132+ ormolu --check-idempotence --mode inplace --start-line 1 --end-line 18 result-all-explicit.hs
133+ cp src.hs result-only-start.hs
134+ ormolu --check-idempotence --mode inplace --start-line 1 result-only-start.hs
135+ cp src.hs result-only-end.hs
136+ ormolu --check-idempotence --mode inplace --end-line 18 result-only-end.hs
137+ cp src.hs result-6-7.hs
138+ ormolu --check-idempotence --mode inplace --start-line 6 --end-line 7 result-6-7.hs
139+ cp src.hs result-6-8.hs
140+ ormolu --check-idempotence --mode inplace --start-line 6 --end-line 8 result-6-8.hs
141+ cp src.hs result-9-12.hs
142+ ormolu --check-idempotence --mode inplace --start-line 9 --end-line 12 result-9-12.hs
143+ cp src.hs result-17-18.hs
144+ ormolu --check-idempotence --mode inplace --start-line 17 --end-line 18 result-17-18.hs
145+ '';
146+ checkPhase = ''
147+ echo result-all-implicit.hs
148+ diff --color=always expected-result-all.hs result-all-implicit.hs
149+ echo result-all-explicit.hs
150+ diff --color=always expected-result-all.hs result-all-explicit.hs
151+ echo result-only-start.hs
152+ diff --color=always expected-result-all.hs result-only-start.hs
153+ echo result-only-end.hs
154+ diff --color=always expected-result-all.hs result-only-end.hs
155+ echo result-6-7.hs
156+ diff --color=always expected-result-6-7.hs result-6-7.hs
157+ echo result-6-8.hs
158+ diff --color=always expected-result-6-8.hs result-6-8.hs
159+ echo result-9-12.hs
160+ diff --color=always expected-result-9-12.hs result-9-12.hs
161+ echo result-17-18.hs
162+ diff --color=always expected-result-17-18.hs result-17-18.hs
163+ '';
164+ installPhase = ''
165+ mkdir "$out"
166+ find . -name '*.hs' -exec cp --parents {} $out \;
167+ '';
168+ };
169+}
expected-failures/Agda.txtnew file+11
@@ -0,0 +1,11 @@
1+Formatting is not idempotent:
2+ dist/build/Agda/Syntax/Parser/Lexer.hs<rendered>:1602:17
3+ before: " = (check_ac"
4+ after: " =\n "
5+Please, consider reporting the bug.
6+
7+Formatting is not idempotent:
8+ src/full/Agda/Syntax/Translation/InternalToAbstract.hs<rendered>:769:4
9+ before: " nes\n\n "
10+ after: " nes\n\n -- Andreas"
11+Please, consider reporting the bug.
expected-failures/aws.txtnew file+9
@@ -0,0 +1,9 @@
1+The GHC parser (in Haddock mode) failed:
2+ Examples/PutBucketNearLine.hs:5:1-6
3+ parse error on input `import'
4+
5+The GHC parser (in Haddock mode) failed:
6+ Examples/Sqs.hs:(88,3)-(90,4)
7+ parse error on input `{- | Let's make sure the queue was actually deleted and that the same number of queues exist at when
8+ | the program ends as when it started.
9+ -}'
expected-failures/distributed-process.txtnew file+7
@@ -0,0 +1,7 @@
1+The GHC parser (in Haddock mode) failed:
2+ benchmarks/Channels.hs:2:1-6
3+ parse error on input `import'
4+
5+The GHC parser (in Haddock mode) failed:
6+ benchmarks/Spawns.hs:5:1-6
7+ parse error on input `import'
expected-failures/esqueleto.txtnew file+7
@@ -0,0 +1,7 @@
1+The GHC parser (in Haddock mode) failed:
2+ src/Database/Esqueleto/Internal/Internal.hs:379:1
3+ lexical error in string/character literal at character 's'
4+
5+The GHC parser (in Haddock mode) failed:
6+ test/PostgreSQL/Test.hs:562:9-41
7+ parse error on input `-- | Check the result is not null'
expected-failures/fay.txtnew file+18
@@ -0,0 +1,18 @@
1+The GHC parser (in Haddock mode) failed:
2+ examples/Separated.hs:12:1-6
3+ parse error on input `module'
4+
5+The GHC parser (in Haddock mode) failed:
6+ examples/calc.hs:(4,1)-(6,2)
7+ parse error on input `-- $ fay -p --html-wrapper --html-js-lib jquery.min.js examples/calc.hs
8+-- You also need to download jquery.min.js.
9+--'
10+
11+The GHC parser (in Haddock mode) failed:
12+ examples/canvaswater.hs:(6,1)-(7,17)
13+ parse error on input `-- | A demonstration of Fay using the canvas element to display a
14+-- simple effect.'
15+
16+The GHC parser (in Haddock mode) failed:
17+ examples/data.hs:9:1-6
18+ parse error on input `module'
expected-failures/hlint.txtnew file+11
@@ -0,0 +1,11 @@
1+Formatting is not idempotent:
2+ src/Extension.hs<rendered>:19:22
3+ before: "DoRec , -} Recursive"
4+ after: "DoRec , -}\n "
5+Please, consider reporting the bug.
6+
7+Formatting is not idempotent:
8+ src/Hint/Bracket.hs<rendered>:249:50
9+ before: "\" x y [r]) {ideaSpan"
10+ after: "\" x y [r])\n "
11+Please, consider reporting the bug.
expected-failures/idris.txtnew file+7
@@ -0,0 +1,7 @@
1+The GHC parser (in Haddock mode) failed:
2+ src/Idris/Parser.hs:1052:1
3+ parse error on input `@'
4+
5+The GHC parser (in Haddock mode) failed:
6+ src/Idris/Parser/Expr.hs:75:1
7+ parse error on input `@'
expected-failures/intero.txtnew file+5
@@ -0,0 +1,5 @@
1+Formatting is not idempotent:
2+ src/InteractiveUI.hs<rendered>:3748:33
3+ before: "text \"Try\" <+> doWha"
4+ after: "text \"Try\"\n "
5+Please, consider reporting the bug.
expected-failures/leksah.txtnew file+5
@@ -0,0 +1,5 @@
1+Formatting is not idempotent:
2+ src/IDE/Pane/Modules.hs<rendered>:1184:7
3+ before: "cr\n -- show"
4+ after: "cr\n in -- show"
5+Please, consider reporting the bug.
expected-failures/lens.txtnew file+3
@@ -0,0 +1,3 @@
1+The GHC parser (in Haddock mode) failed:
2+ src/Control/Exception/Lens.hs:180:13-37
3+ parse error on input `AllocationLimitExceeded__'
expected-failures/pandoc.txtnew file+9
@@ -0,0 +1,9 @@
1+The GHC parser (in Haddock mode) failed:
2+ benchmark/weigh-pandoc.hs:14:1-6
3+ parse error on input `import'
4+
5+Formatting is not idempotent:
6+ src/Text/Pandoc/Readers/Vimwiki.hs<rendered>:613:19
7+ before: ".softbreak <$ endlin"
8+ after: ".softbreak\n <$ en"
9+Please, consider reporting the bug.
expected-failures/pipes.txtnew file+3
@@ -0,0 +1,3 @@
1+AST of input and AST of formatted code differ.
2+ at src/Pipes/Core.hs:(128,1)-(151,2)
3+Please, consider reporting the bug.
expected-failures/postgrest.txtnew file+5
@@ -0,0 +1,5 @@
1+Formatting is not idempotent:
2+ src/PostgREST/DbRequestBuilder.hs<rendered>:149:24
3+ before: " || -- clients"
4+ after: " || ( origin ="
5+Please, consider reporting the bug.
expected-failures/purescript.txtnew file+18
@@ -0,0 +1,18 @@
1+The GHC parser (in Haddock mode) failed:
2+ src/Language/PureScript/AST/Declarations.hs:479:1-17
3+ Invalid type signature: pattern ValueDecl :: ...
4+Perhaps you meant to use PatternSynonyms?
5+
6+The GHC parser (in Haddock mode) failed:
7+ src/Language/PureScript/AST/SourcePos.hs:99:1-22
8+ Invalid type signature: pattern NullSourceSpan :: ...
9+Perhaps you meant to use PatternSynonyms?
10+
11+The GHC parser (in Haddock mode) failed:
12+ src/Language/PureScript/Constants.hs:42:1-15
13+ Invalid type signature: pattern Discard :: ...
14+Perhaps you meant to use PatternSynonyms?
15+
16+The GHC parser (in Haddock mode) failed:
17+ src/Language/PureScript/Crash.hs:16:1-6
18+ parse error on input `import'
expected-failures/tensorflow.txtnew file+7
@@ -0,0 +1,7 @@
1+The GHC parser (in Haddock mode) failed:
2+ tensorflow-mnist/app/Main.hs:50:13-14
3+ parse error on input `->'
4+
5+The GHC parser (in Haddock mode) failed:
6+ tensorflow-ops/tests/RegressionTest.hs:3:1-6
7+ parse error on input `import'
format.shnew file+14
@@ -0,0 +1,14 @@
1+#!/usr/bin/env nix-shell
2+#!nix-shell default.nix -A dev.withOrmolu -i bash --pure
3+#
4+# Format Ormolu using current version of Ormolu.
5+
6+set -e
7+
8+export LANG="C.UTF-8"
9+
10+cabal format
11+
12+ormolu -m inplace $(find app -type f -name "*.hs")
13+ormolu -m inplace $(find src -type f \( -name "*.hs" -o -name "*.hs-boot" \))
14+ormolu -m inplace $(find tests -type f -name "*.hs")
nix/nixpkgs/default.nixnew file+13
@@ -0,0 +1,13 @@
1+{ system ? builtins.currentSystem }:
2+let
3+ rev = "32b46dd897ab2143a609988a04d87452f0bbef59";
4+ sha256 = "1gzfrpjnr1bz9zljsyg3a4zrhk8r927sz761mrgcg56dwinkhpjk";
5+ nixpkgs = builtins.fetchTarball {
6+ url = "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz";
7+ inherit sha256;
8+ };
9+ pkgs = import nixpkgs {
10+ inherit system;
11+ config.allowUnfree = true;
12+ };
13+in pkgs
nix/ormolize/default.nixnew file+53
@@ -0,0 +1,53 @@
1+{ pkgs
2+, haskellPackages
3+}:
4+{ package
5+, expectedFailures ? null
6+, doCheck ? false
7+}:
8+ pkgs.stdenv.mkDerivation rec {
9+ name = package.name + "-ormolized";
10+ src = package.src;
11+ buildInputs = [
12+ haskellPackages.cpphs
13+ haskellPackages.ormolu
14+ pkgs.diffutils
15+ pkgs.glibcLocales
16+ ];
17+ LANG = "en_US.UTF-8";
18+ buildPhase = ''
19+ hs_files=$(find . -name '*.hs')
20+ for hs_file in $hs_files; do
21+
22+ # drop includes
23+ sed -i '/^#include/d' "$hs_file"
24+
25+ # deal with CPP
26+ cpphs "$hs_file" --noline -DARCH_X86 > "''${hs_file}-nocpp" 2> /dev/null
27+
28+ # annoyingly, cpphs cannot modify files in place
29+ mv "''${hs_file}-nocpp" "$hs_file"
30+
31+ # preserve the original
32+ cp "$hs_file" "''${hs_file}-original"
33+ done
34+
35+ (ormolu --check-idempotence --mode inplace $hs_files || true) 2> log.txt
36+ '';
37+ inherit doCheck;
38+ checkPhase =
39+ if expectedFailures == null
40+ then ''
41+ echo "No failures expected"
42+ if [[ -s log.txt ]]; then exit 1; fi
43+ ''
44+ else ''
45+ diff --ignore-blank-lines --color=always ${expectedFailures} log.txt
46+ '';
47+ installPhase = ''
48+ mkdir "$out"
49+ find . -name '*.hs-original' -exec cp --parents {} $out \;
50+ find . -name '*.hs' -exec cp --parents {} $out \;
51+ cp log.txt $out/log.txt
52+ '';
53+ }
ormolu.cabal+174−102
@@ -1,112 +1,184 @@
1−name: ormolu
2−version: 0.0.1.0
3−cabal-version: 1.18
1+cabal-version: 1.18
4−tested-with: GHC==8.4.4
2+name: ormolu
3+version: 0.1.2.0
5−license: BSD3
4+license: BSD3
6−license-file: LICENSE.md
5+license-file: LICENSE.md
7−maintainer: Mark Karpov <mark.karpov@tweag.io>
6+maintainer: Mark Karpov <mark.karpov@tweag.io>
7+tested-with: ghc ==8.6.5 ghc ==8.8.4 ghc ==8.10.1
8−homepage: https://github.com/tweag/ormolu
8+homepage: https://github.com/tweag/ormolu
9−bug-reports: https://github.com/tweag/ormolu/issues
9+bug-reports: https://github.com/tweag/ormolu/issues
10+synopsis: A formatter for Haskell source code
11+description: A formatter for Haskell source code.
10−category: Development, Formatting
12+category: Development, Formatting
11−synopsis: A formatter for Haskell source code
12−build-type: Simple
13+build-type: Simple
13−description: A formatter for Haskell source code.
14+data-files:
15+ data/examples/declaration/annotation/*.hs
16+ data/examples/declaration/class/*.hs
17+ data/examples/declaration/data/*.hs
18+ data/examples/declaration/data/gadt/*.hs
19+ data/examples/declaration/default/*.hs
20+ data/examples/declaration/deriving/*.hs
21+ data/examples/declaration/foreign/*.hs
22+ data/examples/declaration/instance/*.hs
23+ data/examples/declaration/rewrite-rule/*.hs
24+ data/examples/declaration/role-annotation/*.hs
25+ data/examples/declaration/signature/complete/*.hs
26+ data/examples/declaration/signature/fixity/*.hs
27+ data/examples/declaration/signature/inline/*.hs
28+ data/examples/declaration/signature/minimal/*.hs
29+ data/examples/declaration/signature/pattern/*.hs
30+ data/examples/declaration/signature/set-cost-centre/*.hs
31+ data/examples/declaration/signature/specialize/*.hs
32+ data/examples/declaration/signature/type/*.hs
33+ data/examples/declaration/splice/*.hs
34+ data/examples/declaration/type-families/closed-type-family/*.hs
35+ data/examples/declaration/type-families/data-family/*.hs
36+ data/examples/declaration/type-families/type-family/*.hs
37+ data/examples/declaration/type-synonyms/*.hs
38+ data/examples/declaration/type/*.hs
39+ data/examples/declaration/value/function/*.hs
40+ data/examples/declaration/value/function/arrow/*.hs
41+ data/examples/declaration/value/function/comprehension/*.hs
42+ data/examples/declaration/value/function/do/*.hs
43+ data/examples/declaration/value/function/infix/*.hs
44+ data/examples/declaration/value/function/pattern/*.hs
45+ data/examples/declaration/value/other/*.hs
46+ data/examples/declaration/value/pattern-synonyms/*.hs
47+ data/examples/declaration/warning/*.hs
48+ data/examples/import/*.hs
49+ data/examples/module-header/*.hs
50+ data/examples/other/*.hs
51+
14−extra-doc-files: CHANGELOG.md
52+extra-doc-files:
53+ CONTRIBUTING.md
54+ CHANGELOG.md
55+ DESIGN.md
15− , README.md
56+ README.md
16−data-files: data/examples/module-header/*.hs
17− , data/printer/*.hs
18
57
19source-repository head
58source-repository head
20− type: git
59+ type: git
21− location: https://github.com/tweag/ormolu.git
60+ location: https://github.com/tweag/ormolu.git
22
61
23flag dev
62flag dev
24− description: Turn on development settings.
63+ description: Turn on development settings.
25− manual: True
26− default: False
64+ default: False
65+ manual: True
27
66
28library
67library
29− hs-source-dirs: src
30− build-depends: base >= 4.8 && < 5.0
31− , containers >= 0.5 && < 0.7
32− , exceptions >= 0.6 && < 0.11
33− , ghc >= 8.4.3
34− , ghc-boot-th >= 8.4.3
35− , ghc-exactprint >= 0.5.6
36− , mtl >= 2.0 && < 3.0
37− , syb >= 0.7 && < 0.8
38− , text >= 0.2 && < 1.3
39− , yaml >= 0.8 && < 0.12
40− exposed-modules: Ormolu
68+ exposed-modules:
41− , Ormolu.Comments
69+ Ormolu
42− , Ormolu.Config
70+ Ormolu.Config
43− , Ormolu.Diff
71+ Ormolu.Diff
44− , Ormolu.Exception
72+ Ormolu.Exception
45− , Ormolu.Imports
73+ Ormolu.Imports
74+ Ormolu.Parser
75+ Ormolu.Parser.Anns
46− , Ormolu.Parser
76+ Ormolu.Parser.CommentStream
77+ Ormolu.Parser.Pragma
78+ Ormolu.Parser.Result
79+ Ormolu.Parser.Shebang
47− , Ormolu.Printer
80+ Ormolu.Printer
48− , Ormolu.Printer.Combinators
81+ Ormolu.Printer.Combinators
49− , Ormolu.Printer.Comments
82+ Ormolu.Printer.Comments
50− , Ormolu.Printer.Internal
83+ Ormolu.Printer.Internal
51− , Ormolu.Printer.Meat.Common
84+ Ormolu.Printer.Meat.Common
85+ Ormolu.Printer.Meat.Declaration
86+ Ormolu.Printer.Meat.Declaration.Annotation
52− , Ormolu.Printer.Meat.Declaration
87+ Ormolu.Printer.Meat.Declaration.Class
53− , Ormolu.Printer.Meat.Declaration.Data
88+ Ormolu.Printer.Meat.Declaration.Data
89+ Ormolu.Printer.Meat.Declaration.Default
54− , Ormolu.Printer.Meat.Declaration.Type
90+ Ormolu.Printer.Meat.Declaration.Foreign
91+ Ormolu.Printer.Meat.Declaration.Instance
92+ Ormolu.Printer.Meat.Declaration.RoleAnnotation
93+ Ormolu.Printer.Meat.Declaration.Rule
94+ Ormolu.Printer.Meat.Declaration.Signature
95+ Ormolu.Printer.Meat.Declaration.Splice
96+ Ormolu.Printer.Meat.Declaration.Type
55− , Ormolu.Printer.Meat.Declaration.TypeFamily
97+ Ormolu.Printer.Meat.Declaration.TypeFamily
98+ Ormolu.Printer.Meat.Declaration.Value
99+ Ormolu.Printer.Meat.Declaration.Warning
56− , Ormolu.Printer.Meat.ImportExport
100+ Ormolu.Printer.Meat.ImportExport
57− , Ormolu.Printer.Meat.Module
101+ Ormolu.Printer.Meat.Module
102+ Ormolu.Printer.Meat.Pragma
58− , Ormolu.Printer.Meat.Type
103+ Ormolu.Printer.Meat.Type
59− if flag(dev)
104+ Ormolu.Printer.Operators
60− ghc-options: -Wall -Werror -Wcompat
105+ Ormolu.Printer.SpanStream
61− -Wincomplete-record-updates
106+ Ormolu.Processing.Common
62− -Wincomplete-uni-patterns
107+ Ormolu.Processing.Cpp
63− -Wnoncanonical-monad-instances
108+ Ormolu.Processing.Postprocess
64− -Wnoncanonical-monadfail-instances
109+ Ormolu.Processing.Preprocess
65− else
110+ Ormolu.Utils
66− ghc-options: -O2 -Wall
67− default-language: Haskell2010
68
111
69−test-suite tests
70− main-is: Spec.hs
71− hs-source-dirs: tests
112+ hs-source-dirs: src
72− type: exitcode-stdio-1.0
113+ other-modules:
114+ GHC
115+ GHC.DynFlags
116+
117+ default-language: Haskell2010
73− build-depends: base >= 4.8 && < 5.0
118+ build-depends:
119+ base >=4.12 && <5.0,
120+ bytestring >=0.2 && <0.11,
74− , containers >= 0.5 && < 0.7
121+ containers >=0.5 && <0.7,
75− , filepath >= 1.2 && < 1.5
122+ dlist >=0.8 && <2.0,
76− , hspec >= 2.0 && < 3.0
123+ exceptions >=0.6 && <0.11,
77− , ormolu
124+ ghc-lib-parser >=8.10 && <8.11,
78− , path >= 0.6 && < 0.7
125+ mtl >=2.0 && <3.0,
79− , path-io >= 1.4.2 && < 2.0
126+ syb >=0.7 && <0.8,
80− , text >= 0.2 && < 1.3
127+ text >=0.2 && <1.3
81− build-tools: hspec-discover >= 2.0 && < 3.0
82− other-modules:
83− Ormolu.Printer.CombinatorsSpec
84− , Ormolu.PrinterSpec
85
128
86− if flag(dev)
129+ if flag(dev)
87− ghc-options: -Wall -Werror
130+ ghc-options:
131+ -Wall -Werror -Wcompat -Wincomplete-record-updates
132+ -Wincomplete-uni-patterns -Wnoncanonical-monad-instances
133+ -Wno-missing-home-modules
134+
88− else
135+ else
89− ghc-options: -O2 -Wall
136+ ghc-options: -O2 -Wall
90− default-language: Haskell2010
91
137
92executable ormolu
138executable ormolu
93− main-is: Main.hs
139+ main-is: Main.hs
94− hs-source-dirs: app
140+ hs-source-dirs: app
141+ other-modules: Paths_ormolu
142+ default-language: Haskell2010
95− build-depends: base >= 4.8 && < 5.0
143+ build-depends:
96− , ghc >= 8.4.3
144+ base >=4.12 && <5.0,
97− , ghc-exactprint >= 0.5.6
145+ ghc-lib-parser >=8.10 && <8.11,
98− , gitrev >= 1.3 && < 1.4
146+ gitrev >=1.3 && <1.4,
99− , optparse-applicative >= 0.14 && < 0.15
147+ optparse-applicative >=0.14 && <0.17,
100− , ormolu
148+ ormolu -any,
101− , text >= 0.2 && < 1.3
149+ text >=0.2 && <1.3
102− , yaml >= 0.8 && < 0.12
150+
103− other-modules: Paths_ormolu
104− if flag(dev)
151+ if flag(dev)
105− ghc-options: -Wall -Werror -Wcompat
152+ ghc-options:
106− -Wincomplete-record-updates
153+ -Wall -Werror -Wcompat -Wincomplete-record-updates
107− -Wincomplete-uni-patterns
108− -Wnoncanonical-monad-instances
154+ -Wincomplete-uni-patterns -Wnoncanonical-monad-instances
109− -Wnoncanonical-monadfail-instances
155+ -optP-Wno-nonportable-include-path
156+
110− else
157+ else
111− ghc-options: -O2 -Wall
158+ ghc-options: -O2 -Wall -rtsopts
159+
160+test-suite tests
161+ type: exitcode-stdio-1.0
162+ main-is: Spec.hs
163+ build-tools: hspec-discover >=2.0 && <3.0
164+ hs-source-dirs: tests
165+ other-modules:
166+ Ormolu.Parser.PragmaSpec
167+ Ormolu.PrinterSpec
168+
112− default-language: Haskell2010
169+ default-language: Haskell2010
170+ build-depends:
171+ base >=4.12 && <5.0,
172+ containers >=0.5 && <0.7,
173+ filepath >=1.2 && <1.5,
174+ hspec >=2.0 && <3.0,
175+ ormolu -any,
176+ path >=0.6 && <0.8,
177+ path-io >=1.4.2 && <2.0,
178+ text >=0.2 && <1.3
179+
180+ if flag(dev)
181+ ghc-options: -Wall -Werror
182+
183+ else
184+ ghc-options: -O2 -Wall
region-tests/expected-result-17-18.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE LambdaCase #-}
2+
3+module Foo (
4+ foo, bar, baz) where
5+
6+foo :: Int
7+foo = 5
8+
9+bar :: Int -> Int
10+bar = \case
11+ 0 -> foo
12+ x -> x - foo
13+
14+baz :: Int -> Int
15+baz = gege
16+ where
17+ gege = 1 + 2
region-tests/expected-result-6-7.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE LambdaCase #-}
2+
3+module Foo (
4+ foo, bar, baz) where
5+
6+foo :: Int
7+foo = 5
8+
9+bar :: Int -> Int
10+bar = \case
11+ 0 -> foo
12+ x -> x - foo
13+
14+baz :: Int -> Int
15+baz = gege
16+ where
17+ gege = 1 + 2
region-tests/expected-result-6-8.hsnew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE LambdaCase #-}
2+
3+module Foo (
4+ foo, bar, baz) where
5+
6+foo :: Int
7+foo = 5
8+bar :: Int -> Int
9+bar = \case
10+ 0 -> foo
11+ x -> x - foo
12+
13+baz :: Int -> Int
14+baz = gege
15+ where
16+ gege = 1 + 2
region-tests/expected-result-9-12.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE LambdaCase #-}
2+
3+module Foo (
4+ foo, bar, baz) where
5+
6+foo :: Int
7+foo = 5
8+
9+bar :: Int -> Int
10+bar = \case
11+ 0 -> foo
12+ x -> x - foo
13+
14+baz :: Int -> Int
15+baz = gege
16+ where
17+ gege = 1 + 2
region-tests/expected-result-all.hsnew file+21
@@ -0,0 +1,21 @@
1+{-# LANGUAGE LambdaCase #-}
2+
3+module Foo
4+ ( foo,
5+ bar,
6+ baz,
7+ )
8+where
9+
10+foo :: Int
11+foo = 5
12+
13+bar :: Int -> Int
14+bar = \case
15+ 0 -> foo
16+ x -> x - foo
17+
18+baz :: Int -> Int
19+baz = gege
20+ where
21+ gege = 1 + 2
region-tests/src.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE LambdaCase #-}
2+
3+module Foo (
4+ foo, bar, baz) where
5+
6+foo :: Int
7+foo = 5
8+
9+bar :: Int -> Int
10+bar = \case
11+ 0 -> foo
12+ x -> x - foo
13+
14+baz :: Int -> Int
15+baz = gege
16+ where
17+ gege = 1 + 2
shell.nixnew file+5
@@ -0,0 +1,5 @@
1+{ pkgs ? (import ./nix/nixpkgs { inherit system; })
2+, system ? builtins.currentSystem
3+}:
4+
5+(import ./default.nix { inherit pkgs; }).dev.ormoluShell
src/GHC.hsnew file+12
@@ -0,0 +1,12 @@
1+module GHC
2+ ( module X,
3+ )
4+where
5+
6+import ApiAnnotation as X
7+import BasicTypes as X
8+import GHC.Hs as X
9+import GHC.Hs.Instances as X ()
10+import Module as X
11+import RdrName as X
12+import SrcLoc as X
src/GHC/DynFlags.hsnew file+49
@@ -0,0 +1,49 @@
1+{-# OPTIONS_GHC -Wno-missing-fields #-}
2+
3+-- Modified from ghc-lib-api-ext.
4+
5+module GHC.DynFlags
6+ ( baseDynFlags,
7+ )
8+where
9+
10+import Config
11+import DynFlags
12+import Fingerprint
13+import GHC.Platform
14+import ToolSettings
15+
16+fakeSettings :: Settings
17+fakeSettings =
18+ Settings
19+ { sGhcNameVersion =
20+ GhcNameVersion
21+ { ghcNameVersion_programName = "ghc",
22+ ghcNameVersion_projectVersion = cProjectVersion
23+ },
24+ sFileSettings = FileSettings {},
25+ sTargetPlatform =
26+ Platform
27+ { platformWordSize = PW8,
28+ platformMini =
29+ PlatformMini
30+ { platformMini_arch = ArchUnknown,
31+ platformMini_os = OSUnknown
32+ },
33+ platformUnregisterised = True
34+ },
35+ sPlatformMisc = PlatformMisc {},
36+ sPlatformConstants =
37+ PlatformConstants {pc_DYNAMIC_BY_DEFAULT = False, pc_WORD_SIZE = 8},
38+ sToolSettings =
39+ ToolSettings
40+ { toolSettings_opt_P_fingerprint = fingerprint0,
41+ toolSettings_pgm_F = ""
42+ }
43+ }
44+
45+fakeLlvmConfig :: LlvmConfig
46+fakeLlvmConfig = LlvmConfig [] []
47+
48+baseDynFlags :: DynFlags
49+baseDynFlags = defaultDynFlags fakeSettings fakeLlvmConfig
src/Ormolu.hs+98−60
@@ -1,33 +1,34 @@
1−-- | A formatter for Haskell source code.
1+{-# LANGUAGE BangPatterns #-}
2−
3−{-# LANGUAGE RecordWildCards #-}
4
2
3+-- | A formatter for Haskell source code.
5module Ormolu
4module Ormolu
6− ( ormolu
5+ ( ormolu,
7− , ormoluFile
6+ ormoluFile,
7+ ormoluStdin,
8− , Config (..)
8+ Config (..),
9+ RegionIndices (..),
9− , defaultConfig
10+ defaultConfig,
10− , DynOption (..)
11+ DynOption (..),
11− , OrmoluException (..)
12+ OrmoluException (..),
12− , withPrettyOrmoluExceptions
13+ withPrettyOrmoluExceptions,
13 )
14 )
14where
15where
15
16
17+import qualified CmdLineParser as GHC
16import Control.Exception
18import Control.Exception
17import Control.Monad
19import Control.Monad
18import Control.Monad.IO.Class (MonadIO (..))
20import Control.Monad.IO.Class (MonadIO (..))
19import Data.Text (Text)
21import Data.Text (Text)
22+import qualified Data.Text as T
20import Debug.Trace
23import Debug.Trace
21−import Language.Haskell.GHC.ExactPrint.Types
22import Ormolu.Config
24import Ormolu.Config
23import Ormolu.Diff
25import Ormolu.Diff
24import Ormolu.Exception
26import Ormolu.Exception
25import Ormolu.Parser
27import Ormolu.Parser
28+import Ormolu.Parser.Result
26import Ormolu.Printer
29import Ormolu.Printer
27−import qualified CmdLineParser as GHC
30+import Ormolu.Utils (showOutputable)
28−import qualified Data.Text as T
29−import qualified GHC
31+import qualified SrcLoc as GHC
30−import qualified Outputable as GHC
31
32
32-- | Format a 'String', return formatted version as 'Text'.
33-- | Format a 'String', return formatted version as 'Text'.
33--
34--
@@ -39,29 +40,52 @@ import qualified Outputable as GHC
39-- side-effects though.
40-- side-effects though.
40-- * Takes file name just to use it in parse error messages.
41-- * Takes file name just to use it in parse error messages.
41-- * Throws 'OrmoluException'.
42-- * Throws 'OrmoluException'.
42−
43−ormolu
43+ormolu ::
44− :: MonadIO m
44+ MonadIO m =>
45− => Config -- ^ Ormolu configuration
45+ -- | Ormolu configuration
46+ Config RegionIndices ->
46− -> FilePath -- ^ Location of source file
47+ -- | Location of source file
48+ FilePath ->
47− -> String -- ^ Input to format
49+ -- | Input to format
50+ String ->
48− -> m Text
51+ m Text
49−ormolu cfg path str = do
52+ormolu cfgWithIndices path str = do
50− (ws, (anns0, parsedSrc0)) <-
53+ let totalLines = length (lines str)
54+ cfg = regionIndicesToDeltas totalLines <$> cfgWithIndices
55+ (warnings, result0) <-
51 parseModule' cfg OrmoluParsingFailed path str
56 parseModule' cfg OrmoluParsingFailed path str
52 when (cfgDebug cfg) $ do
57 when (cfgDebug cfg) $ do
53 traceM "warnings:\n"
58 traceM "warnings:\n"
54− traceM (concatMap showWarn ws)
59+ traceM (concatMap showWarn warnings)
55− traceM "anns:\n"
60+ traceM (prettyPrintParseResult result0)
56− traceM (showOutputable anns0)
61+ -- We're forcing 'txt' here because otherwise errors (such as messages
62+ -- about not-yet-supported functionality) will be thrown later when we try
63+ -- to parse the rendered code back, inside of GHC monad wrapper which will
64+ -- lead to error messages presenting the exceptions as GHC bugs.
57− let txt = printModule (cfgDebug cfg) anns0 parsedSrc0
65+ let !txt = printModule result0
66+ when (not (cfgUnsafe cfg) || cfgCheckIdempotence cfg) $ do
67+ let pathRendered = path ++ "<rendered>"
58− -- Parse the result of pretty-printing again and make sure that AST is the
68+ -- Parse the result of pretty-printing again and make sure that AST
59− -- same as AST of original snippet module span positions.
69+ -- is the same as AST of original snippet module span positions.
60− unless (cfgUnsafe cfg) $ do
70+ (_, result1) <-
61− (_, (anns1, parsedSrc1)) <-
71+ parseModule'
72+ cfg
62− parseModule' cfg OrmoluOutputParsingFailed "<rendered>" (T.unpack txt)
73+ OrmoluOutputParsingFailed
63− when (diff (anns0, parsedSrc0) (anns1, parsedSrc1)) $
74+ pathRendered
75+ (T.unpack txt)
76+ unless (cfgUnsafe cfg) $
77+ case diffParseResult result0 result1 of
78+ Same -> return ()
64− liftIO $ throwIO (OrmoluASTDiffers str txt)
79+ Different ss -> liftIO $ throwIO (OrmoluASTDiffers path ss)
80+ -- Try re-formatting the formatted result to check if we get exactly
81+ -- the same output.
82+ when (cfgCheckIdempotence cfg) $
83+ let txt2 = printModule result1
84+ in case diffText txt txt2 pathRendered of
85+ Nothing -> return ()
86+ Just (loc, l, r) ->
87+ liftIO $
88+ throwIO (OrmoluNonIdempotentOutput loc l r)
65 return txt
89 return txt
66
90
67-- | Load a file and format it. The file stays intact and the rendered
91-- | Load a file and format it. The file stays intact and the rendered
@@ -69,41 +93,55 @@ ormolu cfg path str = do
69--
93--
70-- > ormoluFile cfg path =
94-- > ormoluFile cfg path =
71-- > liftIO (readFile path) >>= ormolu cfg path
95-- > liftIO (readFile path) >>= ormolu cfg path
72−
73−ormoluFile
96+ormoluFile ::
74− :: MonadIO m
97+ MonadIO m =>
75− => Config -- ^ Ormolu configuration
98+ -- | Ormolu configuration
99+ Config RegionIndices ->
76− -> FilePath -- ^ Location of source file
100+ -- | Location of source file
101+ FilePath ->
77− -> m Text -- ^ Resulting rendition
102+ -- | Resulting rendition
103+ m Text
78ormoluFile cfg path =
104ormoluFile cfg path =
79 liftIO (readFile path) >>= ormolu cfg path
105 liftIO (readFile path) >>= ormolu cfg path
80
106
107+-- | Read input from stdin and format it.
108+--
109+-- > ormoluStdin cfg =
110+-- > liftIO (hGetContents stdin) >>= ormolu cfg "<stdin>"
111+ormoluStdin ::
112+ MonadIO m =>
113+ -- | Ormolu configuration
114+ Config RegionIndices ->
115+ -- | Resulting rendition
116+ m Text
117+ormoluStdin cfg =
118+ liftIO getContents >>= ormolu cfg "<stdin>"
119+
81----------------------------------------------------------------------------
120----------------------------------------------------------------------------
82-- Helpers
121-- Helpers
83
122
84-- | A wrapper around 'parseModule'.
123-- | A wrapper around 'parseModule'.
85−
86−parseModule'
124+parseModule' ::
87− :: MonadIO m
125+ MonadIO m =>
88− => Config -- ^ Ormolu configuration
126+ -- | Ormolu configuration
89− -> (GHC.SrcSpan -> String -> OrmoluException)
127+ Config RegionDeltas ->
90− -- ^ How to obtain 'OrmoluException' to throw when parsing fails
128+ -- | How to obtain 'OrmoluException' to throw when parsing fails
129+ (GHC.SrcSpan -> String -> OrmoluException) ->
91− -> FilePath -- ^ File name to use in errors
130+ -- | File name to use in errors
131+ FilePath ->
92− -> String -- ^ Actual input for the parser
132+ -- | Actual input for the parser
93− -> m ([GHC.Warn], (Anns, GHC.ParsedSource)) -- ^ Annotations and parsed source
133+ String ->
134+ m ([GHC.Warn], ParseResult)
94−parseModule' Config {..} mkException path str = do
135+parseModule' cfg mkException path str = do
95− (ws, r) <- parseModule cfgDynOptions path str
136+ (warnings, r) <- parseModule cfg path str
96 case r of
137 case r of
97 Left (spn, err) -> liftIO $ throwIO (mkException spn err)
138 Left (spn, err) -> liftIO $ throwIO (mkException spn err)
98− Right x -> return (ws, x)
139+ Right x -> return (warnings, x)
99
140
100-- | Pretty-print a 'GHC.Warn'.
141-- | Pretty-print a 'GHC.Warn'.
101−
102showWarn :: GHC.Warn -> String
142showWarn :: GHC.Warn -> String
103showWarn (GHC.Warn reason l) =
143showWarn (GHC.Warn reason l) =
144+ unlines
104− showOutputable reason ++ "\n" ++ showOutputable l ++ "\n"
145+ [ showOutputable reason,
105−
146+ showOutputable l
106−-- | Pretty-print an 'GHC.Outputable' thing.
147+ ]
107−
108−showOutputable :: GHC.Outputable o => o -> String
109−showOutputable = GHC.showSDocUnsafe . GHC.ppr
src/Ormolu/Comments.hsdeleted−33
@@ -1,33 +0,0 @@
1−-- | Various functions for manipulation of 'Comment's.
2−
3−module Ormolu.Comments
4− ( annComment
5− , normalizeComment
6− )
7−where
8−
9−import Data.List (isPrefixOf)
10−import Language.Haskell.GHC.ExactPrint.Types
11−
12−-- | If 'KeywordId' is a comment, extract it.
13−
14−annComment :: KeywordId -> Maybe Comment
15−annComment (AnnComment x) = Just x
16−annComment _ = Nothing
17−
18−-- | Normalize comment string. Sometimes one multi-line comment is turned
19−-- into several lines for subsequent outputting with correct indentation for
20−-- each line.
21−
22−normalizeComment :: String -> [String]
23−normalizeComment s =
24− if isMultiline s
25− then if isPragma s
26− then [normalizePragma s]
27− else normalizeIndent s
28− else [s]
29− where
30− isMultiline x = not ("--" `isPrefixOf` x)
31− isPragma x = "{-#" `isPrefixOf` x
32− normalizeIndent = fmap (dropWhile (== ' ')) . lines
33− normalizePragma = unwords . words
src/Ormolu/Config.hs+69−45
@@ -1,65 +1,89 @@
1−-- | Configuration options used by the tool.
1+{-# LANGUAGE DeriveFunctor #-}
2−
3−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4−{-# LANGUAGE OverloadedStrings #-}
5−{-# LANGUAGE RecordWildCards #-}
2+{-# LANGUAGE RecordWildCards #-}
6
3
4+-- | Configuration options used by the tool.
7module Ormolu.Config
5module Ormolu.Config
8− ( Config (..)
6+ ( Config (..),
7+ RegionIndices (..),
8+ RegionDeltas (..),
9− , defaultConfig
9+ defaultConfig,
10+ regionIndicesToDeltas,
10− , DynOption (..)
11+ DynOption (..),
11− , dynOptionToLocatedStr
12+ dynOptionToLocatedStr,
12 )
13 )
13where
14where
14
15
15−import Data.Yaml
16import qualified SrcLoc as GHC
16import qualified SrcLoc as GHC
17
17
18-- | Ormolu configuration.
18-- | Ormolu configuration.
19+data Config region = Config
20+ { -- | Dynamic options to pass to GHC parser
21+ cfgDynOptions :: ![DynOption],
22+ -- | Do formatting faster but without automatic detection of defects
23+ cfgUnsafe :: !Bool,
24+ -- | Output information useful for debugging
25+ cfgDebug :: !Bool,
26+ -- | Checks if re-formatting the result is idempotent
27+ cfgCheckIdempotence :: !Bool,
28+ -- | Region selection
29+ cfgRegion :: !region
30+ }
31+ deriving (Eq, Show, Functor)
19
32
20−data Config = Config
33+-- | Region selection as the combination of start and end line numbers.
21− { cfgDynOptions :: ![DynOption]
34+data RegionIndices = RegionIndices
22− -- ^ Dynamic options to pass to GHC parser
35+ { -- | Start line of the region to format
23− , cfgUnsafe :: !Bool
36+ regionStartLine :: !(Maybe Int),
24− -- ^ Do formatting faster but without automatic detection of defects
37+ -- | End line of the region to format
25− , cfgDebug :: !Bool
38+ regionEndLine :: !(Maybe Int)
26− -- ^ Output information useful for debugging
39+ }
27− } deriving (Eq, Show)
40+ deriving (Eq, Show)
28−
29−instance Semigroup Config where
30− a <> b = Config
31− { cfgDynOptions = cfgDynOptions a <> cfgDynOptions b
32− , cfgUnsafe = cfgUnsafe a || cfgUnsafe b
33− , cfgDebug = cfgDebug a || cfgDebug b
34− }
35−
36−instance Monoid Config where
37− mempty = defaultConfig
38− mappend = (<>)
39
41
40−instance FromJSON Config where
42+-- | Region selection as the length of the literal prefix and the literal
41− parseJSON = withObject "config" $ \o -> do
43+-- suffix.
42− cfgDynOptions <- o .: "ghc-opts"
44+data RegionDeltas = RegionDeltas
43− cfgUnsafe <- o .: "unsafe"
45+ { -- | Prefix length in number of lines
44− cfgDebug <- o .: "debug"
46+ regionPrefixLength :: !Int,
45− return Config {..}
47+ -- | Suffix length in number of lines
48+ regionSuffixLength :: !Int
49+ }
50+ deriving (Eq, Show)
46
51
47−-- | Default 'Config'.
52+-- | Default @'Config' 'RegionIndices'@.
53+defaultConfig :: Config RegionIndices
54+defaultConfig =
55+ Config
56+ { cfgDynOptions = [],
57+ cfgUnsafe = False,
58+ cfgDebug = False,
59+ cfgCheckIdempotence = False,
60+ cfgRegion =
61+ RegionIndices
62+ { regionStartLine = Nothing,
63+ regionEndLine = Nothing
64+ }
65+ }
48
66
49−defaultConfig :: Config
67+-- | Convert 'RegionIndices' into 'RegionDeltas'.
50−defaultConfig = Config
68+regionIndicesToDeltas ::
51− { cfgDynOptions = []
69+ -- | Total number of lines in the input
52− , cfgUnsafe = False
70+ Int ->
53− , cfgDebug = False
71+ -- | Region indices
72+ RegionIndices ->
73+ -- | Region deltas
74+ RegionDeltas
75+regionIndicesToDeltas total RegionIndices {..} =
76+ RegionDeltas
77+ { regionPrefixLength = maybe 0 (subtract 1) regionStartLine,
78+ regionSuffixLength = maybe 0 (total -) regionEndLine
54− }
79+ }
55
80
56-- | A wrapper for dynamic options.
81-- | A wrapper for dynamic options.
57−
58newtype DynOption = DynOption
82newtype DynOption = DynOption
59 { unDynOption :: String
83 { unDynOption :: String
84+ }
60− } deriving (Eq, Ord, Show, FromJSON)
85+ deriving (Eq, Ord, Show)
61
86
62-- | Convert 'DynOption' to @'GHC.Located' 'String'@.
87-- | Convert 'DynOption' to @'GHC.Located' 'String'@.
63−
64dynOptionToLocatedStr :: DynOption -> GHC.Located String
88dynOptionToLocatedStr :: DynOption -> GHC.Located String
65dynOptionToLocatedStr (DynOption o) = GHC.L GHC.noSrcSpan o
89dynOptionToLocatedStr (DynOption o) = GHC.L GHC.noSrcSpan o
src/Ormolu/Diff.hs+143−57
@@ -1,72 +1,158 @@
1−{-# LANGUAGE DeriveDataTypeable #-}
2−{-# LANGUAGE RankNTypes #-}
1+{-# LANGUAGE RankNTypes #-}
3−{-# LANGUAGE RecordWildCards #-}
4
2
5-- | Diffing GHC ASTs modulo span positions.
3-- | Diffing GHC ASTs modulo span positions.
6−
7module Ormolu.Diff
4module Ormolu.Diff
8− ( diff
5+ ( Diff (..),
6+ diffParseResult,
7+ diffText,
9 )
8 )
10where
9where
11
10
11+import Data.ByteString (ByteString)
12import Data.Generics
12import Data.Generics
13−import Data.Maybe (mapMaybe)
13+import Data.Text (Text)
14−import GHC hiding (GhcPs)
14+import qualified Data.Text as T
15−import Language.Haskell.GHC.ExactPrint.Types
15+import qualified FastString as GHC
16−import Ormolu.Comments
16+import GHC
17−import Ormolu.Imports (sortImports)
17+import Ormolu.Imports (normalizeImports)
18−import qualified Data.Map.Strict as M
18+import Ormolu.Parser.CommentStream
19+import Ormolu.Parser.Result
20+import Ormolu.Utils
21+
22+-- | Result of comparing two 'ParseResult's.
23+data Diff
24+ = -- | Two parse results are the same
25+ Same
26+ | -- | Two parse results differ
27+ Different [SrcSpan]
19
28
20−-- | Return 'False' if two annotated ASTs are the same modulo span
29+instance Semigroup Diff where
21−-- positions.
30+ Same <> a = a
31+ a <> Same = a
32+ Different xs <> Different ys = Different (xs ++ ys)
22
33
23−diff
34+instance Monoid Diff where
24− :: (Anns, ParsedSource) -- ^ First annotated AST
35+ mempty = Same
25− -> (Anns, ParsedSource) -- ^ Second annotated AST
26− -> Bool
27−diff (anns0, ps0) (anns1, ps1) =
28− not (matchIgnoringSrcSpans (simplifyAnns anns0) (simplifyAnns anns1))
29− || not (matchIgnoringSrcSpans ps0 ps1)
30
36
31−-- | Compare two 'ParsedSource' values disregarding differences in
37+-- | Return 'Diff' of two 'ParseResult's.
32−-- 'SrcSpan's and the ordering of import lists.
38+diffParseResult :: ParseResult -> ParseResult -> Diff
39+diffParseResult
40+ ParseResult
41+ { prCommentStream = cstream0,
42+ prParsedSource = hs0
43+ }
44+ ParseResult
45+ { prCommentStream = cstream1,
46+ prParsedSource = hs1
47+ } =
48+ matchIgnoringSrcSpans cstream0 cstream1
49+ <> matchIgnoringSrcSpans
50+ hs0 {hsmodImports = normalizeImports (hsmodImports hs0)}
51+ hs1 {hsmodImports = normalizeImports (hsmodImports hs1)}
33
52
53+-- | Compare two values for equality disregarding differences in 'SrcSpan's
54+-- and the ordering of import lists.
34−matchIgnoringSrcSpans :: Data a => a -> a -> Bool
55+matchIgnoringSrcSpans :: Data a => a -> a -> Diff
35matchIgnoringSrcSpans = genericQuery
56matchIgnoringSrcSpans = genericQuery
36 where
57 where
37− genericQuery :: GenericQ (GenericQ Bool)
58+ genericQuery :: GenericQ (GenericQ Diff)
38− genericQuery x y = (toConstr x == toConstr y)
59+ genericQuery x y
39− && and (gzipWithQ (genericQuery `extQ` srcSpanEq `extQ` hsModuleEq) x y)
60+ -- 'ByteString' implements 'Data' instance manually and does not
40−
61+ -- implement 'toConstr', so we have to deal with it in a special way.
62+ | Just x' <- cast x,
63+ Just y' <- cast y =
64+ if x' == (y' :: ByteString)
65+ then Same
66+ else Different []
67+ | typeOf x == typeOf y,
68+ toConstr x == toConstr y =
69+ mconcat $
70+ gzipWithQ
71+ ( genericQuery
72+ `extQ` srcSpanEq
73+ `extQ` commentEq
74+ `extQ` sourceTextEq
75+ `extQ` hsDocStringEq
76+ `extQ` importDeclQualifiedStyleEq
77+ `ext2Q` forLocated
78+ )
79+ x
80+ y
81+ | otherwise = Different []
41− srcSpanEq :: SrcSpan -> GenericQ Bool
82+ srcSpanEq :: SrcSpan -> GenericQ Diff
42− srcSpanEq _ _ = True
83+ srcSpanEq _ _ = Same
43−
84+ commentEq :: Comment -> GenericQ Diff
44− hsModuleEq :: HsModule GhcPs -> GenericQ Bool
85+ commentEq (Comment _ x) d =
45− hsModuleEq hs0 hs1' =
46− case cast hs1' :: Maybe (HsModule GhcPs) of
86+ case cast d :: Maybe Comment of
47− Nothing -> False
87+ Nothing -> Different []
48− Just hs1 ->
88+ Just (Comment _ y) ->
49− matchIgnoringSrcSpans
89+ if x == y
50− hs0 { hsmodImports = sortImports (hsmodImports hs0) }
90+ then Same
51− hs1 { hsmodImports = sortImports (hsmodImports hs1) }
91+ else Different []
52−
92+ sourceTextEq :: SourceText -> GenericQ Diff
53−-- | Simplified collection of 'Comment's.
93+ sourceTextEq _ _ = Same
54−
94+ importDeclQualifiedStyleEq :: ImportDeclQualifiedStyle -> GenericQ Diff
55−data Comments = Comments [Comment] [Comment] [Comment]
95+ importDeclQualifiedStyleEq d0 d1' =
56− deriving (Show, Typeable, Data)
96+ case (d0, cast d1' :: Maybe ImportDeclQualifiedStyle) of
57−
97+ (x, Just x') | x == x' -> Same
58−-- | Simplify a collection of annotations.
98+ (QualifiedPre, Just QualifiedPost) -> Same
59−
99+ (QualifiedPost, Just QualifiedPre) -> Same
60−simplifyAnns :: Anns -> [Comments]
100+ _ -> Different []
61−simplifyAnns = fmap simplifyAnn . M.elems
101+ hsDocStringEq :: HsDocString -> GenericQ Diff
62−
102+ hsDocStringEq str0 str1' =
63−-- | Simplify single annotation.
103+ case cast str1' :: Maybe HsDocString of
104+ Nothing -> Different []
105+ Just str1 ->
106+ if splitDocString str0 == splitDocString str1
107+ then Same
108+ else Different []
109+ forLocated ::
110+ (Data e0, Data e1) =>
111+ GenLocated e0 e1 ->
112+ GenericQ Diff
113+ forLocated x@(L mspn _) y =
114+ maybe id appendSpan (cast mspn) (genericQuery x y)
115+ appendSpan :: SrcSpan -> Diff -> Diff
116+ appendSpan s (Different ss) | fresh && helpful = Different (s : ss)
117+ where
118+ fresh = not $ any (`isSubspanOf` s) ss
119+ helpful = isGoodSrcSpan s
120+ appendSpan _ d = d
64
121
65−simplifyAnn :: Annotation -> Comments
122+-- | Diff two texts and return the location they start to differ, alongside
66−simplifyAnn Ann {..} = Comments
123+-- with excerpts around that location.
67− (f . fst <$> annPriorComments)
124+diffText ::
68− (f . fst <$> annFollowingComments)
125+ -- | Text before
69− (mapMaybe (fmap f . annComment) (fst <$> annsDP))
126+ Text ->
127+ -- | Text after
128+ Text ->
129+ -- | Path to use to construct 'GHC.RealSrcLoc'
130+ FilePath ->
131+ Maybe (GHC.RealSrcLoc, Text, Text)
132+diffText left right fp =
133+ case go (0, 0, 0) left right of
134+ Nothing -> Nothing
135+ Just (row, col, loc) ->
136+ Just
137+ ( GHC.mkRealSrcLoc (GHC.mkFastString fp) row col,
138+ getSpan loc left,
139+ getSpan loc right
140+ )
70 where
141 where
71− f (Comment str i o) =
142+ go (row, col, loc) t1 t2 =
72− Comment (unlines $ normalizeComment str) i o
143+ case (T.uncons t1, T.uncons t2) of
144+ -- both text empty, all good
145+ (Nothing, Nothing) ->
146+ Nothing
147+ -- first chars are the same, adjust position and recurse
148+ (Just (c1, r1), Just (c2, r2))
149+ | c1 == c2 ->
150+ let (row', col', loc') =
151+ if c1 == '\n'
152+ then (row + 1, 0, loc + 1)
153+ else (row, col + 1, loc + 1)
154+ in go (row', col', loc') r1 r2
155+ -- something is different, return the position
156+ _ ->
157+ Just (row, col, loc)
158+ getSpan loc = T.take 20 . T.drop (loc - 10)
src/Ormolu/Exception.hs+67−41
@@ -1,73 +1,99 @@
1−-- | 'OrmoluException' type and surrounding definitions.
2−
3{-# LANGUAGE LambdaCase #-}
1{-# LANGUAGE LambdaCase #-}
4
2
3+-- | 'OrmoluException' type and surrounding definitions.
5module Ormolu.Exception
4module Ormolu.Exception
6− ( OrmoluException (..)
5+ ( OrmoluException (..),
7− , withPrettyOrmoluExceptions
6+ withPrettyOrmoluExceptions,
8 )
7 )
9where
8where
10
9
11import Control.Exception
10import Control.Exception
11+import Data.List.NonEmpty (NonEmpty (..))
12+import qualified Data.List.NonEmpty as NE
12import Data.Text (Text)
13import Data.Text (Text)
13−import System.Exit (exitFailure)
14−import System.IO
15import qualified GHC
14import qualified GHC
15+import Ormolu.Utils (showOutputable)
16import qualified Outputable as GHC
16import qualified Outputable as GHC
17+import System.Exit (ExitCode (..), exitWith)
18+import System.IO
17
19
18−-- | Ormolu exception representing all cases when 'ormoluFile' can fail.
20+-- | Ormolu exception representing all cases when Ormolu can fail.
19−
20data OrmoluException
21data OrmoluException
21− = OrmoluCppEnabled
22+ = -- | Parsing of original source code failed
22− -- ^ Ormolu does not work with source files that use CPP
23− | OrmoluParsingFailed GHC.SrcSpan String
23+ OrmoluParsingFailed GHC.SrcSpan String
24− -- ^ Parsing of original source code failed
25− | OrmoluOutputParsingFailed GHC.SrcSpan String
26− -- ^ Parsing of formatted source code failed
24+ | -- | Parsing of formatted source code failed
27− | OrmoluASTDiffers String Text
25+ OrmoluOutputParsingFailed GHC.SrcSpan String
28− -- ^ Original and resulting ASTs differ, first argument is the original
26+ | -- | Original and resulting ASTs differ
29− -- source code, second argument is rendered source code
27+ OrmoluASTDiffers FilePath [GHC.SrcSpan]
28+ | -- | Formatted source code is not idempotent
29+ OrmoluNonIdempotentOutput GHC.RealSrcLoc Text Text
30+ | -- | Some GHC options were not recognized
31+ OrmoluUnrecognizedOpts (NonEmpty String)
30 deriving (Eq, Show)
32 deriving (Eq, Show)
31
33
32instance Exception OrmoluException where
34instance Exception OrmoluException where
33 displayException = \case
35 displayException = \case
34− OrmoluCppEnabled -> "CPP is not supported"
35 OrmoluParsingFailed s e ->
36 OrmoluParsingFailed s e ->
36− showParsingErr "Parsing of source code failed:" s e
37+ showParsingErr "The GHC parser (in Haddock mode) failed:" s [e]
37 OrmoluOutputParsingFailed s e ->
38 OrmoluOutputParsingFailed s e ->
38− showParsingErr "Parsing of formatted code failed:" s e ++
39+ showParsingErr "Parsing of formatted code failed:" s [e]
39− "Please, consider reporting the bug."
40+ ++ "Please, consider reporting the bug.\n"
40− OrmoluASTDiffers _ _ -> unlines
41+ OrmoluASTDiffers path ss ->
42+ unlines $
41− [ "AST of input and AST of formatted code differ."
43+ [ "AST of input and AST of formatted code differ."
44+ ]
45+ ++ fmap
46+ withIndent
47+ ( case fmap (\s -> "at " ++ showOutputable s) ss of
48+ [] -> ["in " ++ path]
49+ xs -> xs
50+ )
51+ ++ ["Please, consider reporting the bug."]
52+ OrmoluNonIdempotentOutput loc left right ->
53+ showParsingErr
54+ "Formatting is not idempotent:"
55+ loc
56+ ["before: " ++ show left, "after: " ++ show right]
42− , "Please, consider reporting the bug."
57+ ++ "Please, consider reporting the bug.\n"
58+ OrmoluUnrecognizedOpts opts ->
59+ unlines
60+ [ "The following GHC options were not recognized:",
61+ (withIndent . unwords . NE.toList) opts
43− ]
62+ ]
44
63
45-- | Inside this wrapper 'OrmoluException' will be caught and displayed
64-- | Inside this wrapper 'OrmoluException' will be caught and displayed
46-- nicely using 'displayException'.
65-- nicely using 'displayException'.
47−
48−withPrettyOrmoluExceptions
66+withPrettyOrmoluExceptions ::
49− :: IO a -- ^ Action that may throw the exception
67+ -- | Action that may throw the exception
68+ IO a ->
50− -> IO a
69+ IO a
51withPrettyOrmoluExceptions m = m `catch` h
70withPrettyOrmoluExceptions m = m `catch` h
52 where
71 where
53 h :: OrmoluException -> IO a
72 h :: OrmoluException -> IO a
54 h e = do
73 h e = do
55 hPutStrLn stderr (displayException e)
74 hPutStrLn stderr (displayException e)
56− exitFailure
75+ exitWith . ExitFailure $
76+ case e of
77+ -- Error code 1 is for 'error' or 'notImplemented'
78+ -- 2 used to be for erroring out on CPP
79+ OrmoluParsingFailed {} -> 3
80+ OrmoluOutputParsingFailed {} -> 4
81+ OrmoluASTDiffers {} -> 5
82+ OrmoluNonIdempotentOutput {} -> 6
83+ OrmoluUnrecognizedOpts {} -> 7
57
84
58----------------------------------------------------------------------------
85----------------------------------------------------------------------------
59-- Helpers
86-- Helpers
60
87
61-- | Show a parse error.
88-- | Show a parse error.
89+showParsingErr :: GHC.Outputable a => String -> a -> [String] -> String
90+showParsingErr msg spn err =
91+ unlines $
92+ [ msg,
93+ withIndent (showOutputable spn)
94+ ]
95+ ++ map withIndent err
62
96
63−showParsingErr :: String -> GHC.SrcSpan -> String -> String
97+-- | Indent with 2 spaces for readability.
64−showParsingErr msg spn err = unlines
98+withIndent :: String -> String
65− [ msg
99+withIndent txt = " " ++ txt
66− , showOutputable spn
67− , err
68− ]
69−
70−-- | Display something 'GHC.Outputable'.
71−
72−showOutputable :: GHC.Outputable o => o -> String
73−showOutputable = GHC.showSDocUnsafe . GHC.ppr
src/Ormolu/Imports.hs+176−64
@@ -1,90 +1,202 @@
1{-# LANGUAGE LambdaCase #-}
1{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE RankNTypes #-}
2{-# LANGUAGE RankNTypes #-}
3+{-# LANGUAGE RecordWildCards #-}
3
4
4-- | Manipulations on import lists.
5-- | Manipulations on import lists.
5−
6module Ormolu.Imports
6module Ormolu.Imports
7− ( sortImports
7+ ( normalizeImports,
8 )
8 )
9where
9where
10
10
11import Data.Bifunctor
11import Data.Bifunctor
12+import Data.Char (isAlphaNum)
12import Data.Function (on)
13import Data.Function (on)
13−import Data.List (sortBy)
14+import Data.List (foldl', nubBy, sortBy, sortOn)
15+import Data.Map.Strict (Map)
16+import qualified Data.Map.Strict as M
17+import FastString (FastString)
14import GHC hiding (GhcPs, IE)
18import GHC hiding (GhcPs, IE)
15−import HsImpExp (IE (..))
19+import GHC.Hs.Extension
16−import Language.Haskell.GHC.ExactPrint.Types
20+import GHC.Hs.ImpExp (IE (..))
17−
21+import Ormolu.Utils (notImplemented, showOutputable)
18−-- | Sort imports by module name. This also sorts explicit import lists for
22+
19−-- each declaration.
23+-- | Sort and normalize imports.
20−
21−sortImports :: [LImportDecl GhcPs] -> [LImportDecl GhcPs]
24+normalizeImports :: [LImportDecl GhcPs] -> [LImportDecl GhcPs]
22−sortImports = sortBy compareIdecl . fmap (fmap sortImportLists)
25+normalizeImports =
26+ fmap snd
27+ . M.toAscList
28+ . M.fromListWith combineImports
29+ . fmap (\x -> (importId x, g x))
23 where
30 where
24− sortImportLists :: ImportDecl GhcPs -> ImportDecl GhcPs
31+ g (L l ImportDecl {..}) =
25− sortImportLists decl =
32+ L
33+ l
34+ ImportDecl
26− decl { ideclHiding = second (fmap sortLies) <$> ideclHiding decl
35+ { ideclHiding = second (fmap normalizeLies) <$> ideclHiding,
36+ ..
27− }
37+ }
28−
38+ g _ = notImplemented "XImportDecl"
39+
40+-- | Combine two import declarations. It should be assumed that 'ImportId's
41+-- are equal.
42+combineImports ::
29−-- | Compare two @'LImportDecl' 'GhcPs'@ things.
43+ LImportDecl GhcPs ->
30−
44+ LImportDecl GhcPs ->
31−compareIdecl :: LImportDecl GhcPs -> LImportDecl GhcPs -> Ordering
45+ LImportDecl GhcPs
32−compareIdecl (L _ m0) (L _ m1) =
46+combineImports (L lx ImportDecl {..}) (L _ y) =
47+ L
48+ lx
49+ ImportDecl
50+ { ideclHiding = case (ideclHiding, GHC.ideclHiding y) of
51+ (Just (hiding, L l' xs), Just (_, L _ ys)) ->
52+ Just (hiding, (L l' (normalizeLies (xs ++ ys))))
53+ _ -> Nothing,
54+ ..
55+ }
56+combineImports _ _ = notImplemented "XImportDecl"
57+
58+-- | Import id, a collection of all things that justify having a separate
59+-- import entry. This is used for merging of imports. If two imports have
60+-- the same 'ImportId' they can be merged.
61+data ImportId = ImportId
62+ { importIsPrelude :: Bool,
63+ importIdName :: ModuleName,
64+ importPkgQual :: Maybe FastString,
65+ importSource :: Bool,
66+ importSafe :: Bool,
67+ importQualified :: Bool,
68+ importImplicit :: Bool,
69+ importAs :: Maybe ModuleName,
70+ importHiding :: Maybe Bool
71+ }
72+ deriving (Eq, Ord)
73+
74+-- | Obtain an 'ImportId' for a given import.
75+importId :: LImportDecl GhcPs -> ImportId
76+importId (L _ ImportDecl {..}) =
77+ ImportId
33− if isPrelude n0
78+ { importIsPrelude = isPrelude,
34− then GT
79+ importIdName = moduleName,
35− else if isPrelude n1
80+ importPkgQual = sl_fs <$> ideclPkgQual,
36− then LT
81+ importSource = ideclSource,
37− else n0 `compare` n1
82+ importSafe = ideclSafe,
83+ importQualified = case ideclQualified of
84+ QualifiedPre -> True
85+ QualifiedPost -> True
86+ NotQualified -> False,
87+ importImplicit = ideclImplicit,
88+ importAs = unLoc <$> ideclAs,
89+ importHiding = fst <$> ideclHiding
90+ }
38 where
91 where
39− n0 = unL (ideclName m0)
40− n1 = unL (ideclName m1)
41− isPrelude = (== "Prelude") . moduleNameString
92+ isPrelude = moduleNameString moduleName == "Prelude"
42−
93+ moduleName = unLoc ideclName
43−-- | Sort located import or export.
94+importId _ = notImplemented "XImportDecl"
44−
45−sortLies :: [LIE GhcPs] -> [LIE GhcPs]
46−sortLies = sortBy (compareIE `on` unL) . fmap (fmap sortThings)
47−
48−-- | Sort imports\/exports inside of 'IEThingWith'.
49
95
50−sortThings :: IE GhcPs -> IE GhcPs
96+-- | Normalize a collection of import\/export items.
51−sortThings = \case
97+normalizeLies :: [LIE GhcPs] -> [LIE GhcPs]
52− IEThingWith x w xs fl ->
98+normalizeLies = sortOn (getIewn . unLoc) . M.elems . foldl' combine M.empty
53− IEThingWith x w (sortBy (compareIewn `on` unL) xs) fl
99+ where
100+ combine ::
101+ Map IEWrappedNameOrd (LIE GhcPs) ->
102+ LIE GhcPs ->
103+ Map IEWrappedNameOrd (LIE GhcPs)
104+ combine m (L new_l new) =
105+ let wname = getIewn new
106+ normalizeWNames =
107+ nubBy (\x y -> compareLIewn x y == EQ) . sortBy compareLIewn
108+ alter = \case
109+ Nothing -> Just . L new_l $
110+ case new of
111+ IEThingWith NoExtField n wildcard g flbl ->
112+ IEThingWith NoExtField n wildcard (normalizeWNames g) flbl
54− other -> other
113+ other -> other
55−
114+ Just old ->
56−-- | Compare two located imports or exports.
115+ let f = \case
57−
116+ IEVar NoExtField n -> IEVar NoExtField n
58−compareIE :: IE GhcPs -> IE GhcPs -> Ordering
117+ IEThingAbs NoExtField _ -> new
59−compareIE = compareIewn `on` getIewn
118+ IEThingAll NoExtField n -> IEThingAll NoExtField n
119+ IEThingWith NoExtField n wildcard g flbl ->
120+ case new of
121+ IEVar NoExtField _ ->
122+ error "Ormolu.Imports broken presupposition"
123+ IEThingAbs NoExtField _ ->
124+ IEThingWith NoExtField n wildcard g flbl
125+ IEThingAll NoExtField n' ->
126+ IEThingAll NoExtField n'
127+ IEThingWith NoExtField n' wildcard' g' flbl' ->
128+ let combinedWildcard =
129+ case (wildcard, wildcard') of
130+ (IEWildcard _, _) -> IEWildcard 0
131+ (_, IEWildcard _) -> IEWildcard 0
132+ _ -> NoIEWildcard
133+ in IEThingWith
134+ NoExtField
135+ n'
136+ combinedWildcard
137+ (normalizeWNames (g <> g'))
138+ flbl'
139+ IEModuleContents NoExtField _ -> notImplemented "IEModuleContents"
140+ IEGroup NoExtField _ _ -> notImplemented "IEGroup"
141+ IEDoc NoExtField _ -> notImplemented "IEDoc"
142+ IEDocNamed NoExtField _ -> notImplemented "IEDocNamed"
143+ XIE x -> noExtCon x
144+ IEModuleContents NoExtField _ -> notImplemented "IEModuleContents"
145+ IEGroup NoExtField _ _ -> notImplemented "IEGroup"
146+ IEDoc NoExtField _ -> notImplemented "IEDoc"
147+ IEDocNamed NoExtField _ -> notImplemented "IEDocNamed"
148+ XIE x -> noExtCon x
149+ in Just (f <$> old)
150+ in M.alter alter wname m
151+
152+-- | A wrapper for @'IEWrappedName' 'RdrName'@ that allows us to define an
153+-- 'Ord' instance for it.
154+newtype IEWrappedNameOrd = IEWrappedNameOrd (IEWrappedName RdrName)
155+ deriving (Eq)
156+
157+instance Ord IEWrappedNameOrd where
158+ compare (IEWrappedNameOrd x) (IEWrappedNameOrd y) = compareIewn x y
60
159
61-- | Project @'IEWrappedName' 'RdrName'@ from @'IE' 'GhcPs'@.
160-- | Project @'IEWrappedName' 'RdrName'@ from @'IE' 'GhcPs'@.
62−
63−getIewn :: IE GhcPs -> IEWrappedName RdrName
161+getIewn :: IE GhcPs -> IEWrappedNameOrd
64getIewn = \case
162getIewn = \case
65− IEVar x -> unL x
163+ IEVar NoExtField x -> IEWrappedNameOrd (unLoc x)
66− IEThingAbs x -> unL x
164+ IEThingAbs NoExtField x -> IEWrappedNameOrd (unLoc x)
67− IEThingAll x -> unL x
165+ IEThingAll NoExtField x -> IEWrappedNameOrd (unLoc x)
68− IEThingWith x _ _ _ -> unL x
166+ IEThingWith NoExtField x _ _ _ -> IEWrappedNameOrd (unLoc x)
69− IEModuleContents _ -> error "Ormolu.Imports.projectName: IEModuleContents"
167+ IEModuleContents NoExtField _ -> notImplemented "IEModuleContents"
70− IEGroup _ _ -> error "Ormolu.Imports.projectName: IEGroup"
168+ IEGroup NoExtField _ _ -> notImplemented "IEGroup"
71− IEDoc _ -> error "Ormolu.Imports.projectName: IEGroup"
169+ IEDoc NoExtField _ -> notImplemented "IEDoc"
72− IEDocNamed _ -> error "Ormolu.Imports.projectName: IEGroup"
170+ IEDocNamed NoExtField _ -> notImplemented "IEDocNamed"
171+ XIE x -> noExtCon x
172+
173+-- | Like 'compareIewn' for located wrapped names.
174+compareLIewn :: LIEWrappedName RdrName -> LIEWrappedName RdrName -> Ordering
175+compareLIewn = compareIewn `on` unLoc
73
176
74-- | Compare two @'IEWrapppedName' 'RdrName'@ things.
177-- | Compare two @'IEWrapppedName' 'RdrName'@ things.
75−
76compareIewn :: IEWrappedName RdrName -> IEWrappedName RdrName -> Ordering
178compareIewn :: IEWrappedName RdrName -> IEWrappedName RdrName -> Ordering
77−compareIewn (IEName x) (IEName y) = unL x `compare` unL y
179+compareIewn (IEName x) (IEName y) = unLoc x `compareRdrName` unLoc y
78compareIewn (IEName _) (IEPattern _) = LT
180compareIewn (IEName _) (IEPattern _) = LT
79compareIewn (IEName _) (IEType _) = LT
181compareIewn (IEName _) (IEType _) = LT
80compareIewn (IEPattern _) (IEName _) = GT
182compareIewn (IEPattern _) (IEName _) = GT
81−compareIewn (IEPattern x) (IEPattern y) = unL x `compare` unL y
183+compareIewn (IEPattern x) (IEPattern y) = unLoc x `compareRdrName` unLoc y
82compareIewn (IEPattern _) (IEType _) = LT
184compareIewn (IEPattern _) (IEType _) = LT
83compareIewn (IEType _) (IEName _) = GT
185compareIewn (IEType _) (IEName _) = GT
84compareIewn (IEType _) (IEPattern _) = GT
186compareIewn (IEType _) (IEPattern _) = GT
85−compareIewn (IEType x) (IEType y) = unL x `compare` unL y
187+compareIewn (IEType x) (IEType y) = unLoc x `compareRdrName` unLoc y
86−
188+
87−-- | Exact inner value from 'Located'.
189+compareRdrName :: RdrName -> RdrName -> Ordering
88−
190+compareRdrName x y =
89−unL :: Located e -> e
191+ case (getNameStr x, getNameStr y) of
90−unL (L _ e) = e
192+ ([], []) -> EQ
193+ ((_ : _), []) -> GT
194+ ([], (_ : _)) -> LT
195+ ((x' : _), (y' : _)) ->
196+ case (isAlphaNum x', isAlphaNum y') of
197+ (False, False) -> x `compare` y
198+ (True, False) -> LT
199+ (False, True) -> GT
200+ (True, True) -> x `compare` y
201+ where
202+ getNameStr = showOutputable . rdrNameOcc
src/Ormolu/Parser.hs+200−84
@@ -1,103 +1,219 @@
1+{-# LANGUAGE LambdaCase #-}
1{-# LANGUAGE RecordWildCards #-}
2{-# LANGUAGE RecordWildCards #-}
3+{-# OPTIONS_GHC -fno-warn-orphans #-}
2
4
3-- | Parser for Haskell source code.
5-- | Parser for Haskell source code.
4−
5module Ormolu.Parser
6module Ormolu.Parser
6− ( parseModule
7+ ( parseModule,
8+ manualExts,
7 )
9 )
8where
10where
9
11
12+import Bag (bagToList)
13+import qualified CmdLineParser as GHC
10import Control.Exception
14import Control.Exception
11−import Control.Monad
12import Control.Monad.IO.Class
15import Control.Monad.IO.Class
13−import Data.Generics
16+import qualified Data.List as L
14−import GHC hiding (GhcPs, IE, parseModule)
17+import qualified Data.List.NonEmpty as NE
18+import Data.Ord (Down (Down))
19+import qualified Data.Text as T
20+import DynFlags as GHC
21+import ErrUtils (Severity (..), errMsgSeverity, errMsgSpan)
22+import qualified FastString as GHC
23+import GHC hiding (IE, UnicodeSyntax)
24+import GHC.DynFlags (baseDynFlags)
15−import GHC.LanguageExtensions.Type (Extension (Cpp))
25+import GHC.LanguageExtensions.Type (Extension (..))
16−import Language.Haskell.GHC.ExactPrint.Parsers hiding (parseModule)
26+import qualified HeaderInfo as GHC
17−import Language.Haskell.GHC.ExactPrint.Types
27+import qualified HscTypes as GHC
28+import qualified Lexer as GHC
18import Ormolu.Config
29import Ormolu.Config
19import Ormolu.Exception
30import Ormolu.Exception
31+import Ormolu.Parser.Anns
32+import Ormolu.Parser.CommentStream
33+import Ormolu.Parser.Result
34+import Ormolu.Processing.Preprocess (preprocess)
35+import Ormolu.Utils (incSpanLine, removeIndentation)
20−import qualified CmdLineParser as GHC
36+import qualified Panic as GHC
21−import qualified Data.Map.Strict as M
37+import qualified Parser as GHC
22−import qualified DynFlags as GHC
38+import qualified StringBuffer as GHC
23
39
24-- | Parse a complete module from string.
40-- | Parse a complete module from string.
41+parseModule ::
42+ MonadIO m =>
43+ -- | Ormolu configuration
44+ Config RegionDeltas ->
45+ -- | File name (only for source location annotations)
46+ FilePath ->
47+ -- | Input for parser
48+ String ->
49+ m
50+ ( [GHC.Warn],
51+ Either (SrcSpan, String) ParseResult
52+ )
53+parseModule Config {..} path rawInput = liftIO $ do
54+ let (literalPrefix, indentedInput, literalSuffix, extraComments) =
55+ preprocess path rawInput cfgRegion
56+ (input, indent) = removeIndentation indentedInput
57+ -- It's important that 'setDefaultExts' is done before
58+ -- 'parsePragmasIntoDynFlags', because otherwise we might enable an
59+ -- extension that was explicitly disabled in the file.
60+ let baseFlags =
61+ GHC.setGeneralFlag'
62+ GHC.Opt_Haddock
63+ (setDefaultExts baseDynFlags)
64+ extraOpts = dynOptionToLocatedStr <$> cfgDynOptions
65+ (warnings, dynFlags) <-
66+ parsePragmasIntoDynFlags baseFlags extraOpts path rawInput >>= \case
67+ Right res -> pure res
68+ Left err ->
69+ let loc =
70+ mkSrcSpan
71+ (mkSrcLoc (GHC.mkFastString path) 1 1)
72+ (mkSrcLoc (GHC.mkFastString path) 1 1)
73+ in throwIO (OrmoluParsingFailed loc err)
74+ let useRecordDot =
75+ "record-dot-preprocessor" == pgm_F dynFlags
76+ || any
77+ (("RecordDotPreprocessor" ==) . moduleNameString)
78+ (pluginModNames dynFlags)
79+ pStateErrors = \pstate ->
80+ let errs = bagToList $ GHC.getErrorMessages pstate dynFlags
81+ fixupErrSpan = incSpanLine (regionPrefixLength cfgRegion)
82+ in case L.sortOn (Down . SeverityOrd . errMsgSeverity) errs of
83+ [] -> Nothing
84+ err : _ ->
85+ -- Show instance returns a short error message
86+ Just (fixupErrSpan (errMsgSpan err), show err)
87+ r = case runParser GHC.parseModule dynFlags path input of
88+ GHC.PFailed pstate ->
89+ case pStateErrors pstate of
90+ Just err -> Left err
91+ Nothing -> error "PFailed does not have an error"
92+ GHC.POk pstate (L _ hsModule) ->
93+ case pStateErrors pstate of
94+ -- Some parse errors (pattern/arrow syntax in expr context)
95+ -- do not cause a parse error, but they are replaced with "_"
96+ -- by the parser and the modified AST is propagated to the
97+ -- later stages; but we fail in those cases.
98+ Just err -> Left err
99+ Nothing ->
100+ let (stackHeader, shebangs, pragmas, comments) =
101+ mkCommentStream input extraComments pstate
102+ in Right
103+ ParseResult
104+ { prParsedSource = hsModule,
105+ prAnns = mkAnns pstate,
106+ prStackHeader = stackHeader,
107+ prShebangs = shebangs,
108+ prPragmas = pragmas,
109+ prCommentStream = comments,
110+ prUseRecordDot = useRecordDot,
111+ prImportQualifiedPost =
112+ GHC.xopt ImportQualifiedPost dynFlags,
113+ prLiteralPrefix = T.pack literalPrefix,
114+ prLiteralSuffix = T.pack literalSuffix,
115+ prIndent = indent
116+ }
117+ return (warnings, r)
118+
119+-- | Enable all language extensions that we think should be enabled by
120+-- default for ease of use.
121+setDefaultExts :: DynFlags -> DynFlags
122+setDefaultExts flags = L.foldl' xopt_set flags autoExts
123+ where
124+ autoExts = allExts L.\\ manualExts
125+ allExts = [minBound .. maxBound]
126+
127+-- | Extensions that are not enabled automatically and should be activated
128+-- by user.
129+manualExts :: [Extension]
130+manualExts =
131+ [ Arrows, -- steals proc
132+ Cpp, -- forbidden
133+ BangPatterns, -- makes certain patterns with ! fail
134+ PatternSynonyms, -- steals the pattern keyword
135+ RecursiveDo, -- steals the rec keyword
136+ StaticPointers, -- steals static keyword
137+ TransformListComp, -- steals the group keyword
138+ UnboxedTuples, -- breaks (#) lens operator
139+ MagicHash, -- screws {-# these things #-}
140+ TypeApplications, -- steals (@) operator on some cases
141+ AlternativeLayoutRule,
142+ AlternativeLayoutRuleTransitional,
143+ MonadComprehensions,
144+ UnboxedSums,
145+ UnicodeSyntax, -- gives special meanings to operators like (→)
146+ TemplateHaskellQuotes, -- enables TH subset of quasi-quotes, this
147+ -- apparently interferes with QuasiQuotes in
148+ -- weird ways
149+ ImportQualifiedPost -- affects how Ormolu renders imports, so the
150+ -- decision of enabling this style is left to the user
151+ ]
152+
153+-- | Run a 'GHC.P' computation.
154+runParser ::
155+ -- | Computation to run
156+ GHC.P a ->
157+ -- | Dynamic flags
158+ GHC.DynFlags ->
159+ -- | Module path
160+ FilePath ->
161+ -- | Module contents
162+ String ->
163+ -- | Parse result
164+ GHC.ParseResult a
165+runParser parser flags filename input = GHC.unP parser parseState
166+ where
167+ location = GHC.mkRealSrcLoc (GHC.mkFastString filename) 1 1
168+ buffer = GHC.stringToStringBuffer input
169+ parseState = GHC.mkPState flags buffer location
25
170
26−parseModule
171+-- | Wrap GHC's 'Severity' to add 'Ord' instance.
27− :: MonadIO m
172+newtype SeverityOrd = SeverityOrd Severity
28− => [DynOption] -- ^ Dynamic options that affect parsing
29− -> FilePath -- ^ File name (only for source location annotations)
30− -> String -- ^ Input for parser
31− -> m ([GHC.Warn], Either (SrcSpan, String) (Anns, ParsedSource))
32−parseModule dynOpts path input = liftIO $ do
33− (ws, dynFlags) <- ghcWrapper $ do
34− dynFlags0 <- initDynFlagsPure path input
35− (dynFlags1, _, ws) <-
36− GHC.parseDynamicFilePragma dynFlags0 (dynOptionToLocatedStr <$> dynOpts)
37− return (ws, dynFlags1)
38− -- NOTE It's better to throw this outside of 'ghcWrapper' because
39− -- otherwise the exception will be wrapped as a GHC panic, which we don't
40− -- want.
41− when (GHC.xopt Cpp dynFlags) $
42− throwIO OrmoluCppEnabled
43− let r = case parseModuleFromStringInternal dynFlags path input of
44− Left e -> Left e
45− Right (anns, psrc) ->
46− Right (dropImportComments anns psrc, psrc)
47− return (ws, r)
48
173
49−-- | Drop comments associated with elements of import lists. The reason we
174+instance Eq SeverityOrd where
50−-- do this is that those comments are not associated as user would expect.
175+ s1 == s2 = compare s1 s2 == EQ
51−--
52−-- For example:
53−--
54−-- > import Foo -- (1)
55−-- > import Bar -- (2)
56−-- > import Baz -- (3)
57−--
58−-- Here, @(1)@ is considered preceding comment of @Baz@ import, in fact, it
59−-- has nothing to do with @Foo@. Similarly, @(2)@ is associted with @Baz@,
60−-- not @Bar@. Finally @(3)@ is actually preceeding comment for the thing
61−-- that follows the import list, or if nothing follows, it's a trailing
62−-- comment of the whole module.
63−--
64−-- Since we do sorting of imports when we print them, we would need to do
65−-- sorting of corresponding annotations as well (because we do checking of
66−-- annotations and AST in "Ormolu.Diff" as part of the self-check), and this
67−-- is hard. Even if we manage to do that the result will be totally
68−-- confusing, e.g. for the example above:
69−--
70−-- > -- (1)
71−-- > import Bar
72−-- > -- (2)
73−-- > import Baz
74−-- > import Foo
75−-- > -- (3)
76−--
77−-- The solution is to drop the tricky comments right after parsing, so we
78−-- don't need to deal with them at all, including the need to update
79−-- annotations for the correctness checking we do in "Ormolu.Diff".
80−--
81−-- The solution is not perfect, but practical.
82
176
83−dropImportComments
177+instance Ord SeverityOrd where
84− :: Anns
178+ compare (SeverityOrd s1) (SeverityOrd s2) =
85− -> ParsedSource
179+ compare (f s1) (f s2)
86− -> Anns
180+ where
87−dropImportComments anns (L _ HsModule {..}) =
181+ f :: Severity -> Int
88− foldr M.delete anns (hsmodImports >>= keyAnnsFor)
182+ f SevOutput = 1
183+ f SevFatal = 2
184+ f SevInteractive = 3
185+ f SevDump = 4
186+ f SevInfo = 5
187+ f SevWarning = 6
188+ f SevError = 7
89
189
90−-- | Extract all 'AnnKey's from given 'Data'.
190+----------------------------------------------------------------------------
191+-- Helpers taken from HLint
91
192
92−keyAnnsFor :: GenericQ [AnnKey]
193+parsePragmasIntoDynFlags ::
93−keyAnnsFor a = everything mappend (const id `ext2Q` queryLocated) a []
194+ -- | Pre-set 'DynFlags'
195+ DynFlags ->
196+ -- | Extra options (provided by user)
197+ [Located String] ->
198+ -- | File name (only for source location annotations)
199+ FilePath ->
200+ -- | Input for parser
201+ String ->
202+ IO (Either String ([GHC.Warn], DynFlags))
203+parsePragmasIntoDynFlags flags extraOpts filepath str =
204+ catchErrors $ do
205+ let opts = GHC.getOptions flags (GHC.stringToStringBuffer str) filepath
206+ (flags', leftovers, warnings) <-
207+ parseDynamicFilePragma flags (opts <> extraOpts)
208+ case NE.nonEmpty leftovers of
209+ Nothing -> return ()
210+ Just unrecognizedOpts ->
211+ throwIO (OrmoluUnrecognizedOpts (unLoc <$> unrecognizedOpts))
212+ let flags'' = flags' `gopt_set` Opt_KeepRawTokenStream
213+ return $ Right (warnings, flags'')
94 where
214 where
95− queryLocated
215+ catchErrors act =
96− :: (Data e0, Data e1)
216+ GHC.handleGhcException
97− => GenLocated e0 e1
217+ reportErr
98− -> [AnnKey]
218+ (GHC.handleSourceError reportErr act)
99− -> [AnnKey]
219+ reportErr e = return $ Left (show e)
100− queryLocated (L mspn x) =
101− case cast mspn :: Maybe SrcSpan of
102− Nothing -> id
103− Just spn -> (mkAnnKey (L spn x) :)
src/Ormolu/Parser/Anns.hsnew file+46
@@ -0,0 +1,46 @@
1+-- | Ormolu-specific representation of GHC annotations.
2+module Ormolu.Parser.Anns
3+ ( Anns (..),
4+ emptyAnns,
5+ mkAnns,
6+ lookupAnns,
7+ )
8+where
9+
10+import Data.Map.Strict (Map)
11+import qualified Data.Map.Strict as M
12+import Data.Maybe (mapMaybe)
13+import qualified GHC
14+import qualified Lexer as GHC
15+import SrcLoc
16+
17+-- | Ormolu-specific representation of GHC annotations.
18+newtype Anns = Anns (Map RealSrcSpan [GHC.AnnKeywordId])
19+ deriving (Eq)
20+
21+-- | Empty 'Anns'.
22+emptyAnns :: Anns
23+emptyAnns = Anns M.empty
24+
25+-- | Create 'Anns' from 'GHC.PState'.
26+mkAnns ::
27+ GHC.PState ->
28+ Anns
29+mkAnns pstate =
30+ Anns $
31+ M.fromListWith (++) (mapMaybe f (GHC.annotations pstate))
32+ where
33+ f ((spn, kid), _) =
34+ case spn of
35+ RealSrcSpan rspn -> Just (rspn, [kid])
36+ UnhelpfulSpan _ -> Nothing
37+
38+-- | Lookup 'GHC.AnnKeywordId's corresponding to a given 'SrcSpan'.
39+lookupAnns ::
40+ -- | Span to lookup with
41+ SrcSpan ->
42+ -- | Collection of annotations
43+ Anns ->
44+ [GHC.AnnKeywordId]
45+lookupAnns (RealSrcSpan rspn) (Anns m) = M.findWithDefault [] rspn m
46+lookupAnns (UnhelpfulSpan _) _ = []
src/Ormolu/Parser/CommentStream.hsnew file+226
@@ -0,0 +1,226 @@
1+{-# LANGUAGE DeriveDataTypeable #-}
2+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3+{-# LANGUAGE LambdaCase #-}
4+
5+-- | Functions for working with comment stream.
6+module Ormolu.Parser.CommentStream
7+ ( -- * Comment stream
8+ CommentStream (..),
9+ mkCommentStream,
10+ showCommentStream,
11+
12+ -- * Comment
13+ Comment (..),
14+ unComment,
15+ hasAtomsBefore,
16+ isMultilineComment,
17+ )
18+where
19+
20+import Data.Char (isSpace)
21+import Data.Data (Data)
22+import qualified Data.List as L
23+import Data.List.NonEmpty (NonEmpty (..))
24+import qualified Data.List.NonEmpty as NE
25+import Data.Maybe (mapMaybe)
26+import qualified GHC
27+import qualified Lexer as GHC
28+import Ormolu.Parser.Pragma
29+import Ormolu.Parser.Shebang
30+import Ormolu.Processing.Common
31+import Ormolu.Utils (onTheSameLine, showOutputable)
32+import SrcLoc
33+
34+----------------------------------------------------------------------------
35+-- Comment stream
36+
37+-- | A stream of 'RealLocated' 'Comment's in ascending order with respect to
38+-- beginning of corresponding spans.
39+newtype CommentStream = CommentStream [RealLocated Comment]
40+ deriving (Eq, Data, Semigroup, Monoid)
41+
42+-- | Create 'CommentStream' from 'GHC.PState'. The pragmas and shebangs are
43+-- removed from the 'CommentStream'. Shebangs are only extracted from the
44+-- comments that come from the first argument.
45+mkCommentStream ::
46+ -- | Original input
47+ String ->
48+ -- | Extra comments to include
49+ [Located String] ->
50+ -- | Parser state to use for comment extraction
51+ GHC.PState ->
52+ -- | Stack header, shebangs, pragmas, and comment stream
53+ ( Maybe (RealLocated Comment),
54+ [Shebang],
55+ [([RealLocated Comment], Pragma)],
56+ CommentStream
57+ )
58+mkCommentStream input extraComments pstate =
59+ ( mstackHeader,
60+ shebangs,
61+ pragmas,
62+ CommentStream comments
63+ )
64+ where
65+ (comments, pragmas) = extractPragmas input rawComments1
66+ (rawComments1, mstackHeader) = extractStackHeader rawComments0
67+ rawComments0 =
68+ L.sortOn (realSrcSpanStart . getRealSrcSpan) . mapMaybe toRealSpan $
69+ otherExtraComments
70+ ++ mapMaybe (liftMaybe . fmap unAnnotationComment) (GHC.comment_q pstate)
71+ ++ concatMap
72+ (mapMaybe (liftMaybe . fmap unAnnotationComment) . snd)
73+ (GHC.annotations_comments pstate)
74+ (shebangs, otherExtraComments) = extractShebangs extraComments
75+
76+-- | Pretty-print a 'CommentStream'.
77+showCommentStream :: CommentStream -> String
78+showCommentStream (CommentStream xs) =
79+ unlines $
80+ showComment <$> xs
81+ where
82+ showComment (GHC.L l str) = showOutputable l ++ " " ++ show str
83+
84+----------------------------------------------------------------------------
85+-- Comment
86+
87+-- | A wrapper for a single comment. The 'Bool' indicates whether there were
88+-- atoms before beginning of the comment in the original input. The
89+-- 'NonEmpty' list inside contains lines of multiline comment @{- … -}@ or
90+-- just single item\/line otherwise.
91+data Comment = Comment Bool (NonEmpty String)
92+ deriving (Eq, Show, Data)
93+
94+-- | Normalize comment string. Sometimes one multi-line comment is turned
95+-- into several lines for subsequent outputting with correct indentation for
96+-- each line.
97+mkComment ::
98+ -- | Lines of original input with their indices
99+ [(Int, String)] ->
100+ -- | Raw comment string
101+ RealLocated String ->
102+ -- | Remaining lines of original input and the constructed 'Comment'
103+ ([(Int, String)], RealLocated Comment)
104+mkComment ls (L l s) = (ls', comment)
105+ where
106+ comment =
107+ L l . Comment atomsBefore . removeConseqBlanks . fmap dropTrailing $
108+ if "{-" `L.isPrefixOf` s
109+ then case NE.nonEmpty (lines s) of
110+ Nothing -> s :| []
111+ Just (x :| xs) ->
112+ let getIndent y =
113+ if all isSpace y || y == endDisabling
114+ then startIndent
115+ else length (takeWhile isSpace y)
116+ n = minimum (startIndent : fmap getIndent xs)
117+ removeIndent y =
118+ if y == endDisabling
119+ then y
120+ else drop n y
121+ in x :| (removeIndent <$> xs)
122+ else s :| []
123+ (atomsBefore, ls') =
124+ case dropWhile ((< commentLine) . fst) ls of
125+ [] -> (False, [])
126+ ((_, i) : ls'') ->
127+ case take 2 (dropWhile isSpace i) of
128+ "--" -> (False, ls'')
129+ "{-" -> (False, ls'')
130+ _ -> (True, ls'')
131+ dropTrailing = L.dropWhileEnd isSpace
132+ startIndent = srcSpanStartCol l - 1
133+ commentLine = srcSpanStartLine l
134+
135+-- | Get a collection of lines from a 'Comment'.
136+unComment :: Comment -> NonEmpty String
137+unComment (Comment _ xs) = xs
138+
139+-- | Check whether the 'Comment' had some non-whitespace atoms in front of
140+-- it in the original input.
141+hasAtomsBefore :: Comment -> Bool
142+hasAtomsBefore (Comment atomsBefore _) = atomsBefore
143+
144+-- | Is this comment multiline-style?
145+isMultilineComment :: Comment -> Bool
146+isMultilineComment (Comment _ (x :| _)) = "{-" `L.isPrefixOf` x
147+
148+----------------------------------------------------------------------------
149+-- Helpers
150+
151+-- | Detect and extract stack header if it is present.
152+extractStackHeader ::
153+ -- | Comment stream to analyze
154+ [RealLocated String] ->
155+ ([RealLocated String], Maybe (RealLocated Comment))
156+extractStackHeader = \case
157+ [] -> ([], Nothing)
158+ (x : xs) ->
159+ let comment = snd (mkComment [] x)
160+ in if isStackHeader (unRealSrcSpan comment)
161+ then (xs, Just comment)
162+ else (x : xs, Nothing)
163+ where
164+ isStackHeader (Comment _ (x :| _)) =
165+ "stack" `L.isPrefixOf` dropWhile isSpace (drop 2 x)
166+
167+-- | Extract pragmas and their associated comments.
168+extractPragmas ::
169+ -- | Input
170+ String ->
171+ -- | Comment stream to analyze
172+ [RealLocated String] ->
173+ ([RealLocated Comment], [([RealLocated Comment], Pragma)])
174+extractPragmas input = go initialLs id id
175+ where
176+ initialLs = zip [1 ..] (lines input)
177+ go ls csSoFar pragmasSoFar = \case
178+ [] -> (csSoFar [], pragmasSoFar [])
179+ (x : xs) ->
180+ case parsePragma (unRealSrcSpan x) of
181+ Nothing ->
182+ let (ls', x') = mkComment ls x
183+ in go ls' (csSoFar . (x' :)) pragmasSoFar xs
184+ Just pragma ->
185+ let combined ys = (csSoFar ys, pragma)
186+ go' ls' ys rest = go ls' id (pragmasSoFar . (combined ys :)) rest
187+ in case xs of
188+ [] -> go' ls [] xs
189+ (y : ys) ->
190+ let (ls', y') = mkComment ls y
191+ in if onTheSameLine
192+ (RealSrcSpan (getRealSrcSpan x))
193+ (RealSrcSpan (getRealSrcSpan y))
194+ then go' ls' [y'] ys
195+ else go' ls [] xs
196+
197+-- | Get a 'String' from 'GHC.AnnotationComment'.
198+unAnnotationComment :: GHC.AnnotationComment -> Maybe String
199+unAnnotationComment = \case
200+ GHC.AnnDocCommentNext _ -> Nothing -- @-- |@
201+ GHC.AnnDocCommentPrev _ -> Nothing -- @-- ^@
202+ GHC.AnnDocCommentNamed _ -> Nothing -- @-- $@
203+ GHC.AnnDocSection _ _ -> Nothing -- @-- *@
204+ GHC.AnnDocOptions s -> Just s
205+ GHC.AnnLineComment s -> Just s
206+ GHC.AnnBlockComment s -> Just s
207+
208+liftMaybe :: Located (Maybe a) -> Maybe (Located a)
209+liftMaybe = \case
210+ L _ Nothing -> Nothing
211+ L l (Just a) -> Just (L l a)
212+
213+toRealSpan :: Located a -> Maybe (RealLocated a)
214+toRealSpan (L (RealSrcSpan l) a) = Just (L l a)
215+toRealSpan _ = Nothing
216+
217+-- | Remove consecutive blank lines.
218+removeConseqBlanks :: NonEmpty String -> NonEmpty String
219+removeConseqBlanks (x :| xs) = x :| go (null x) id xs
220+ where
221+ go seenBlank acc = \case
222+ [] -> acc []
223+ (y : ys) ->
224+ if seenBlank && null y
225+ then go True acc ys
226+ else go (null y) (acc . (y :)) ys
src/Ormolu/Parser/Pragma.hsnew file+89
@@ -0,0 +1,89 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+
4+-- | A module for parsing of pragmas from comments.
5+module Ormolu.Parser.Pragma
6+ ( Pragma (..),
7+ parsePragma,
8+ )
9+where
10+
11+import Control.Monad
12+import Data.Char (isSpace, toLower)
13+import qualified Data.List as L
14+import qualified EnumSet as ES
15+import FastString (mkFastString, unpackFS)
16+import qualified Lexer as L
17+import Module (ComponentId (..), newSimpleUnitId)
18+import SrcLoc
19+import StringBuffer
20+
21+-- | Ormolu's representation of pragmas.
22+data Pragma
23+ = -- | Language pragma
24+ PragmaLanguage [String]
25+ | -- | GHC options pragma
26+ PragmaOptionsGHC String
27+ | -- | Haddock options pragma
28+ PragmaOptionsHaddock String
29+ deriving (Show, Eq)
30+
31+-- | Extract a pragma from a comment if possible, or return 'Nothing'
32+-- otherwise.
33+parsePragma ::
34+ -- | Comment to try to parse
35+ String ->
36+ Maybe Pragma
37+parsePragma input = do
38+ inputNoPrefix <- L.stripPrefix "{-#" input
39+ guard ("#-}" `L.isSuffixOf` input)
40+ let contents = take (length inputNoPrefix - 3) inputNoPrefix
41+ (pragmaName, cs) = (break isSpace . dropWhile isSpace) contents
42+ case toLower <$> pragmaName of
43+ "language" -> PragmaLanguage <$> parseExtensions cs
44+ "options_ghc" -> Just $ PragmaOptionsGHC (trimSpaces cs)
45+ "options_haddock" -> Just $ PragmaOptionsHaddock (trimSpaces cs)
46+ _ -> Nothing
47+ where
48+ trimSpaces :: String -> String
49+ trimSpaces = L.dropWhileEnd isSpace . dropWhile isSpace
50+
51+-- | Assuming the input consists of a series of tokens from a language
52+-- pragma, return the set of enabled extensions.
53+parseExtensions :: String -> Maybe [String]
54+parseExtensions str = tokenize str >>= go
55+ where
56+ go = \case
57+ [L.ITconid ext] -> return [unpackFS ext]
58+ (L.ITconid ext : L.ITcomma : xs) -> (unpackFS ext :) <$> go xs
59+ _ -> Nothing
60+
61+-- | Tokenize a given input using GHC's lexer.
62+tokenize :: String -> Maybe [L.Token]
63+tokenize input =
64+ case L.unP pLexer parseState of
65+ L.PFailed {} -> Nothing
66+ L.POk _ x -> Just x
67+ where
68+ location = mkRealSrcLoc (mkFastString "") 1 1
69+ buffer = stringToStringBuffer input
70+ parseState = L.mkPStatePure parserFlags buffer location
71+ parserFlags =
72+ L.mkParserFlags'
73+ ES.empty
74+ ES.empty
75+ (newSimpleUnitId (ComponentId (mkFastString "")))
76+ True
77+ True
78+ True
79+ True
80+
81+-- | Haskell lexer.
82+pLexer :: L.P [L.Token]
83+pLexer = go
84+ where
85+ go = do
86+ r <- L.lexer False return
87+ case unLoc r of
88+ L.ITeof -> return []
89+ x -> (x :) <$> go
src/Ormolu/Parser/Result.hsnew file+51
@@ -0,0 +1,51 @@
1+{-# LANGUAGE RecordWildCards #-}
2+
3+-- | A type for result of parsing.
4+module Ormolu.Parser.Result
5+ ( ParseResult (..),
6+ prettyPrintParseResult,
7+ )
8+where
9+
10+import Data.Text (Text)
11+import GHC
12+import Ormolu.Parser.Anns
13+import Ormolu.Parser.CommentStream
14+import Ormolu.Parser.Pragma (Pragma)
15+import Ormolu.Parser.Shebang (Shebang)
16+
17+-- | A collection of data that represents a parsed module in Ormolu.
18+data ParseResult = ParseResult
19+ { -- | 'ParsedSource' from GHC
20+ prParsedSource :: HsModule GhcPs,
21+ -- | Ormolu-specfic representation of annotations
22+ prAnns :: Anns,
23+ -- | Stack header
24+ prStackHeader :: Maybe (RealLocated Comment),
25+ -- | Shebangs found in the input
26+ prShebangs :: [Shebang],
27+ -- | Pragmas and the associated comments
28+ prPragmas :: [([RealLocated Comment], Pragma)],
29+ -- | Comment stream
30+ prCommentStream :: CommentStream,
31+ -- | Whether or not record dot syntax is enabled
32+ prUseRecordDot :: Bool,
33+ -- | Whether or not ImportQualifiedPost is enabled
34+ prImportQualifiedPost :: Bool,
35+ -- | Literal prefix
36+ prLiteralPrefix :: Text,
37+ -- | Literal suffix
38+ prLiteralSuffix :: Text,
39+ -- | Indentation level, can be non-zero in case of region formatting
40+ prIndent :: Int
41+ }
42+
43+-- | Pretty-print a 'ParseResult'.
44+prettyPrintParseResult :: ParseResult -> String
45+prettyPrintParseResult ParseResult {..} =
46+ unlines
47+ [ "parse result:",
48+ " comment stream:",
49+ showCommentStream prCommentStream
50+ -- XXX extend as needed
51+ ]
src/Ormolu/Parser/Shebang.hsnew file+27
@@ -0,0 +1,27 @@
1+{-# LANGUAGE DeriveDataTypeable #-}
2+
3+-- | A module for dealing with shebangs.
4+module Ormolu.Parser.Shebang
5+ ( Shebang (..),
6+ extractShebangs,
7+ isShebang,
8+ )
9+where
10+
11+import Data.Data (Data)
12+import qualified Data.List as L
13+import SrcLoc
14+
15+-- | A wrapper for a shebang.
16+newtype Shebang = Shebang (Located String)
17+ deriving (Eq, Data)
18+
19+-- | Extract shebangs from the beginning of a comment stream.
20+extractShebangs :: [Located String] -> ([Shebang], [Located String])
21+extractShebangs comments = (Shebang <$> shebangs, rest)
22+ where
23+ (shebangs, rest) = span (isShebang . unLoc) comments
24+
25+-- | Return 'True' if given 'String' is a shebang.
26+isShebang :: String -> Bool
27+isShebang str = "#!" `L.isPrefixOf` str
src/Ormolu/Printer.hs+27−15
@@ -1,26 +1,38 @@
1−{-# LANGUAGE LambdaCase #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE RecordWildCards #-}
1+{-# LANGUAGE RecordWildCards #-}
4
2
5-- | Pretty-printer for Haskell AST.
3-- | Pretty-printer for Haskell AST.
6−
7module Ormolu.Printer
4module Ormolu.Printer
8− ( printModule
5+ ( printModule,
9 )
6 )
10where
7where
11
8
12import Data.Text (Text)
9import Data.Text (Text)
13−import GHC (ParsedSource)
10+import Ormolu.Parser.Result
14−import Language.Haskell.GHC.ExactPrint.Types
15import Ormolu.Printer.Combinators
11import Ormolu.Printer.Combinators
16import Ormolu.Printer.Meat.Module
12import Ormolu.Printer.Meat.Module
13+import Ormolu.Printer.SpanStream
14+import Ormolu.Processing.Postprocess (postprocess)
17
15
18-- | Render a module.
16-- | Render a module.
19−
20−printModule
17+printModule ::
21− :: Bool -- ^ Trace debugging information
18+ -- | Result of parsing
22− -> Anns -- ^ Annotations
19+ ParseResult ->
23− -> ParsedSource -- ^ Parsed source
24− -> Text -- ^ Resulting rendition
20+ -- | Resulting rendition
21+ Text
25−printModule debugOn anns src =
22+printModule ParseResult {..} =
23+ prLiteralPrefix <> region <> prLiteralSuffix
24+ where
25+ region =
26+ postprocess prIndent $
27+ runR
26− runR debugOn (p_hsModule src) anns
28+ ( p_hsModule
29+ prStackHeader
30+ prShebangs
31+ prPragmas
32+ prImportQualifiedPost
33+ prParsedSource
34+ )
35+ (mkSpanStream prParsedSource)
36+ prCommentStream
37+ prAnns
38+ prUseRecordDot
src/Ormolu/Printer/Combinators.hs+244−224
@@ -1,278 +1,298 @@
1+{-# LANGUAGE FlexibleContexts #-}
2+{-# LANGUAGE GADTs #-}
1−{-# LANGUAGE LambdaCase #-}
3+{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE RecordWildCards #-}
4−
5−-- | Printing combinators.
6
5
6+-- | Printing combinators. The definitions here are presented in such an
7+-- order so you can just go through the Haddocks and by the end of the file
8+-- you should have a pretty good idea how to program rendering logic.
7module Ormolu.Printer.Combinators
9module Ormolu.Printer.Combinators
8 ( -- * The 'R' monad
10 ( -- * The 'R' monad
9− R
11+ R,
10− , runR
12+ runR,
13+ getAnns,
14+ getEnclosingSpan,
15+
11 -- * Combinators
16 -- * Combinators
17+
12 -- ** Basic
18 -- ** Basic
13− , txt
19+ txt,
14− , atom
20+ atom,
21+ space,
15− , newline
22+ newline,
16− , inci
23+ inci,
17− , relaxComments
24+ inciIf,
18− , located
25+ located,
19− , locatedVia
20− , located'
26+ located',
21− , switchLayout
27+ switchLayout,
22− , velt
28+ Layout (..),
23− , velt'
24− , vlayout
29+ vlayout,
30+ getLayout,
25− , breakpoint
31+ breakpoint,
26− , withSep
32+ breakpoint',
27− , spaceSep
33+
28− , newlineSep
34+ -- ** Formatting lists
35+ sep,
36+ sepSemi,
37+ canUseBraces,
38+ useBraces,
39+ dontUseBraces,
40+
29 -- ** Wrapping
41 -- ** Wrapping
30− , line
42+ BracketStyle (..),
43+ sitcc,
31− , backticks
44+ backticks,
45+ banana,
32− , braces
46+ braces,
33− , brackets
47+ brackets,
34− , bracketsPar
35− , parens
48+ parens,
36− , parensHash
49+ parensHash,
50+ pragmaBraces,
51+ pragma,
52+
37 -- ** Literals
53 -- ** Literals
38− , comma
54+ comma,
39− , space
55+ commaDel,
56+ equals,
57+
58+ -- ** Stateful markers
59+ SpanMark (..),
60+ spanMarkSpan,
61+ HaddockStyle (..),
62+ setSpanMark,
63+ getSpanMark,
40 )
64 )
41where
65where
42
66
43−import Data.Bool (bool)
67+import Control.Monad
44−import Data.Data (Data)
45import Data.List (intersperse)
68import Data.List (intersperse)
46import Data.Text (Text)
69import Data.Text (Text)
47−import Language.Haskell.GHC.ExactPrint.Types
48import Ormolu.Printer.Comments
70import Ormolu.Printer.Comments
49import Ormolu.Printer.Internal
71import Ormolu.Printer.Internal
50−import Outputable (Outputable (..), showSDocUnsafe)
51import SrcLoc
72import SrcLoc
52−import qualified Data.Text as T
53
73
54----------------------------------------------------------------------------
74----------------------------------------------------------------------------
55-- Basic
75-- Basic
56
76
57−-- | Output a fixed 'Text' fragment. The argument may not contain any line
77+-- | Indent the inner expression if the first argument is 'True'.
58−-- breaks or tab characters.
78+inciIf ::
59−
79+ -- | Whether to indent
60−txt :: Text -> R ()
80+ Bool ->
61−txt t = ensureIndent >> spit t
81+ -- | The expression to indent
62−
82+ R () ->
63−-- | Output 'Outputable' fragment of AST.
83+ R ()
64−
84+inciIf b m = if b then inci m else m
65−atom :: Outputable a => a -> R ()
85+
66−atom = txt . T.pack . showSDocUnsafe . ppr
67−
68−-- | Enter a 'Located' entity. This primitive handles outputting comments
86+-- | Enter a 'Located' entity. This combinator handles outputting comments
69−-- that may be associated with the primitive and sets corresponding layout
70−-- for the inner computation.
87+-- and sets layout (single-line vs multi-line) for the inner computation.
71−
88+-- Roughly, the rule for using 'located' is that every time there is a
72−located
89+-- 'Located' wrapper, it should be “discharged” with a corresponding
73− :: Data a
90+-- 'located' invocation.
74− => Located a -- ^ Thing to enter
91+located ::
75− -> (a -> R ()) -- ^ How to render inner value
76− -> R ()
77−located loc@(L l _) = locatedVia (Just l) loc
78−
79−-- | A special version of 'located' that allows to control layout using
80−-- externally provided span. 'Nothing' means that layout won't be changed.
81−
82−locatedVia
83− :: Data a
84− => Maybe SrcSpan -- ^ Span that controls layout selection
85− -> Located a -- ^ Thing to enter
92+ -- | Thing to enter
93+ Located a ->
86− -> (a -> R ()) -- ^ How to render inner value
94+ -- | How to render inner value
87− -> R ()
95+ (a -> R ()) ->
88−locatedVia ml loc@(L l a) f = do
96+ R ()
89− mann <- lookupAnn loc
97+located (L (UnhelpfulSpan _) a) f = f a
90− relaxed <- relaxedComments
98+located (L (RealSrcSpan l) a) f = do
91− let m = case ml of
99+ spitPrecedingComments l
92− Nothing -> f a
100+ withEnclosingSpan l $
93− Just l' -> switchLayout l' (f a)
101+ switchLayout [RealSrcSpan l] (f a)
94− case mann of
102+ spitFollowingComments l
95− Nothing -> m
96− Just Ann {..} -> bool sitcc id relaxed $ do
97− -- There are three things in 'Ann' which contain comments:
98−
99− let cmode =
100− if annGetConstr a == CN "HsModule"
101− then Module
102− else Other
103− (before, after) = partitionDPs cmode l annsDP
104−
105− -- 'annPriorComments' contains comments that were directly placed
106− -- before entities such as comments (in both styles) before function
107− -- definitions and inline comments before smaller things like types
108− -- and literals.
109−
110− spitComments (addDecoration cmode Before l <$> annPriorComments)
111−
112− -- Comments inside 'annsDP' marked with 'AnnComment' are trickier,
113− -- they seem to contain everything that goes after the thing they
114− -- are attached to and in some cases (e.g. for modules) they contain
115− -- comments that go before things. Exact location can only be
116− -- deduced by analyzing the associated span.
117−
118− spitComments before
119− m
120− spitComments after
121−
122− -- I wasn't able to find any case when 'annFollowingComments' is
123− -- populated, so we'll ignore that one for now and fix it when we
124− -- have an example of source code where it matters.
125
103
126-- | A version of 'located' with arguments flipped.
104-- | A version of 'located' with arguments flipped.
127−
128−located'
105+located' ::
129− :: Data a
130− => (a -> R ()) -- ^ How to render inner value
106+ -- | How to render inner value
107+ (a -> R ()) ->
131− -> Located a -- ^ Thing to enter
108+ -- | Thing to enter
109+ Located a ->
132− -> R ()
110+ R ()
133located' = flip located
111located' = flip located
134
112
135−-- | Set layout according to given 'SrcSpan' for a given computation. Use
113+-- | Set layout according to combination of given 'SrcSpan's for a given.
136−-- this only when you need to set layout based on e.g. combined span of
114+-- Use this only when you need to set layout based on e.g. combined span of
137-- several elements when there is no corresponding 'Located' wrapper
115-- several elements when there is no corresponding 'Located' wrapper
138−-- provided by GHC AST.
116+-- provided by GHC AST. It is relatively rare that this one is needed.
139−
140−switchLayout
141− :: SrcSpan -- ^ Span that controls layout
142− -> R () -- ^ Computation to run with changed layout
143− -> R ()
144−switchLayout spn = enterLayout
145− (if isOneLineSpan spn
146− then SingleLine
147− else MultiLine)
148−
149−-- | Element of variable layout. This means that the sub-components may be
150−-- rendered either on single line or each on its own line depending on
151−-- current layout.
152--
117--
153−-- This version does not make subsequent element (second and later) align
118+-- Given empty list this function will set layout to single line.
154−-- with the first automatically and does not insert spaces between elements
119+switchLayout ::
155−-- when layout is single line.
120+ -- | Span that controls layout
156−
121+ [SrcSpan] ->
157−velt :: [R ()] -> R ()
122+ -- | Computation to run with changed layout
158−velt xs = sequence_ (intersperse sep (sitcc <$> xs))
123+ R () ->
159− where
124+ R ()
160− sep = vlayout (pure ()) newline
125+switchLayout spans' = enterLayout (spansLayout spans')
161−
126+
162−-- | Like 'velt', but all sub-elements start at the same indentation level
127+-- | Which layout combined spans result in?
163−-- as first element, additionally spaces are inserted when layout is single
128+spansLayout :: [SrcSpan] -> Layout
164−-- line.
129+spansLayout = \case
165−
130+ [] -> SingleLine
166−velt' :: [R ()] -> R ()
131+ (x : xs) ->
167−velt' xs = sitcc $ sequence_ (intersperse sep (sitcc <$> xs))
132+ if isOneLineSpan (foldr combineSrcSpans x xs)
168− where
133+ then SingleLine
169− sep = vlayout (spit " ") newline
134+ else MultiLine
170
135
171-- | Insert a space if enclosing layout is single-line, or newline if it's
136-- | Insert a space if enclosing layout is single-line, or newline if it's
172-- multiline.
137-- multiline.
173−
138+--
139+-- > breakpoint = vlayout space newline
174breakpoint :: R ()
140breakpoint :: R ()
175breakpoint = vlayout space newline
141breakpoint = vlayout space newline
176
142
177−-- | Put separator between renderings of items of a list.
143+-- | Similar to 'breakpoint' but outputs nothing in case of single-line
178−
144+-- layout.
179−withSep
145+--
180− :: R () -- ^ Separator
146+-- > breakpoint' = vlayout (return ()) newline
181− -> (a -> R ()) -- ^ How to render list items
147+breakpoint' :: R ()
182− -> [a] -- ^ List to render
148+breakpoint' = vlayout (return ()) newline
183− -> [R ()] -- ^ List of printing actions
184−withSep sep f = \case
185− [] -> []
186− (x:xs) ->
187− let g a = sep >> f a
188− in f x : fmap g xs
189−
190−-- | Render space-separated elements.
191−
192−spaceSep
193− :: (a -> R ()) -- ^ How to render list items
194− -> [a] -- ^ List to render
195− -> R ()
196−spaceSep f = sequence_ . withSep space f
197−
198−-- | Render newline-separated elements.
199
149
200−newlineSep
150+----------------------------------------------------------------------------
151+-- Formatting lists
152+
153+-- | Render a collection of elements inserting a separator between them.
154+sep ::
155+ -- | Separator
156+ R () ->
201− :: (a -> R ()) -- ^ How to render list items
157+ -- | How to render an element
158+ (a -> R ()) ->
202− -> [a] -- ^ List to render
159+ -- | Elements to render
160+ [a] ->
203− -> R ()
161+ R ()
204−newlineSep f = sequence_ . withSep newline f
162+sep s f xs = sequence_ (intersperse s (f <$> xs))
163+
164+-- | Render a collection of elements layout-sensitively using given printer,
165+-- inserting semicolons if necessary and respecting 'useBraces' and
166+-- 'dontUseBraces' combinators.
167+--
168+-- > useBraces $ sepSemi txt ["foo", "bar"]
169+-- > == vlayout (txt "{ foo; bar }") (txt "foo\nbar")
170+--
171+-- > dontUseBraces $ sepSemi txt ["foo", "bar"]
172+-- > == vlayout (txt "foo; bar") (txt "foo\nbar")
173+sepSemi ::
174+ -- | How to render an element
175+ (a -> R ()) ->
176+ -- | Elements to render
177+ [a] ->
178+ R ()
179+sepSemi f xs = vlayout singleLine multiLine
180+ where
181+ singleLine = do
182+ ub <- canUseBraces
183+ case xs of
184+ [] -> when ub $ txt "{}"
185+ xs' ->
186+ if ub
187+ then do
188+ txt "{"
189+ space
190+ sep (txt ";" >> space) (dontUseBraces . f) xs'
191+ space
192+ txt "}"
193+ else sep (txt ";" >> space) f xs'
194+ multiLine =
195+ sep newline (dontUseBraces . f) xs
205
196
206----------------------------------------------------------------------------
197----------------------------------------------------------------------------
207-- Wrapping
198-- Wrapping
208
199
209−-- | Finish given entity by a 'newline'.
200+-- | 'BracketStyle' controlling how closing bracket is rendered.
210−
201+data BracketStyle
211−line :: R () -> R ()
202+ = -- | Normal
212−line m = do
203+ N
213− m
204+ | -- | Shifted one level
214− newline
205+ S
206+ deriving (Eq, Show)
215
207
216-- | Surround given entity by backticks.
208-- | Surround given entity by backticks.
217−
218backticks :: R () -> R ()
209backticks :: R () -> R ()
219−backticks m = txt "`" >> m >> txt "`"
210+backticks m = do
220−
221−-- | Surround given entity by curly braces.
222−
223−braces :: R () -> R ()
224−braces m = sitcc $ do
225− txt "{"
211+ txt "`"
226− ospaces m
212+ m
227− txt "}"
228−
229−-- | Surround given entity by square brackets.
230−
231−brackets :: R () -> R ()
232−brackets m = sitcc $ do
233− txt "["
234− ospaces m
235− txt "]"
213+ txt "`"
236
214
237−-- | Surround given entity by parallel array brackets @[:@ ond @:]@.
215+-- | Surround given entity by banana brackets (i.e., from arrow notation.)
216+banana :: R () -> R ()
217+banana = brackets_ True "(|" "|)" N
238
218
239−bracketsPar :: R () -> R ()
219+-- | Surround given entity by curly braces @{@ and @}@.
240−bracketsPar m = sitcc $ do
220+braces :: BracketStyle -> R () -> R ()
241− txt "[:"
221+braces = brackets_ False "{" "}"
242− m
243− txt ":]"
244
222
245−-- | Surround given entity by parentheses.
223+-- | Surround given entity by square brackets @[@ and @]@.
224+brackets :: BracketStyle -> R () -> R ()
225+brackets = brackets_ False "[" "]"
246
226
227+-- | Surround given entity by parentheses @(@ and @)@.
247−parens :: R () -> R ()
228+parens :: BracketStyle -> R () -> R ()
248−parens m = sitcc $ do
229+parens = brackets_ False "(" ")"
249− txt "("
250− ospaces m
251− txt ")"
252
230
253-- | Surround given entity by @(# @ and @ #)@.
231-- | Surround given entity by @(# @ and @ #)@.
254−
232+parensHash :: BracketStyle -> R () -> R ()
255−parensHash :: R () -> R ()
233+parensHash = brackets_ True "(#" "#)"
234+
235+-- | Braces as used for pragmas: @{-#@ and @#-}@.
236+pragmaBraces :: R () -> R ()
256−parensHash m = sitcc $ do
237+pragmaBraces m = sitcc $ do
257− txt "(# "
238+ txt "{-#"
239+ space
258 m
240 m
241+ breakpoint
259− txt " #)"
242+ inci (txt "#-}")
260−
243+
261−-- | Surround given entity by optional space before and a newline after, iff
244+-- | Surround the body with a pragma name and 'pragmaBraces'.
262−-- current layout is multiline.
245+pragma ::
263−
246+ -- | Pragma text
264−ospaces :: R () -> R ()
247+ Text ->
248+ -- | Pragma body
249+ R () ->
250+ R ()
251+pragma pragmaText body = pragmaBraces $ do
252+ txt pragmaText
253+ breakpoint
254+ body
255+
256+-- | A helper for defining wrappers like 'parens' and 'braces'.
257+brackets_ ::
258+ -- | Insert breakpoints around brackets
259+ Bool ->
260+ -- | Opening bracket
261+ Text ->
262+ -- | Closing bracket
263+ Text ->
264+ -- | Bracket style
265+ BracketStyle ->
266+ -- | Inner expression
267+ R () ->
268+ R ()
269+brackets_ needBreaks open close style m = sitcc (vlayout singleLine multiLine)
270+ where
271+ singleLine = do
272+ txt open
273+ when needBreaks space
274+ m
275+ when needBreaks space
276+ txt close
277+ multiLine = do
278+ txt open
279+ if needBreaks
280+ then newline >> inci m
281+ else space >> sitcc m
265−ospaces m = vlayout m (txt " " >> m >> newline)
282+ newline
283+ inciIf (style == S) (txt close)
266
284
267----------------------------------------------------------------------------
285----------------------------------------------------------------------------
268-- Literals
286-- Literals
269
287
270−-- | Print @,@ followed by a space.
288+-- | Print @,@.
271−
272comma :: R ()
289comma :: R ()
273−comma = txt ", "
290+comma = txt ","
274
291
275−-- | Print single space.
292+-- | Delimiting combination with 'comma'. To be used with 'sep'.
293+commaDel :: R ()
294+commaDel = comma >> breakpoint
276
295
277−space :: R ()
296+-- | Print @=@. Do not use @'txt' "="@.
278−space = txt " "
297+equals :: R ()
298+equals = interferingTxt "="
src/Ormolu/Printer/Comments.hs+272−172
@@ -1,186 +1,286 @@
1−-- | Helpers for formatting of comments.
2−
3−{-# LANGUAGE LambdaCase #-}
1+{-# LANGUAGE LambdaCase #-}
4{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
5
3
4+-- | Helpers for formatting of comments. This is low-level code, use
5+-- "Ormolu.Printer.Combinators" unless you know what you are doing.
6module Ormolu.Printer.Comments
6module Ormolu.Printer.Comments
7− ( -- * Types
7+ ( spitPrecedingComments,
8− Decoration (..)
8+ spitFollowingComments,
9− , Decorator (..)
9+ spitRemainingComments,
10− , Position (..)
10+ spitCommentNow,
11− , CommentMode (..)
11+ spitCommentPending,
12− -- * Functions for working with comments
13− , spitComments
14− , partitionDPs
15− , addDecoration
16 )
12 )
17where
13where
18
14
19−import ApiAnnotation (AnnKeywordId (AnnModule))
20import Control.Monad
15import Control.Monad
21−import Data.Bifunctor
16+import qualified Data.List.NonEmpty as NE
22−import Data.Maybe (mapMaybe)
17+import Data.Maybe (listToMaybe)
23−import Language.Haskell.GHC.ExactPrint.Types
18+import qualified Data.Text as T
24−import Ormolu.Comments
19+import Ormolu.Parser.CommentStream
25import Ormolu.Printer.Internal
20import Ormolu.Printer.Internal
26import SrcLoc
21import SrcLoc
27−import qualified Data.Text as T
28
22
29−-- | Placement instructions for comments.
23+----------------------------------------------------------------------------
30−
24+-- Top-level
31−data Decoration
25+
32− = Decoration Decorator Decorator
26+-- | Output all preceding comments for an element at given location.
33− deriving (Eq, Show)
27+spitPrecedingComments ::
34−
28+ -- | Span of the element to attach comments to
35−-- | Decorator in this context is a thing to put before\/after a comment.
29+ RealSrcSpan ->
36−
30+ R ()
37−data Decorator
31+spitPrecedingComments ref = do
38− = NoDec -- ^ Output nothing
32+ gotSome <- handleCommentSeries (spitPrecedingComment ref)
39− | SpaceDec -- ^ Output single space
33+ when gotSome $ do
40− | NewlineDec -- ^ Output single newline
34+ lastMark <- getSpanMark
41− deriving (Eq, Show)
35+ -- Insert a blank line between the preceding comments and the thing
42−
36+ -- after them if there was a blank line in the input.
43−-- | Position: before vs after.
37+ when (needsNewlineBefore ref lastMark) newline
44−
38+
45−data Position
39+-- | Output all comments following an element at given location.
46− = Before -- ^ Before
40+spitFollowingComments ::
47− | After -- ^ After
48− deriving (Eq, Show)
49−
50−-- | For which type of AST leaf we're preparing the comments.
51−
52−data CommentMode
53− = Module -- ^ Module
54− | Other -- ^ Other element
55− deriving (Eq, Show)
56−
57−-- | Output a bunch of 'Comment's. 'DeltaPos'es are used to insert extra
58−-- space between the comments when necessary.
59−
60−spitComments :: [(Comment, Decoration)] -> R ()
61−spitComments = mapM_ $ \(comment, (Decoration d0 d1)) -> do
62− let spitDecorator = \case
63− NoDec -> return ()
64− SpaceDec -> spit " "
65− NewlineDec -> newline
66− spitDecorator d0
67− spitComment comment
68− spitDecorator d1
69−
70−-- | Output a 'Comment'.
71−
72−spitComment :: Comment -> R ()
73−spitComment (Comment str _ _) =
74− forM_ (normalizeComment str) $ \x -> do
75− ensureIndent
76− spit (T.pack x)
77−
78−-- | Partition annotations to get a collection of 'Comment's preceding a
79−-- definition and following it. Every 'Comment' has corresponding
80−-- 'Decoration' which is used to understand how to decorate it.
81−
82−partitionDPs
83− :: CommentMode -- ^ For which type of element we prepare comments
84− -> SrcSpan -- ^ Span of element the comments are attached to
41+ -- | Span of the element to attach comments to
85− -> [(KeywordId, DeltaPos)] -- ^ Annotations
42+ RealSrcSpan ->
86− -> ([(Comment, Decoration)], [(Comment, Decoration)])
43+ R ()
87−partitionDPs cmode refSpan anns =
44+spitFollowingComments ref = do
88− case cmode of
45+ trimSpanStream ref
89− Module -> partitionDPsModule refSpan anns
46+ void $ handleCommentSeries (spitFollowingComment ref)
90− Other -> partitionDPsOther refSpan anns
47+
91−
48+-- | Output all remaining comments in the comment stream.
92−-- | Try to partition comments as if for a module.
49+spitRemainingComments :: R ()
93−
50+spitRemainingComments = do
94−partitionDPsModule
51+ -- Make sure we have a blank a line between the last definition and the
95− :: SrcSpan -- ^ Span of element the comments are attached to
52+ -- trailing comments.
96− -> [(KeywordId, DeltaPos)] -- ^ Annotations
53+ newline
97− -> ([(Comment, Decoration)], [(Comment, Decoration)])
54+ void $ handleCommentSeries spitRemainingComment
98−partitionDPsModule refSpan xs
55+
99− = bimap (takeComments Before) (takeComments After) $
56+----------------------------------------------------------------------------
100− -- NOTE If there is no annotation corresponding to module keyword, then
57+-- Single-comment functions
101− -- the module doesn't have a header and all comments shoud go after.
58+
102− if G AnnModule `elem` fmap fst xs
59+-- | Output a single preceding comment for an element at given location.
103− then break ((== G AnnModule) . fst) xs
60+spitPrecedingComment ::
104− else ([], xs)
61+ -- | Span of the element to attach comments to
105− where
62+ RealSrcSpan ->
106− takeComments pos = mapMaybe $ \(keywordId, dpos) -> do
63+ -- | Are we done?
107− c <- annComment keywordId
64+ R Bool
108− return (c, getDecoration Module pos refSpan (c, dpos))
65+spitPrecedingComment ref = do
109−
66+ mlastMark <- getSpanMark
110−-- | Partition comments according to their spans (works for everything but
67+ let p (L l _) = realSrcSpanEnd l <= realSrcSpanStart ref
111−-- modules).
68+ withPoppedComment p $ \l comment -> do
112−
69+ lineSpans <- thisLineSpans
113−partitionDPsOther
70+ let thisCommentLine = srcLocLine (realSrcSpanStart l)
114− :: SrcSpan -- ^ Span of element the comments are attached to
71+ needsNewline =
115− -> [(KeywordId, DeltaPos)] -- ^ Annotations
72+ case listToMaybe lineSpans of
116− -> ([(Comment, Decoration)], [(Comment, Decoration)])
73+ Nothing -> False
117−partitionDPsOther refSpan
74+ Just spn -> srcLocLine (realSrcSpanEnd spn) /= thisCommentLine
118− = bimap (fmap (addDecoration Other Before refSpan))
75+ when (needsNewline || needsNewlineBefore l mlastMark) newline
119− (fixupLastDec . fmap (addDecoration Other After refSpan))
76+ spitCommentNow l comment
120− . break (followedBySpan refSpan . commentIdentifier . fst)
77+ if theSameLinePre l ref
121− . mapMaybe annComment'
78+ then space
79+ else newline
80+
81+-- | Output a comment that follows element at given location immediately on
82+-- the same line, if there is any.
83+spitFollowingComment ::
84+ -- | AST element to attach comments to
85+ RealSrcSpan ->
86+ -- | Are we done?
87+ R Bool
88+spitFollowingComment ref = do
89+ mlastMark <- getSpanMark
90+ mnSpn <- nextEltSpan
91+ -- Get first enclosing span that is not equal to reference span, i.e. it's
92+ -- truly something enclosing the AST element.
93+ meSpn <- getEnclosingSpan (/= ref)
94+ withPoppedComment (commentFollowsElt ref mnSpn meSpn mlastMark) $ \l comment ->
95+ if theSameLinePost l ref
96+ then
97+ if isMultilineComment comment
98+ then space >> spitCommentNow l comment
99+ else spitCommentPending OnTheSameLine l comment
100+ else do
101+ when (needsNewlineBefore l mlastMark) $
102+ registerPendingCommentLine OnNextLine ""
103+ spitCommentPending OnNextLine l comment
104+
105+-- | Output a single remaining comment from the comment stream.
106+spitRemainingComment ::
107+ -- | Are we done?
108+ R Bool
109+spitRemainingComment = do
110+ mlastMark <- getSpanMark
111+ withPoppedComment (const True) $ \l comment -> do
112+ when (needsNewlineBefore l mlastMark) newline
113+ spitCommentNow l comment
114+ newline
115+
116+----------------------------------------------------------------------------
117+-- Helpers
118+
119+-- | Output series of comments.
120+handleCommentSeries ::
121+ -- | Given location of previous comment, output the next comment
122+ -- returning 'True' if we're done
123+ R Bool ->
124+ -- | Whether we printed any comments
125+ R Bool
126+handleCommentSeries f = go False
122 where
127 where
123− annComment' :: (KeywordId, DeltaPos) -> Maybe (Comment, DeltaPos)
128+ go gotSome = do
124− annComment' (keywordId, dpos) = do
129+ done <- f
125− c <- annComment keywordId
130+ if done
126− return (c, dpos)
131+ then return gotSome
127− followedBySpan :: SrcSpan -> SrcSpan -> Bool
128− followedBySpan spn0 spn1 =
129− if srcSpanEnd spn0 < srcSpanStart spn1
130− then True
131− else False
132+ else go True
132−
133+
133−-- | Last following comment cannot be standalone because in that case we get
134+-- | Try to pop a comment using given predicate and if there is a comment
134−-- redundant newlines.
135+-- matching the predicate, print it out.
135−
136+withPoppedComment ::
136−fixupLastDec :: [(Comment, Decoration)] -> [(Comment, Decoration)]
137+ -- | Comment predicate
137−fixupLastDec [] = []
138+ (RealLocated Comment -> Bool) ->
138−fixupLastDec [(c, Decoration d0 _)] = [(c, Decoration d0 NoDec)]
139+ -- | Printing function
139−fixupLastDec (c:cs) = c : fixupLastDec cs
140+ (RealSrcSpan -> Comment -> R ()) ->
140−
141+ -- | Are we done?
141−-- | Replace 'DeltaPos' with 'Decoration'.
142+ R Bool
142−
143+withPoppedComment p f = do
143−addDecoration
144+ r <- popComment p
144− :: CommentMode -- ^ For which type of element we prepare comments
145+ case r of
145− -> Position -- ^ Is this for comments before or after?
146+ Nothing -> return True
146− -> SrcSpan -- ^ Span of element the comments are attached to
147− -> (Comment, DeltaPos) -- ^ Thing to decorate
148− -> (Comment, Decoration)
149−addDecoration cmode pos refSpan (comment, dpos) =
150− ( comment
147+ Just (L l comment) -> False <$ f l comment
151− , getDecoration cmode pos refSpan (comment, dpos)
152− )
153
148
154−-- | Calculate decoration for a comment.
149+-- | Determine if we need to insert a newline between current comment and
150+-- last printed comment.
151+needsNewlineBefore ::
152+ -- | Current comment span
153+ RealSrcSpan ->
154+ -- | Last printed comment span
155+ Maybe SpanMark ->
156+ Bool
157+needsNewlineBefore _ (Just (HaddockSpan _ _)) = True
158+needsNewlineBefore l mlastMark =
159+ case spanMarkSpan <$> mlastMark of
160+ Nothing -> False
161+ Just lastMark ->
162+ srcSpanStartLine l > srcSpanEndLine lastMark + 1
155
163
156−getDecoration
164+-- | Is the preceding comment and AST element are on the same line?
157− :: CommentMode -- ^ For which type of element we prepare comments
165+theSameLinePre ::
158− -> Position -- ^ Is this for comment before or after?
166+ -- | Current comment span
159− -> SrcSpan -- ^ Span of element the comments are attached to
167+ RealSrcSpan ->
160− -> (Comment, DeltaPos) -- ^ Thing to decorate
168+ -- | AST element location
161− -> Decoration
169+ RealSrcSpan ->
162−getDecoration cmode pos refSpan (c, (DP (r, _))) =
170+ Bool
163− Decoration preceedingDec followingDec
171+theSameLinePre l ref =
172+ srcSpanEndLine l == srcSpanStartLine ref
173+
174+-- | Is the following comment and AST element are on the same line?
175+theSameLinePost ::
176+ -- | Current comment span
177+ RealSrcSpan ->
178+ -- | AST element location
179+ RealSrcSpan ->
180+ Bool
181+theSameLinePost l ref =
182+ srcSpanStartLine l == srcSpanEndLine ref
183+
184+-- | Determine if given comment follows AST element.
185+commentFollowsElt ::
186+ -- | Location of AST element
187+ RealSrcSpan ->
188+ -- | Location of next AST element
189+ Maybe RealSrcSpan ->
190+ -- | Location of enclosing AST element
191+ Maybe RealSrcSpan ->
192+ -- | Location of last comment in the series
193+ Maybe SpanMark ->
194+ -- | Comment to test
195+ RealLocated Comment ->
196+ Bool
197+commentFollowsElt ref mnSpn meSpn mlastMark (L l comment) =
198+ -- A comment follows a AST element if all 4 conditions are satisfied:
199+ goesAfter
200+ && logicallyFollows
201+ && noEltBetween
202+ && (continuation || lastInEnclosing || supersedesParentElt)
164 where
203 where
165− preceedingDec =
204+ -- 1) The comment starts after end of the AST element:
166− if sameLine
205+ goesAfter =
167− then case pos of
206+ realSrcSpanStart l >= realSrcSpanEnd ref
168− Before -> NoDec
207+ -- 2) The comment logically belongs to the element, four cases:
169− After -> SpaceDec
208+ logicallyFollows =
170− else if r > 1
209+ theSameLinePost l ref -- a) it's on the same line
171− then NewlineDec
210+ || continuation -- b) it's a continuation of a comment block
172− else NoDec
211+ || lastInEnclosing -- c) it's the last element in the enclosing construct
173− followingDec =
212+
174− if sameLine
213+ -- 3) There is no other AST element between this element and the comment:
175− then case pos of
214+ noEltBetween =
176− Before -> SpaceDec
215+ case mnSpn of
177− After -> NewlineDec
216+ Nothing -> True
178− else NewlineDec
217+ Just nspn ->
179− sameLine =
218+ realSrcSpanStart nspn >= realSrcSpanEnd l
180− case cmode of
219+ -- 4) Less obvious: if column of comment is closer to the start of
181− Module -> False
220+ -- enclosing element, it probably related to that parent element, not to
182− Other ->
221+ -- the current child element. This rule is important because otherwise
183− case (refSpan, commentIdentifier c) of
222+ -- all comments would end up assigned to closest inner elements, and
184− (RealSrcSpan spn0, RealSrcSpan spn1) ->
223+ -- parent elements won't have a chance to get any comments assigned to
224+ -- them. This is not OK because comments will get indented according to
225+ -- the AST elements they are attached to.
226+ --
227+ -- Skip this rule if the comment is a continuation of a comment block.
228+ supersedesParentElt =
229+ case meSpn of
230+ Nothing -> True
231+ Just espn ->
232+ let startColumn = srcLocCol . realSrcSpanStart
233+ in startColumn espn > startColumn ref
234+ || ( abs (startColumn espn - startColumn l)
235+ >= abs (startColumn ref - startColumn l)
236+ )
237+ continuation =
238+ -- A comment is a continuation when it doesn't have non-whitespace
239+ -- lexemes in front of it and goes right after the previous comment.
240+ not (hasAtomsBefore comment)
241+ && ( case mlastMark of
242+ Just (HaddockSpan _ _) -> False
243+ Just (CommentSpan spn) ->
185− srcSpanEndLine spn0 == srcSpanStartLine spn1
244+ srcSpanEndLine spn + 1 == srcSpanStartLine l
245+ _ -> False
246+ )
247+ lastInEnclosing =
248+ case meSpn of
249+ -- When there is no enclosing element, return false
186− (_, _) -> False
250+ Nothing -> False
251+ -- When there is an enclosing element,
252+ Just espn ->
253+ let -- Make sure that the comment is inside the enclosing element
254+ insideParent = realSrcSpanEnd l <= realSrcSpanEnd espn
255+ -- And check if the next element is outside of the parent
256+ nextOutsideParent = case mnSpn of
257+ Nothing -> True
258+ Just nspn -> realSrcSpanEnd espn < realSrcSpanStart nspn
259+ in insideParent && nextOutsideParent
260+
261+-- | Output a 'Comment' immediately. This is a low-level printing function.
262+spitCommentNow :: RealSrcSpan -> Comment -> R ()
263+spitCommentNow spn comment = do
264+ sitcc
265+ . sequence_
266+ . NE.intersperse newline
267+ . fmap (txt . T.pack)
268+ . unComment
269+ $ comment
270+ setSpanMark (CommentSpan spn)
271+
272+-- | Output a 'Comment' at the end of correct line or after it depending on
273+-- 'CommentPosition'. Used for comments that may potentially follow on the
274+-- same line as something we just rendered, but not immediately after it.
275+spitCommentPending :: CommentPosition -> RealSrcSpan -> Comment -> R ()
276+spitCommentPending position spn comment = do
277+ let wrapper = case position of
278+ OnTheSameLine -> sitcc
279+ OnNextLine -> id
280+ wrapper
281+ . sequence_
282+ . NE.toList
283+ . fmap (registerPendingCommentLine position . T.pack)
284+ . unComment
285+ $ comment
286+ setSpanMark (CommentSpan spn)
src/Ormolu/Printer/Internal.hs+493−175
@@ -1,259 +1,577 @@
1{-# LANGUAGE GeneralizedNewtypeDeriving #-}
1{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2+{-# LANGUAGE LambdaCase #-}
2−{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE RankNTypes #-}
3
5
4-- | In most cases import "Ormolu.Printer.Combinators" instead, these
6-- | In most cases import "Ormolu.Printer.Combinators" instead, these
5-- functions are the low-level building blocks and should not be used on
7-- functions are the low-level building blocks and should not be used on
6-- their own. The 'R' monad is re-exported from "Ormolu.Printer.Combinators"
8-- their own. The 'R' monad is re-exported from "Ormolu.Printer.Combinators"
7-- as well.
9-- as well.
8−
9module Ormolu.Printer.Internal
10module Ormolu.Printer.Internal
10 ( -- * The 'R' monad
11 ( -- * The 'R' monad
11− R
12+ R,
12− , runR
13+ runR,
14+
13 -- * Internal functions
15 -- * Internal functions
14− , spit
16+ txt,
17+ interferingTxt,
18+ atom,
19+ space,
15− , newline
20+ newline,
16− , ensureIndent
21+ useRecordDot,
17− , inci
22+ inci,
18− , sitcc
23+ sitcc,
19− , relaxComments
20− , Layout (..)
24+ Layout (..),
21− , enterLayout
25+ enterLayout,
22− , vlayout
26+ vlayout,
23− , relaxedComments
27+ getLayout,
24− , lookupAnn
28+
29+ -- * Helpers for braces
30+ useBraces,
31+ dontUseBraces,
32+ canUseBraces,
33+
34+ -- * Special helpers for comment placement
35+ CommentPosition (..),
36+ registerPendingCommentLine,
37+ trimSpanStream,
38+ nextEltSpan,
39+ popComment,
40+ getEnclosingSpan,
41+ withEnclosingSpan,
42+ thisLineSpans,
43+
44+ -- * Stateful markers
45+ SpanMark (..),
46+ spanMarkSpan,
47+ HaddockStyle (..),
48+ setSpanMark,
49+ getSpanMark,
50+
51+ -- * Annotations
52+ getAnns,
25 )
53 )
26where
54where
27
55
28import Control.Monad.Reader
56import Control.Monad.Reader
29import Control.Monad.State.Strict
57import Control.Monad.State.Strict
30−import Data.Data (Data)
58+import Data.Bool (bool)
59+import Data.Coerce
60+import Data.Maybe (listToMaybe)
31import Data.Text (Text)
61import Data.Text (Text)
32−import Data.Text.Lazy.Builder
33−import Debug.Trace
34−import Language.Haskell.GHC.ExactPrint.Types
35−import SrcLoc
36−import qualified Data.Text.Lazy as TL
37−import qualified Data.Map as M
38import qualified Data.Text as T
62import qualified Data.Text as T
63+import qualified Data.Text.Lazy as TL
64+import Data.Text.Lazy.Builder
65+import GHC
66+import Ormolu.Parser.Anns
67+import Ormolu.Parser.CommentStream
68+import Ormolu.Printer.SpanStream
69+import Ormolu.Utils (showOutputable)
70+import Outputable (Outputable)
39
71
40----------------------------------------------------------------------------
72----------------------------------------------------------------------------
41-- The 'R' monad
73-- The 'R' monad
42
74
43-- | The 'R' monad hosts combinators that allow us to describe how to render
75-- | The 'R' monad hosts combinators that allow us to describe how to render
44-- AST.
76-- AST.
45−
46newtype R a = R (ReaderT RC (State SC) a)
77newtype R a = R (ReaderT RC (State SC) a)
47 deriving (Functor, Applicative, Monad)
78 deriving (Functor, Applicative, Monad)
48
79
49−-- | Reader context of 'R'.
80+-- | Reader context of 'R'. This should be used when we control rendering by
50−
81+-- enclosing certain expressions with wrappers.
51data RC = RC
82data RC = RC
52− { rcIndent :: !Int
53− -- ^ Indentation level, as the column index we need to start from after a
83+ { -- | Indentation level, as the column index we need to start from after
54− -- newline if we break lines
84+ -- a newline if we break lines
85+ rcIndent :: !Int,
86+ -- | Current layout
55− , rcLayout :: Layout
87+ rcLayout :: Layout,
56− -- ^ Current layout
88+ -- | Spans of enclosing elements of AST
57− , rcRelaxedComments :: Bool
89+ rcEnclosingSpans :: [RealSrcSpan],
58− -- ^ Whether to relax aligning rules for comments
90+ -- | Collection of annotations
59− , rcAnns :: Anns
91+ rcAnns :: Anns,
60− -- ^ The collection of annotations obtained after parsing
92+ -- | Whether the last expression in the layout can use braces
61− , rcDebug :: Bool
93+ rcCanUseBraces :: Bool,
62− -- ^ Whether to print debugging info as we go
94+ -- | Whether the source could have used the record dot preprocessor
95+ rcUseRecDot :: Bool
63 }
96 }
64
97
65-- | State context of 'R'.
98-- | State context of 'R'.
66−
67data SC = SC
99data SC = SC
68− { scColumn :: !Int
69− -- ^ Index of the next column to render
100+ { -- | Index of the next column to render
70− , scBuilder :: Builder
101+ scColumn :: !Int,
102+ -- | Indentation level that was used for the current line
103+ scIndent :: !Int,
71− -- ^ Rendered source code so far
104+ -- | Rendered source code so far
105+ scBuilder :: Builder,
106+ -- | Span stream
107+ scSpanStream :: SpanStream,
108+ -- | Spans of atoms that have been printed on the current line so far
109+ scThisLineSpans :: [RealSrcSpan],
110+ -- | Comment stream
111+ scCommentStream :: CommentStream,
112+ -- | Pending comment lines (in reverse order) to be inserted before next
113+ -- newline, 'Int' is the indentation level
114+ scPendingComments :: ![(CommentPosition, Text)],
115+ -- | Whether to output a space before the next output
116+ scRequestedDelimiter :: !RequestedDelimiter,
117+ -- | An auxiliary marker for keeping track of last output element
118+ scSpanMark :: !(Maybe SpanMark)
72 }
119 }
73
120
74−-- | 'Layout' options.
121+-- | Make sure next output is delimited by one of the following.
122+data RequestedDelimiter
123+ = -- | A space
124+ RequestedSpace
125+ | -- | A newline
126+ RequestedNewline
127+ | -- | Nothing
128+ RequestedNothing
129+ | -- | We just output a newline
130+ AfterNewline
131+ | -- | We haven't printed anything yet
132+ VeryBeginning
133+ deriving (Eq, Show)
75
134
135+-- | 'Layout' options.
76data Layout
136data Layout
77− = SingleLine -- ^ Put everything on single line
137+ = -- | Put everything on single line
138+ SingleLine
78− | MultiLine -- ^ Use multiple lines
139+ | -- | Use multiple lines
140+ MultiLine
79 deriving (Eq, Show)
141 deriving (Eq, Show)
80
142
81−-- | Run an 'R' monad.
143+-- | Modes for rendering of pending comments.
144+data CommentPosition
145+ = -- | Put the comment on the same line
146+ OnTheSameLine
147+ | -- | Put the comment on next line
148+ OnNextLine
149+ deriving (Eq, Show)
82
150
83−runR
151+-- | Run an 'R' monad.
84− :: Bool -- ^ Whether to print debugging info
152+runR ::
85− -> R () -- ^ Monad to run
153+ -- | Monad to run
86− -> Anns -- ^ Annotations to use
154+ R () ->
155+ -- | Span stream
156+ SpanStream ->
157+ -- | Comment stream
158+ CommentStream ->
159+ -- | Annotations
160+ Anns ->
161+ -- | Use Record Dot Syntax
162+ Bool ->
87− -> Text -- ^ Resulting rendition
163+ -- | Resulting rendition
164+ Text
88−runR debug (R m) anns =
165+runR (R m) sstream cstream anns recDot =
89 TL.toStrict . toLazyText . scBuilder $ execState (runReaderT m rc) sc
166 TL.toStrict . toLazyText . scBuilder $ execState (runReaderT m rc) sc
90 where
167 where
91− rc = RC
168+ rc =
169+ RC
92− { rcIndent = 0
170+ { rcIndent = 0,
93− , rcLayout = MultiLine
171+ rcLayout = MultiLine,
94− , rcRelaxedComments = False
172+ rcEnclosingSpans = [],
95− , rcAnns = anns
173+ rcAnns = anns,
96− , rcDebug = debug
174+ rcCanUseBraces = False,
175+ rcUseRecDot = recDot
97− }
176+ }
98− sc = SC
177+ sc =
178+ SC
99− { scColumn = 0
179+ { scColumn = 0,
180+ scIndent = 0,
100− , scBuilder = mempty
181+ scBuilder = mempty,
182+ scSpanStream = sstream,
183+ scThisLineSpans = [],
184+ scCommentStream = cstream,
185+ scPendingComments = [],
186+ scRequestedDelimiter = VeryBeginning,
187+ scSpanMark = Nothing
101− }
188+ }
102
189
103----------------------------------------------------------------------------
190----------------------------------------------------------------------------
104-- Internal functions
191-- Internal functions
105
192
106−-- | Grow current output by appending given 'Text' to it, which may not
193+-- | Type of the thing to output. Influences the primary low-level rendering
107−-- contain newlines.
194+-- function 'spit'.
108−
195+data SpitType
196+ = -- | Simple opaque text that breaks comment series.
197+ SimpleText
198+ | -- | Like 'SimpleText', but assume that when this text is inserted it
199+ -- will separate an 'Atom' and its pending comments, so insert an extra
200+ -- 'newline' in that case to force the pending comments and continue on
201+ -- a fresh line.
202+ InterferingText
203+ | -- | An atom that typically have span information in the AST and can
204+ -- have comments attached to it.
205+ Atom
206+ | -- | Used for rendering comment lines.
207+ CommentPart
208+ deriving (Show, Eq)
209+
210+-- | Output a fixed 'Text' fragment. The argument may not contain any line
211+-- breaks. 'txt' is used to output all sorts of “fixed” bits of syntax like
212+-- keywords and pipes @|@ in functional dependencies.
213+--
214+-- To separate various bits of syntax with white space use 'space' instead
215+-- of @'txt' " "@. To output 'Outputable' Haskell entities like numbers use
216+-- 'atom'.
217+txt ::
218+ -- | 'Text' to output
219+ Text ->
220+ R ()
221+txt = spit SimpleText
222+
223+-- | Similar to 'txt' but the text inserted this way is assumed to break the
224+-- “link” between the preceding atom and its pending comments.
225+interferingTxt ::
226+ -- | 'Text' to output
227+ Text ->
228+ R ()
229+interferingTxt = spit InterferingText
230+
231+-- | Output 'Outputable' fragment of AST. This can be used to output numeric
232+-- literals and similar. Everything that doesn't have inner structure but
233+-- does have an 'Outputable' instance.
234+atom ::
235+ Outputable a =>
236+ a ->
237+ R ()
238+atom = spit Atom . T.pack . showOutputable
239+
240+-- | Low-level non-public helper to define 'txt' and 'atom'.
241+spit ::
242+ -- | Type of the thing to spit
243+ SpitType ->
244+ -- | 'Text' to output
245+ Text ->
246+ R ()
109−spit :: Text -> R ()
247+spit _ "" = return ()
110−spit x = do
248+spit stype text = do
111− traceR "spit_before" (Just x)
249+ requestedDel <- R (gets scRequestedDelimiter)
112− R (modify modSC)
250+ pendingComments <- R (gets scPendingComments)
113− traceR "spit_after" Nothing
251+ when (stype == InterferingText && not (null pendingComments)) newline
114− where
252+ case requestedDel of
115− modSC sc = sc
253+ RequestedNewline -> do
254+ R . modify $ \sc ->
255+ sc
256+ { scRequestedDelimiter = RequestedNothing
257+ }
258+ case stype of
259+ CommentPart -> newlineRaw
260+ _ -> newline
261+ _ -> return ()
262+ R $ do
263+ i <- asks rcIndent
264+ c <- gets scColumn
265+ closestEnclosing <- listToMaybe <$> asks rcEnclosingSpans
266+ let indentedTxt = spaces <> text
267+ spaces = T.replicate spacesN " "
268+ spacesN =
269+ if c == 0
270+ then i
271+ else bool 0 1 (requestedDel == RequestedSpace)
272+ modify $ \sc ->
273+ sc
116− { scBuilder = scBuilder sc <> fromText x
274+ { scBuilder = scBuilder sc <> fromText indentedTxt,
117− , scColumn = scColumn sc + T.length x
275+ scColumn = scColumn sc + T.length indentedTxt,
118− }
276+ scIndent =
119−
277+ if c == 0
120−-- | Output a newline.
278+ then i
279+ else scIndent sc,
280+ scThisLineSpans =
281+ let xs = scThisLineSpans sc
282+ in case stype of
283+ Atom -> case closestEnclosing of
284+ Nothing -> xs
285+ Just x -> x : xs
286+ _ -> xs,
287+ scRequestedDelimiter = RequestedNothing,
288+ scSpanMark =
289+ -- If there are pending comments, do not reset last comment
290+ -- location.
291+ if (stype == CommentPart) || (not . null . scPendingComments) sc
292+ then scSpanMark sc
293+ else Nothing
294+ }
121
295
296+-- | This primitive /does not/ necessarily output a space. It just ensures
297+-- that the next thing that will be printed on the same line will be
298+-- separated by a single space from the previous output. Using this
299+-- combinator twice results in at most one space.
300+--
301+-- In practice this design prevents trailing white space and makes it hard
302+-- to output more than one delimiting space in a row, which is what we
303+-- usually want.
304+space :: R ()
305+space = R . modify $ \sc ->
306+ sc
307+ { scRequestedDelimiter = case scRequestedDelimiter sc of
308+ RequestedNothing -> RequestedSpace
309+ other -> other
310+ }
311+
312+-- | Output a newline. First time 'newline' is used after some non-'newline'
313+-- output it gets inserted immediately. Second use of 'newline' does not
314+-- output anything but makes sure that the next non-white space output will
315+-- be prefixed by a newline. Using 'newline' more than twice in a row has no
316+-- effect. Also, using 'newline' at the very beginning has no effect, this
317+-- is to avoid leading whitespace.
318+--
319+-- Similarly to 'space', this design prevents trailing newlines and makes it
320+-- hard to output more than one blank newline in a row.
122newline :: R ()
321newline :: R ()
123newline = do
322newline = do
124− traceR "newline_before" (Just "\n")
323+ indent <- R (gets scIndent)
125− R (modify modSC)
324+ cs <- reverse <$> R (gets scPendingComments)
126− traceR "newline_after" Nothing
325+ case cs of
127− where
326+ [] -> newlineRaw
128− modSC sc = sc
327+ ((position, _) : _) -> do
129− { scBuilder = scBuilder sc <> "\n"
328+ case position of
130− , scColumn = 0
329+ OnTheSameLine -> space
330+ OnNextLine -> newlineRaw
331+ R . forM_ cs $ \(_, text) ->
332+ let modRC rc =
333+ rc
334+ { rcIndent = indent
335+ }
336+ R m = do
337+ unless (T.null text) $
338+ spit CommentPart text
339+ newlineRaw
340+ in local modRC m
341+ R . modify $ \sc ->
342+ sc
343+ { scPendingComments = []
131− }
344+ }
132−
345+
133−-- | Ensure that indentation level is satisfied. Insert correct number of
346+-- | Low-level newline primitive. This one always just inserts a newline, no
134−-- spaces if it isn't.
347+-- hooks can be attached.
348+newlineRaw :: R ()
349+newlineRaw = R . modify $ \sc ->
350+ let requestedDel = scRequestedDelimiter sc
351+ builderSoFar = scBuilder sc
352+ in sc
353+ { scBuilder = case requestedDel of
354+ AfterNewline -> builderSoFar
355+ RequestedNewline -> builderSoFar
356+ VeryBeginning -> builderSoFar
357+ _ -> builderSoFar <> "\n",
358+ scColumn = 0,
359+ scIndent = 0,
360+ scThisLineSpans = [],
361+ scRequestedDelimiter = case scRequestedDelimiter sc of
362+ AfterNewline -> RequestedNewline
363+ RequestedNewline -> RequestedNewline
364+ VeryBeginning -> VeryBeginning
365+ _ -> AfterNewline
366+ }
135
367
136−ensureIndent :: R ()
368+-- | Return 'True' if we should print record dot syntax.
137−ensureIndent = do
369+useRecordDot :: R Bool
138− traceR "ensure_indent" Nothing
370+useRecordDot = R (asks rcUseRecDot)
139− i <- R (asks rcIndent)
140− c <- R (gets scColumn)
141− when (c < i) $
142− spit (T.replicate (i - c) " ")
143
371
144-- | Increase indentation level by one indentation step for the inner
372-- | Increase indentation level by one indentation step for the inner
145−-- computation.
373+-- computation. 'inci' should be used when a part of code must be more
146−
374+-- indented relative to the parts outside of 'inci' in order for the output
375+-- to be valid Haskell. When layout is single-line there is no obvious
376+-- effect, but with multi-line layout correct indentation levels matter.
147inci :: R () -> R ()
377inci :: R () -> R ()
148−inci m' = do
149− traceR "inci_before" Nothing
150− let R m = traceR "inci_inside" Nothing >> m'
151− R (local modRC m)
378+inci (R m) = R (local modRC m)
152− traceR "inci_ended" Nothing
153 where
379 where
154− modRC x = x
380+ modRC rc =
381+ rc
155− { rcIndent = rcIndent x + indentStep
382+ { rcIndent = rcIndent rc + indentStep
156− }
383+ }
157
384
158-- | Set indentation level for the inner computation equal to current
385-- | Set indentation level for the inner computation equal to current
159-- column. This makes sure that the entire inner block is uniformly
386-- column. This makes sure that the entire inner block is uniformly
160−-- \"shifted\" to the right. Only works (and makes sense) when enclosing
387+-- \"shifted\" to the right.
161−-- layout is multilined.
162−
163sitcc :: R () -> R ()
388sitcc :: R () -> R ()
164−sitcc m' = do
389+sitcc (R m) = do
165− traceR "sitcc_before" Nothing
390+ requestedDel <- R (gets scRequestedDelimiter)
166 i <- R (asks rcIndent)
391 i <- R (asks rcIndent)
167 c <- R (gets scColumn)
392 c <- R (gets scColumn)
168− let modRC x = x
393+ let modRC rc =
394+ rc
169− { rcIndent = max i c
395+ { rcIndent = max i (c + bool 0 1 (requestedDel == RequestedSpace))
170− }
171− R m = traceR "sitcc_inside" Nothing >> m'
172− vlayout m' (R (local modRC m))
173− traceR "sitcc_ended" Nothing
174−
175−-- | Relax alignment rules for comments inside this block. This is usually
176−-- done to avoid bumping indentation level too aggressively. Important for
177−-- beautiful rendering of e.g. type signatures.
178−
179−relaxComments :: R () -> R ()
180−relaxComments (R m) = do
181− traceR "relax_start" Nothing
182− let modRC x = x
183− { rcRelaxedComments = True
184− }
396+ }
185 R (local modRC m)
397 R (local modRC m)
186− traceR "relax_end" Nothing
187
398
188-- | Set 'Layout' for internal computation.
399-- | Set 'Layout' for internal computation.
189−
190enterLayout :: Layout -> R () -> R ()
400enterLayout :: Layout -> R () -> R ()
191−enterLayout l (R m) = do
401+enterLayout l (R m) = R (local modRC m)
192− let label =
402+ where
193− case l of
194− SingleLine -> "single_line"
195− MultiLine -> "multi_line"
196− traceR ("lstart_" ++ label) Nothing
197− let modRC x = x
403+ modRC rc =
404+ rc
198 { rcLayout = l
405 { rcLayout = l
199 }
406 }
200− R (local modRC m)
201− traceR ("lend_" ++ label) Nothing
202
407
203-- | Do one or another thing depending on current 'Layout'.
408-- | Do one or another thing depending on current 'Layout'.
204−
205−vlayout
409+vlayout ::
206− :: R () -- ^ Single line
410+ -- | Single line
411+ R a ->
207− -> R () -- ^ Multi line
412+ -- | Multi line
413+ R a ->
208− -> R ()
414+ R a
209vlayout sline mline = do
415vlayout sline mline = do
210− l <- currentLayout
416+ l <- getLayout
211 case l of
417 case l of
212 SingleLine -> sline
418 SingleLine -> sline
213 MultiLine -> mline
419 MultiLine -> mline
214
420
215−-- | Return current layout.
421+-- | Get current 'Layout'.
422+getLayout :: R Layout
423+getLayout = R (asks rcLayout)
216
424
217−currentLayout :: R Layout
425+----------------------------------------------------------------------------
218−currentLayout = R (asks rcLayout)
426+-- Special helpers for comment placement
427+
428+-- | Register a comment line for outputting. It will be inserted right
429+-- before next newline. When the comment goes after something else on the
430+-- same line, a space will be inserted between preceding text and the
431+-- comment when necessary.
432+registerPendingCommentLine ::
433+ -- | Comment position
434+ CommentPosition ->
435+ -- | 'Text' to output
436+ Text ->
437+ R ()
438+registerPendingCommentLine position text = R $ do
439+ modify $ \sc ->
440+ sc
441+ { scPendingComments = (position, text) : scPendingComments sc
442+ }
219
443
220−-- | Check whether we're in a region with relaxed comments placement.
444+-- | Drop elements that begin before or at the same place as given
445+-- 'SrcSpan'.
446+trimSpanStream ::
447+ -- | Reference span
448+ RealSrcSpan ->
449+ R ()
450+trimSpanStream ref = do
451+ let leRef :: RealSrcSpan -> Bool
452+ leRef x = realSrcSpanStart x <= realSrcSpanStart ref
453+ R . modify $ \sc ->
454+ sc
455+ { scSpanStream = coerce (dropWhile leRef) (scSpanStream sc)
456+ }
221
457
222−relaxedComments :: R Bool
458+-- | Get location of next element in AST.
223−relaxedComments = R (asks rcRelaxedComments)
459+nextEltSpan :: R (Maybe RealSrcSpan)
460+nextEltSpan = listToMaybe . coerce <$> R (gets scSpanStream)
461+
462+-- | Pop a 'Comment' from the 'CommentStream' if given predicate is
463+-- satisfied and there are comments in the stream.
464+popComment ::
465+ (RealLocated Comment -> Bool) ->
466+ R (Maybe (RealLocated Comment))
467+popComment f = R $ do
468+ CommentStream cstream <- gets scCommentStream
469+ case cstream of
470+ [] -> return Nothing
471+ (x : xs) ->
472+ if f x
473+ then
474+ Just x
475+ <$ modify
476+ ( \sc ->
477+ sc
478+ { scCommentStream = CommentStream xs
479+ }
480+ )
481+ else return Nothing
482+
483+-- | Get the first enclosing 'RealSrcSpan' that satisfies given predicate.
484+getEnclosingSpan ::
485+ -- | Predicate to use
486+ (RealSrcSpan -> Bool) ->
487+ R (Maybe RealSrcSpan)
488+getEnclosingSpan f =
489+ listToMaybe . filter f <$> R (asks rcEnclosingSpans)
490+
491+-- | Set 'RealSrcSpan' of enclosing span for the given computation.
492+withEnclosingSpan :: RealSrcSpan -> R () -> R ()
493+withEnclosingSpan spn (R m) = R (local modRC m)
494+ where
495+ modRC rc =
496+ rc
497+ { rcEnclosingSpans = spn : rcEnclosingSpans rc
498+ }
224
499
225−-- | Lookup an annotation.
500+-- | Get spans on this line so far.
501+thisLineSpans :: R [RealSrcSpan]
502+thisLineSpans = R (gets scThisLineSpans)
226
503
227−lookupAnn :: Data a => Located a -> R (Maybe Annotation)
504+----------------------------------------------------------------------------
228−lookupAnn l = M.lookup (mkAnnKey l) <$> R (asks rcAnns)
505+-- Stateful markers
506+
507+-- | An auxiliary marker for keeping track of last output element.
508+data SpanMark
509+ = -- | Haddock comment
510+ HaddockSpan HaddockStyle RealSrcSpan
511+ | -- | Non-haddock comment
512+ CommentSpan RealSrcSpan
513+ | -- | A statement in a do-block and such span
514+ StatementSpan RealSrcSpan
515+
516+-- | Project 'RealSrcSpan' from 'SpanMark'.
517+spanMarkSpan :: SpanMark -> RealSrcSpan
518+spanMarkSpan = \case
519+ HaddockSpan _ s -> s
520+ CommentSpan s -> s
521+ StatementSpan s -> s
522+
523+-- | Haddock string style.
524+data HaddockStyle
525+ = -- | @-- |@
526+ Pipe
527+ | -- | @-- ^@
528+ Caret
529+ | -- | @-- *@
530+ Asterisk Int
531+ | -- | @-- $@
532+ Named String
533+
534+-- | Set span of last output comment.
535+setSpanMark ::
536+ -- | Span mark to set
537+ SpanMark ->
538+ R ()
539+setSpanMark spnMark = R . modify $ \sc ->
540+ sc
541+ { scSpanMark = Just spnMark
542+ }
543+
544+-- | Get span of last output comment.
545+getSpanMark :: R (Maybe SpanMark)
546+getSpanMark = R (gets scSpanMark)
229
547
230----------------------------------------------------------------------------
548----------------------------------------------------------------------------
231−-- Debug helpers
549+-- Annotations
232−
550+
233−-- | Tracing helper.
551+-- | For a given span return 'AnnKeywordId's associated with it.
234−
552+getAnns ::
235−traceR
553+ SrcSpan ->
236− :: String -- ^ Label
554+ R [AnnKeywordId]
237− -> Maybe Text -- ^ Output, if any
555+getAnns spn = lookupAnns spn <$> R (asks rcAnns)
238− -> R ()
556+
239−traceR label moutput = R $ do
557+----------------------------------------------------------------------------
240− debug <- asks rcDebug
558+-- Helpers for braces
241− i <- asks rcIndent
559+
242− c <- gets scColumn
560+-- | Make the inner computation use braces around single-line layouts.
243− when debug . traceM . concat $
561+useBraces :: R () -> R ()
244− [ replicate i ' '
562+useBraces (R r) = R (local (\i -> i {rcCanUseBraces = True}) r)
245− , unwords [ label ++ ":"
563+
246− , "i=" ++ show i
564+-- | Make the inner computation omit braces around single-line layouts.
247− , "c=" ++ show c
565+dontUseBraces :: R () -> R ()
248− ]
566+dontUseBraces (R r) = R (local (\i -> i {rcCanUseBraces = False}) r)
249− ] ++ case moutput of
567+
250− Nothing -> []
568+-- | Return 'True' if we can use braces in this context.
251− Just output -> [" out=" ++ show output]
569+canUseBraces :: R Bool
570+canUseBraces = R (asks rcCanUseBraces)
252
571
253----------------------------------------------------------------------------
572----------------------------------------------------------------------------
254-- Constants
573-- Constants
255
574
256-- | Indentation step.
575-- | Indentation step.
257−
258indentStep :: Int
576indentStep :: Int
259indentStep = 2
577indentStep = 2
src/Ormolu/Printer/Meat/Common.hs+158−65
@@ -1,57 +1,108 @@
1−{-# LANGUAGE LambdaCase #-}
1+{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3
3
4-- | Rendering of commonly useful bits.
4-- | Rendering of commonly useful bits.
5−
6module Ormolu.Printer.Meat.Common
5module Ormolu.Printer.Meat.Common
6+ ( FamilyStyle (..),
7− ( p_hsmodName
7+ p_hsmodName,
8− , p_ieWrappedName
8+ p_ieWrappedName,
9− , p_rdrName
9+ p_rdrName,
10− , p_rdrName'
10+ doesNotNeedExtraParens,
11− , p_qualName
11+ p_qualName,
12− , p_ieWildcard
12+ p_infixDefHelper,
13− -- * Helpers
13+ p_hsDocString,
14− , opParens
14+ p_hsDocName,
15− , combineSrcSpans'
16− , getSpan
17− , unL
18 )
15 )
19where
16where
20
17
21−import Data.Char (isAlphaNum)
18+import Control.Monad
22−import Data.List.NonEmpty (NonEmpty (..))
19+import Data.List (isPrefixOf)
20+import qualified Data.Text as T
23import GHC hiding (GhcPs, IE)
21import GHC hiding (GhcPs, IE)
24−import Module (Module (..))
22+import Name (nameStableString)
25import OccName (OccName (..))
23import OccName (OccName (..))
26import Ormolu.Printer.Combinators
24import Ormolu.Printer.Combinators
27−import Outputable (Outputable (..), showSDocUnsafe)
25+import Ormolu.Utils
28−import RdrName (RdrName (..), rdrNameOcc)
26+
29−import SrcLoc (combineSrcSpans)
27+-- | Data and type family style.
28+data FamilyStyle
29+ = -- | Declarations in type classes
30+ Associated
31+ | -- | Top-level declarations
32+ Free
30
33
31p_hsmodName :: ModuleName -> R ()
34p_hsmodName :: ModuleName -> R ()
32p_hsmodName mname = do
35p_hsmodName mname = do
33− txt "module "
36+ txt "module"
37+ space
34 atom mname
38 atom mname
35
39
36p_ieWrappedName :: IEWrappedName RdrName -> R ()
40p_ieWrappedName :: IEWrappedName RdrName -> R ()
37p_ieWrappedName = \case
41p_ieWrappedName = \case
38− IEName l2 -> located l2 p_rdrName
42+ IEName x -> p_rdrName x
39− IEPattern l2 -> located l2 $ \x -> do
43+ IEPattern x -> do
40− txt "pattern "
44+ txt "pattern"
45+ space
41 p_rdrName x
46 p_rdrName x
42− IEType l2 -> located l2 $ \x -> do
47+ IEType x -> do
43− txt "type "
48+ txt "type"
49+ space
44 p_rdrName x
50 p_rdrName x
45
51
52+-- | Render a @'Located' 'RdrName'@.
46−p_rdrName :: RdrName -> R ()
53+p_rdrName :: Located RdrName -> R ()
47−p_rdrName x = opParens (rdrNameOcc x) (p_rdrName' x)
54+p_rdrName l@(L spn _) = located l $ \x -> do
48−
55+ ids <- getAnns spn
49−p_rdrName' :: RdrName -> R ()
56+ let backticksWrapper =
57+ if AnnBackquote `elem` ids
58+ then backticks
59+ else id
60+ parensWrapper =
61+ if AnnOpenP `elem` ids
62+ then parens N
63+ else id
64+ singleQuoteWrapper =
65+ if AnnSimpleQuote `elem` ids
66+ then \y -> do
67+ txt "'"
68+ y
69+ else id
70+ m =
50−p_rdrName' x = case x of
71+ case x of
51− Unqual occName -> atom occName
72+ Unqual occName ->
73+ atom occName
74+ Qual mname occName ->
52− Qual mname occName -> p_qualName mname occName
75+ p_qualName mname occName
53− Orig (Module _ mname) occName -> p_qualName mname occName
76+ Orig _ occName ->
77+ -- This is used when GHC generates code that will be fed into
78+ -- the renamer (e.g. from deriving clauses), but where we want
79+ -- to say that something comes from given module which is not
80+ -- specified in the source code, e.g. @Prelude.map@.
81+ --
82+ -- My current understanding is that the provided module name
83+ -- serves no purpose for us and can be safely ignored.
84+ atom occName
85+ Exact name ->
86+ atom name
87+ m' = backticksWrapper (singleQuoteWrapper m)
88+ if doesNotNeedExtraParens x
89+ then m'
90+ else parensWrapper m'
91+
92+-- | Whether given name should not have parentheses around it. This is used
93+-- to detect e.g. tuples for which annotations will indicate parentheses,
94+-- but the parentheses are already part of the symbol, so no extra layer of
95+-- parentheses should be added. It also detects the [] literal.
96+doesNotNeedExtraParens :: RdrName -> Bool
97+doesNotNeedExtraParens = \case
54− Exact name -> atom name
98+ Exact name ->
99+ let s = nameStableString name
100+ in -- I'm not sure this "stable string" is stable enough, but it looks
101+ -- like this is the most robust way to tell if we're looking at
102+ -- exactly this piece of built-in syntax.
103+ ("$ghc-prim$GHC.Tuple$" `isPrefixOf` s)
104+ || ("$ghc-prim$GHC.Types$[]" `isPrefixOf` s)
105+ _ -> False
55
106
56p_qualName :: ModuleName -> OccName -> R ()
107p_qualName :: ModuleName -> OccName -> R ()
57p_qualName mname occName = do
108p_qualName mname occName = do
@@ -59,34 +110,76 @@ p_qualName mname occName = do
59 txt "."
110 txt "."
60 atom occName
111 atom occName
61
112
62−p_ieWildcard :: IEWildcard -> R ()
113+-- | A helper for formatting infix constructions in lhs of definitions.
63−p_ieWildcard = \case
114+p_infixDefHelper ::
64− NoIEWildcard -> return ()
115+ -- | Whether to format in infix style
65− IEWildcard n -> parens (atom n)
116+ Bool ->
66−
117+ -- | Whether to bump indentation for arguments
67−----------------------------------------------------------------------------
118+ Bool ->
68−-- Helpers
119+ -- | How to print the operator\/name
69−
120+ R () ->
70−-- | Put parentheses around the second argument if the 'Outputable' thing
121+ -- | How to print the arguments
71−-- consists only of punctuation characters.
122+ [R ()] ->
72−
123+ R ()
73−opParens :: Outputable a => a -> R () -> R ()
124+p_infixDefHelper isInfix indentArgs name args =
74−opParens x m =
125+ case (isInfix, args) of
75− if all (not . isAlphaNum) (showSDocUnsafe (ppr x))
126+ (True, p0 : p1 : ps) -> do
76− then txt "(" >> m >> txt ")"
127+ let parens' =
77− else m
128+ if null ps
78−
129+ then id
79−-- | Combine all source spans from the given list.
130+ else parens N
80−
131+ parens' $ do
81−combineSrcSpans' :: NonEmpty SrcSpan -> SrcSpan
132+ p0
82−combineSrcSpans' (x:|xs) = foldr combineSrcSpans x xs
133+ breakpoint
83−
134+ inci . sitcc $ do
84−-- | Get source span from a 'Located' thing.
135+ name
85−
136+ space
86−getSpan :: Located e -> SrcSpan
137+ p1
87−getSpan (L spn _) = spn
138+ unless (null ps) . inciIf indentArgs $ do
88−
139+ breakpoint
89−-- | Exact inner value from 'Located'.
140+ sitcc (sep breakpoint sitcc ps)
90−
141+ (_, ps) -> do
91−unL :: Located e -> e
142+ name
92−unL (L _ e) = e
143+ unless (null ps) $ do
144+ breakpoint
145+ inciIf indentArgs $ sitcc (sep breakpoint sitcc args)
146+
147+-- | Print a Haddock.
148+p_hsDocString ::
149+ -- | Haddock style
150+ HaddockStyle ->
151+ -- | Finish the doc string with a newline
152+ Bool ->
153+ -- | The doc string to render
154+ LHsDocString ->
155+ R ()
156+p_hsDocString hstyle needsNewline (L l str) = do
157+ let isCommentSpan = \case
158+ HaddockSpan _ _ -> True
159+ CommentSpan _ -> True
160+ _ -> False
161+ goesAfterComment <- maybe False isCommentSpan <$> getSpanMark
162+ -- Make sure the Haddock is separated by a newline from other comments.
163+ when goesAfterComment newline
164+ forM_ (zip (splitDocString str) (True : repeat False)) $ \(x, isFirst) -> do
165+ if isFirst
166+ then case hstyle of
167+ Pipe -> txt "-- |"
168+ Caret -> txt "-- ^"
169+ Asterisk n -> txt ("-- " <> T.replicate n "*")
170+ Named name -> p_hsDocName name
171+ else newline >> txt "--"
172+ space
173+ unless (T.null x) (txt x)
174+ when needsNewline newline
175+ case l of
176+ UnhelpfulSpan _ ->
177+ -- It's often the case that the comment itself doesn't have a span
178+ -- attached to it and instead its location can be obtained from
179+ -- nearest enclosing span.
180+ getEnclosingSpan (const True) >>= mapM_ (setSpanMark . HaddockSpan hstyle)
181+ RealSrcSpan spn -> setSpanMark (HaddockSpan hstyle spn)
182+
183+-- | Print anchor of named doc section.
184+p_hsDocName :: String -> R ()
185+p_hsDocName name = txt ("-- $" <> T.pack name)
src/Ormolu/Printer/Meat/Declaration.hs+315−16
@@ -1,28 +1,327 @@
1−{-# LANGUAGE LambdaCase #-}
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE PatternSynonyms #-}
2{-# LANGUAGE RecordWildCards #-}
4{-# LANGUAGE RecordWildCards #-}
5+{-# LANGUAGE ViewPatterns #-}
3
6
4-- | Rendering of declarations.
7-- | Rendering of declarations.
5−
6module Ormolu.Printer.Meat.Declaration
8module Ormolu.Printer.Meat.Declaration
7− ( p_hsDecl
9+ ( p_hsDecls,
10+ p_hsDeclsRespectGrouping,
8 )
11 )
9where
12where
10
13
11−import HsDecls
14+import Data.List (sort)
12−import Language.Haskell.GHC.ExactPrint.Types
15+import Data.List.NonEmpty (NonEmpty (..), (<|))
16+import qualified Data.List.NonEmpty as NE
17+import GHC hiding (InlinePragma)
18+import OccName (occNameFS)
13import Ormolu.Printer.Combinators
19import Ormolu.Printer.Combinators
20+import Ormolu.Printer.Meat.Common
21+import Ormolu.Printer.Meat.Declaration.Annotation
22+import Ormolu.Printer.Meat.Declaration.Class
14import Ormolu.Printer.Meat.Declaration.Data
23import Ormolu.Printer.Meat.Declaration.Data
24+import Ormolu.Printer.Meat.Declaration.Default
25+import Ormolu.Printer.Meat.Declaration.Foreign
26+import Ormolu.Printer.Meat.Declaration.Instance
27+import Ormolu.Printer.Meat.Declaration.RoleAnnotation
28+import Ormolu.Printer.Meat.Declaration.Rule
29+import Ormolu.Printer.Meat.Declaration.Signature
30+import Ormolu.Printer.Meat.Declaration.Splice
15import Ormolu.Printer.Meat.Declaration.Type
31import Ormolu.Printer.Meat.Declaration.Type
16import Ormolu.Printer.Meat.Declaration.TypeFamily
32import Ormolu.Printer.Meat.Declaration.TypeFamily
33+import Ormolu.Printer.Meat.Declaration.Value
34+import Ormolu.Printer.Meat.Declaration.Warning
35+import Ormolu.Printer.Meat.Type
36+import Ormolu.Utils
37+
38+data UserGrouping
39+ = -- | Always put newlines where we think they should be
40+ Disregard
41+ | -- | Respect user preferences regarding grouping
42+ Respect
43+ deriving (Eq, Show)
44+
45+p_hsDecls :: FamilyStyle -> [LHsDecl GhcPs] -> R ()
46+p_hsDecls = p_hsDecls' Disregard
47+
48+-- | Like 'p_hsDecls' but respects user choices regarding grouping. If the
49+-- user omits newlines between declarations, we also omit them in most
50+-- cases, except when said declarations have associated Haddocks.
51+--
52+-- Does some normalization (compress subsequent newlines into a single one)
53+p_hsDeclsRespectGrouping :: FamilyStyle -> [LHsDecl GhcPs] -> R ()
54+p_hsDeclsRespectGrouping = p_hsDecls' Respect
55+
56+p_hsDecls' :: UserGrouping -> FamilyStyle -> [LHsDecl GhcPs] -> R ()
57+p_hsDecls' grouping style decls =
58+ sepSemi id $
59+ -- Return a list of rendered declarations, adding a newline to separate
60+ -- groups.
61+ case groupDecls decls of
62+ [] -> []
63+ (x : xs) -> renderGroup x ++ concat (zipWith renderGroupWithPrev (x : xs) xs)
64+ where
65+ renderGroup = NE.toList . fmap (located' $ dontUseBraces . p_hsDecl style)
66+ renderGroupWithPrev prev curr =
67+ -- We can omit a blank line when the user didn't add one, but we must
68+ -- ensure we always add blank lines around documented declarations
69+ case grouping of
70+ Disregard ->
71+ breakpoint : renderGroup curr
72+ Respect ->
73+ if separatedByBlankNE getLoc prev curr
74+ || isDocumented prev
75+ || isDocumented curr
76+ then breakpoint : renderGroup curr
77+ else renderGroup curr
78+
79+-- | Is a declaration group documented?
80+isDocumented :: NonEmpty (LHsDecl GhcPs) -> Bool
81+isDocumented = any (isHaddock . unLoc)
82+ where
83+ isHaddock DocNext = True
84+ isHaddock DocPrev = True
85+ isHaddock _ = False
86+
87+-- | Group relevant declarations together.
88+groupDecls :: [LHsDecl GhcPs] -> [NonEmpty (LHsDecl GhcPs)]
89+groupDecls [] = []
90+groupDecls (l@(L _ DocNext) : xs) =
91+ -- If the first element is a doc string for next element, just include it
92+ -- in the next block:
93+ case groupDecls xs of
94+ [] -> [l :| []]
95+ (x : xs') -> (l <| x) : xs'
96+groupDecls (header : xs) =
97+ let (grp, rest) = flip span (zip (header : xs) xs) $ \(previous, current) ->
98+ let relevantToHdr = groupedDecls header current
99+ relevantToPrev = groupedDecls previous current
100+ isDeclSeries = declSeries previous current
101+ in isDeclSeries || relevantToHdr || relevantToPrev
102+ in (header :| map snd grp) : groupDecls (map snd rest)
103+
104+p_hsDecl :: FamilyStyle -> HsDecl GhcPs -> R ()
105+p_hsDecl style = \case
106+ TyClD NoExtField x -> p_tyClDecl style x
107+ ValD NoExtField x -> p_valDecl x
108+ SigD NoExtField x -> p_sigDecl x
109+ InstD NoExtField x -> p_instDecl style x
110+ DerivD NoExtField x -> p_derivDecl x
111+ DefD NoExtField x -> p_defaultDecl x
112+ ForD NoExtField x -> p_foreignDecl x
113+ WarningD NoExtField x -> p_warnDecls x
114+ AnnD NoExtField x -> p_annDecl x
115+ RuleD NoExtField x -> p_ruleDecls x
116+ SpliceD NoExtField x -> p_spliceDecl x
117+ DocD NoExtField docDecl ->
118+ case docDecl of
119+ DocCommentNext str -> p_hsDocString Pipe False (noLoc str)
120+ DocCommentPrev str -> p_hsDocString Caret False (noLoc str)
121+ DocCommentNamed name str -> p_hsDocString (Named name) False (noLoc str)
122+ DocGroup n str -> p_hsDocString (Asterisk n) False (noLoc str)
123+ RoleAnnotD NoExtField x -> p_roleAnnot x
124+ KindSigD NoExtField s -> p_standaloneKindSig s
125+ XHsDecl x -> noExtCon x
126+
127+p_tyClDecl :: FamilyStyle -> TyClDecl GhcPs -> R ()
128+p_tyClDecl style = \case
129+ FamDecl NoExtField x -> p_famDecl style x
130+ SynDecl {..} -> p_synDecl tcdLName tcdFixity tcdTyVars tcdRhs
131+ DataDecl {..} ->
132+ p_dataDecl
133+ Associated
134+ tcdLName
135+ (tyVarsToTypes tcdTyVars)
136+ tcdFixity
137+ tcdDataDefn
138+ ClassDecl {..} ->
139+ p_classDecl
140+ tcdCtxt
141+ tcdLName
142+ tcdTyVars
143+ tcdFixity
144+ tcdFDs
145+ tcdSigs
146+ tcdMeths
147+ tcdATs
148+ tcdATDefs
149+ tcdDocs
150+ XTyClDecl x -> noExtCon x
151+
152+p_instDecl :: FamilyStyle -> InstDecl GhcPs -> R ()
153+p_instDecl style = \case
154+ ClsInstD NoExtField x -> p_clsInstDecl x
155+ TyFamInstD NoExtField x -> p_tyFamInstDecl style x
156+ DataFamInstD NoExtField x -> p_dataFamInstDecl style x
157+ XInstDecl x -> noExtCon x
158+
159+p_derivDecl :: DerivDecl GhcPs -> R ()
160+p_derivDecl = \case
161+ d@DerivDecl {} -> p_standaloneDerivDecl d
162+ XDerivDecl x -> noExtCon x
163+
164+-- | Determine if these declarations should be grouped together.
165+groupedDecls ::
166+ LHsDecl GhcPs ->
167+ LHsDecl GhcPs ->
168+ Bool
169+groupedDecls (L l_x x') (L l_y y') =
170+ case (x', y') of
171+ (TypeSignature ns, FunctionBody ns') -> ns `intersects` ns'
172+ (TypeSignature ns, DefaultSignature ns') -> ns `intersects` ns'
173+ (DefaultSignature ns, TypeSignature ns') -> ns `intersects` ns'
174+ (DefaultSignature ns, FunctionBody ns') -> ns `intersects` ns'
175+ (x, FunctionBody ns) | Just ns' <- isPragma x -> ns `intersects` ns'
176+ (FunctionBody ns, x) | Just ns' <- isPragma x -> ns `intersects` ns'
177+ (x, DataDeclaration n) | Just ns <- isPragma x -> n `elem` ns
178+ (DataDeclaration n, x)
179+ | Just ns <- isPragma x ->
180+ let f = occNameFS . rdrNameOcc in f n `elem` map f ns
181+ (x, y)
182+ | Just ns <- isPragma x,
183+ Just ns' <- isPragma y ->
184+ ns `intersects` ns'
185+ (x, TypeSignature ns) | Just ns' <- isPragma x -> ns `intersects` ns'
186+ (TypeSignature ns, x) | Just ns' <- isPragma x -> ns `intersects` ns'
187+ (PatternSignature ns, Pattern n) -> n `elem` ns
188+ (KindSignature n, DataDeclaration n') -> n == n'
189+ (KindSignature n, ClassDeclaration n') -> n == n'
190+ (KindSignature n, FamilyDeclaration n') -> n == n'
191+ -- Special case for TH splices, we look at locations
192+ (Splice, Splice) -> not (separatedByBlank id l_x l_y)
193+ -- This looks only at Haddocks, normal comments are handled elsewhere
194+ (DocNext, _) -> True
195+ (_, DocPrev) -> True
196+ _ -> False
197+
198+-- | Detect declaration series that should not have blanks between them.
199+declSeries ::
200+ LHsDecl GhcPs ->
201+ LHsDecl GhcPs ->
202+ Bool
203+declSeries (L _ x) (L _ y) =
204+ case (x, y) of
205+ ( SigD NoExtField (TypeSig NoExtField _ _),
206+ SigD NoExtField (TypeSig NoExtField _ _)
207+ ) -> True
208+ _ -> False
209+
210+intersects :: Ord a => [a] -> [a] -> Bool
211+intersects a b = go (sort a) (sort b)
212+ where
213+ go :: Ord a => [a] -> [a] -> Bool
214+ go _ [] = False
215+ go [] _ = False
216+ go (x : xs) (y : ys)
217+ | x < y = go xs (y : ys)
218+ | x > y = go (x : xs) ys
219+ | otherwise = True
220+
221+isPragma ::
222+ HsDecl GhcPs ->
223+ Maybe [RdrName]
224+isPragma = \case
225+ InlinePragma n -> Just [n]
226+ SpecializePragma n -> Just [n]
227+ SCCPragma n -> Just [n]
228+ AnnTypePragma n -> Just [n]
229+ AnnValuePragma n -> Just [n]
230+ WarningPragma n -> Just n
231+ _ -> Nothing
232+
233+-- Declarations that do not refer to names
234+
235+pattern Splice :: HsDecl GhcPs
236+pattern Splice <- SpliceD NoExtField (SpliceDecl NoExtField _ _)
237+
238+-- Declarations referring to a single name
239+
240+pattern
241+ InlinePragma,
242+ SpecializePragma,
243+ SCCPragma,
244+ AnnTypePragma,
245+ AnnValuePragma,
246+ Pattern,
247+ DataDeclaration,
248+ ClassDeclaration,
249+ KindSignature,
250+ FamilyDeclaration ::
251+ RdrName -> HsDecl GhcPs
252+pattern InlinePragma n <- SigD NoExtField (InlineSig NoExtField (L _ n) _)
253+pattern SpecializePragma n <- SigD NoExtField (SpecSig NoExtField (L _ n) _ _)
254+pattern SCCPragma n <- SigD NoExtField (SCCFunSig NoExtField _ (L _ n) _)
255+pattern AnnTypePragma n <- AnnD NoExtField (HsAnnotation NoExtField _ (TypeAnnProvenance (L _ n)) _)
256+pattern AnnValuePragma n <- AnnD NoExtField (HsAnnotation NoExtField _ (ValueAnnProvenance (L _ n)) _)
257+pattern Pattern n <- ValD NoExtField (PatSynBind NoExtField (PSB _ (L _ n) _ _ _))
258+pattern DataDeclaration n <- TyClD NoExtField (DataDecl NoExtField (L _ n) _ _ _)
259+pattern ClassDeclaration n <- TyClD NoExtField (ClassDecl NoExtField _ (L _ n) _ _ _ _ _ _ _ _)
260+pattern KindSignature n <- KindSigD NoExtField (StandaloneKindSig NoExtField (L _ n) _)
261+pattern FamilyDeclaration n <- TyClD NoExtField (FamDecl NoExtField (FamilyDecl NoExtField _ (L _ n) _ _ _ _))
262+
263+-- Declarations which can refer to multiple names
264+
265+pattern
266+ TypeSignature,
267+ DefaultSignature,
268+ FunctionBody,
269+ PatternSignature,
270+ WarningPragma ::
271+ [RdrName] -> HsDecl GhcPs
272+pattern TypeSignature n <- (sigRdrNames -> Just n)
273+pattern DefaultSignature n <- (defSigRdrNames -> Just n)
274+pattern FunctionBody n <- (funRdrNames -> Just n)
275+pattern PatternSignature n <- (patSigRdrNames -> Just n)
276+pattern WarningPragma n <- (warnSigRdrNames -> Just n)
277+
278+pattern DocNext, DocPrev :: HsDecl GhcPs
279+pattern DocNext <- (DocD NoExtField (DocCommentNext _))
280+pattern DocPrev <- (DocD NoExtField (DocCommentPrev _))
281+
282+sigRdrNames :: HsDecl GhcPs -> Maybe [RdrName]
283+sigRdrNames (SigD NoExtField (TypeSig NoExtField ns _)) = Just $ map unLoc ns
284+sigRdrNames (SigD NoExtField (ClassOpSig NoExtField _ ns _)) = Just $ map unLoc ns
285+sigRdrNames (SigD NoExtField (PatSynSig NoExtField ns _)) = Just $ map unLoc ns
286+sigRdrNames _ = Nothing
287+
288+defSigRdrNames :: HsDecl GhcPs -> Maybe [RdrName]
289+defSigRdrNames (SigD NoExtField (ClassOpSig NoExtField True ns _)) = Just $ map unLoc ns
290+defSigRdrNames _ = Nothing
291+
292+funRdrNames :: HsDecl GhcPs -> Maybe [RdrName]
293+funRdrNames (ValD NoExtField (FunBind NoExtField (L _ n) _ _ _)) = Just [n]
294+funRdrNames (ValD NoExtField (PatBind NoExtField (L _ n) _ _)) = Just $ patBindNames n
295+funRdrNames _ = Nothing
296+
297+patSigRdrNames :: HsDecl GhcPs -> Maybe [RdrName]
298+patSigRdrNames (SigD NoExtField (PatSynSig NoExtField ns _)) = Just $ map unLoc ns
299+patSigRdrNames _ = Nothing
300+
301+warnSigRdrNames :: HsDecl GhcPs -> Maybe [RdrName]
302+warnSigRdrNames (WarningD NoExtField (Warnings NoExtField _ ws)) = Just $
303+ flip concatMap ws $ \case
304+ L _ (Warning NoExtField ns _) -> map unLoc ns
305+ L _ (XWarnDecl x) -> noExtCon x
306+warnSigRdrNames _ = Nothing
17
307
18−p_hsDecl :: HsDecl GhcPs -> R ()
308+patBindNames :: Pat GhcPs -> [RdrName]
19−p_hsDecl = \case
309+patBindNames (TuplePat NoExtField ps _) = concatMap (patBindNames . unLoc) ps
20− TyClD x -> p_tyClDecl x
310+patBindNames (VarPat NoExtField (L _ n)) = [n]
21− _ -> error "this is not yet supported"
311+patBindNames (WildPat NoExtField) = []
22−
312+patBindNames (LazyPat NoExtField (L _ p)) = patBindNames p
23−p_tyClDecl :: TyClDecl GhcPs -> R ()
313+patBindNames (BangPat NoExtField (L _ p)) = patBindNames p
24−p_tyClDecl = \case
314+patBindNames (ParPat NoExtField (L _ p)) = patBindNames p
25− FamDecl x -> p_famDecl x
315+patBindNames (ListPat NoExtField ps) = concatMap (patBindNames . unLoc) ps
26− SynDecl {..} -> p_synDecl tcdLName tcdTyVars tcdRhs
316+patBindNames (AsPat NoExtField (L _ n) (L _ p)) = n : patBindNames p
27− DataDecl {..} -> p_dataDecl tcdLName tcdTyVars tcdDataDefn
317+patBindNames (SumPat NoExtField (L _ p) _ _) = patBindNames p
28− _ -> error "this is not yet supported"
318+patBindNames (ViewPat NoExtField _ (L _ p)) = patBindNames p
319+patBindNames (SplicePat NoExtField _) = []
320+patBindNames (LitPat NoExtField _) = []
321+patBindNames (SigPat _ (L _ p) _) = patBindNames p
322+patBindNames (NPat NoExtField _ _ _) = []
323+patBindNames (NPlusKPat NoExtField (L _ n) _ _ _ _) = [n]
324+patBindNames (ConPatIn _ d) = concatMap (patBindNames . unLoc) (hsConPatArgs d)
325+patBindNames ConPatOut {} = notImplemented "ConPatOut" -- created by renamer
326+patBindNames (CoPat NoExtField _ p _) = patBindNames p
327+patBindNames (XPat x) = noExtCon x
src/Ormolu/Printer/Meat/Declaration.hs-bootnew file+12
@@ -0,0 +1,12 @@
1+module Ormolu.Printer.Meat.Declaration
2+ ( p_hsDecls,
3+ p_hsDeclsRespectGrouping,
4+ )
5+where
6+
7+import GHC
8+import Ormolu.Printer.Combinators
9+import Ormolu.Printer.Meat.Common
10+
11+p_hsDecls :: FamilyStyle -> [LHsDecl GhcPs] -> R ()
12+p_hsDeclsRespectGrouping :: FamilyStyle -> [LHsDecl GhcPs] -> R ()
src/Ormolu/Printer/Meat/Declaration/Annotation.hsnew file+26
@@ -0,0 +1,26 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+
4+module Ormolu.Printer.Meat.Declaration.Annotation
5+ ( p_annDecl,
6+ )
7+where
8+
9+import GHC
10+import Ormolu.Printer.Combinators
11+import Ormolu.Printer.Meat.Common
12+import Ormolu.Printer.Meat.Declaration.Value
13+
14+p_annDecl :: AnnDecl GhcPs -> R ()
15+p_annDecl = \case
16+ HsAnnotation NoExtField _ annProv expr -> pragma "ANN" . inci $ do
17+ p_annProv annProv
18+ breakpoint
19+ located expr p_hsExpr
20+ XAnnDecl x -> noExtCon x
21+
22+p_annProv :: AnnProvenance (IdP GhcPs) -> R ()
23+p_annProv = \case
24+ ValueAnnProvenance name -> p_rdrName name
25+ TypeAnnProvenance name -> txt "type" >> space >> p_rdrName name
26+ ModuleAnnProvenance -> txt "module"
src/Ormolu/Printer/Meat/Declaration/Class.hsnew file+101
@@ -0,0 +1,101 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE RecordWildCards #-}
4+
5+-- | Rendering of type class declarations.
6+module Ormolu.Printer.Meat.Declaration.Class
7+ ( p_classDecl,
8+ )
9+where
10+
11+import Class
12+import Control.Arrow
13+import Control.Monad
14+import Data.Foldable
15+import Data.List (sortOn)
16+import GHC
17+import Ormolu.Printer.Combinators
18+import Ormolu.Printer.Meat.Common
19+import {-# SOURCE #-} Ormolu.Printer.Meat.Declaration
20+import Ormolu.Printer.Meat.Type
21+
22+p_classDecl ::
23+ LHsContext GhcPs ->
24+ Located RdrName ->
25+ LHsQTyVars GhcPs ->
26+ LexicalFixity ->
27+ [Located (FunDep (Located RdrName))] ->
28+ [LSig GhcPs] ->
29+ LHsBinds GhcPs ->
30+ [LFamilyDecl GhcPs] ->
31+ [LTyFamDefltDecl GhcPs] ->
32+ [LDocDecl] ->
33+ R ()
34+p_classDecl ctx name HsQTvs {..} fixity fdeps csigs cdefs cats catdefs cdocs = do
35+ let variableSpans = getLoc <$> hsq_explicit
36+ signatureSpans = getLoc name : variableSpans
37+ dependencySpans = getLoc <$> fdeps
38+ combinedSpans = getLoc ctx : (signatureSpans ++ dependencySpans)
39+ -- GHC's AST does not necessarily store each kind of element in source
40+ -- location order. This happens because different declarations are stored
41+ -- in different lists. Consequently, to get all the declarations in proper
42+ -- order, they need to be manually sorted.
43+ sigs = (getLoc &&& fmap (SigD NoExtField)) <$> csigs
44+ vals = (getLoc &&& fmap (ValD NoExtField)) <$> toList cdefs
45+ tyFams = (getLoc &&& fmap (TyClD NoExtField . FamDecl NoExtField)) <$> cats
46+ docs = (getLoc &&& fmap (DocD NoExtField)) <$> cdocs
47+ tyFamDefs =
48+ ( getLoc &&& fmap (InstD NoExtField . TyFamInstD NoExtField)
49+ )
50+ <$> catdefs
51+ allDecls =
52+ snd <$> sortOn fst (sigs <> vals <> tyFams <> tyFamDefs <> docs)
53+ txt "class"
54+ switchLayout combinedSpans $ do
55+ breakpoint
56+ inci $ do
57+ p_classContext ctx
58+ switchLayout signatureSpans $
59+ p_infixDefHelper
60+ (isInfix fixity)
61+ True
62+ (p_rdrName name)
63+ (located' p_hsTyVarBndr <$> hsq_explicit)
64+ inci (p_classFundeps fdeps)
65+ unless (null allDecls) $ do
66+ breakpoint
67+ txt "where"
68+ unless (null allDecls) $ do
69+ breakpoint -- Ensure whitespace is added after where clause.
70+ inci (p_hsDeclsRespectGrouping Associated allDecls)
71+p_classDecl _ _ (XLHsQTyVars c) _ _ _ _ _ _ _ = noExtCon c
72+
73+p_classContext :: LHsContext GhcPs -> R ()
74+p_classContext ctx = unless (null (unLoc ctx)) $ do
75+ located ctx p_hsContext
76+ space
77+ txt "=>"
78+ breakpoint
79+
80+p_classFundeps :: [Located (FunDep (Located RdrName))] -> R ()
81+p_classFundeps fdeps = unless (null fdeps) $ do
82+ breakpoint
83+ txt "|"
84+ space
85+ inci $ sep commaDel (sitcc . located' p_funDep) fdeps
86+
87+p_funDep :: FunDep (Located RdrName) -> R ()
88+p_funDep (before, after) = do
89+ sep space p_rdrName before
90+ space
91+ txt "->"
92+ space
93+ sep space p_rdrName after
94+
95+----------------------------------------------------------------------------
96+-- Helpers
97+
98+isInfix :: LexicalFixity -> Bool
99+isInfix = \case
100+ Infix -> True
101+ Prefix -> False
src/Ormolu/Printer/Meat/Declaration/Data.hs+230−91
@@ -1,122 +1,261 @@
1−{-# LANGUAGE LambdaCase #-}
1+{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE RecordWildCards #-}
3+{-# LANGUAGE RecordWildCards #-}
4
4
5+-- | Renedring of data type declarations.
5module Ormolu.Printer.Meat.Declaration.Data
6module Ormolu.Printer.Meat.Declaration.Data
6− ( p_dataDecl
7+ ( p_dataDecl,
7 )
8 )
8where
9where
9
10
10−import BasicTypes (DerivStrategy (..))
11import Control.Monad
11import Control.Monad
12−import Data.List.NonEmpty (nonEmpty)
13−import Data.Maybe (isJust)
12+import Data.Maybe (isJust, maybeToList)
14−import GHC hiding (GhcPs, IE)
13+import GHC
15−import Language.Haskell.GHC.ExactPrint.Types
16import Ormolu.Printer.Combinators
14import Ormolu.Printer.Combinators
17import Ormolu.Printer.Meat.Common
15import Ormolu.Printer.Meat.Common
18import Ormolu.Printer.Meat.Type
16import Ormolu.Printer.Meat.Type
19−import RdrName (RdrName (..))
17+import Ormolu.Utils
20−import SrcLoc (Located)
21
18
22−p_dataDecl
19+p_dataDecl ::
20+ -- | Whether to format as data family
21+ FamilyStyle ->
22+ -- | Type constructor
23− :: Located RdrName -- ^ Type constructor
23+ Located RdrName ->
24− -> LHsQTyVars GhcPs -- ^ Type variables
24+ -- | Type patterns
25+ [LHsType GhcPs] ->
26+ -- | Lexical fixity
27+ LexicalFixity ->
25− -> HsDataDefn GhcPs -- ^ Data definition
28+ -- | Data definition
29+ HsDataDefn GhcPs ->
26− -> R ()
30+ R ()
27−p_dataDecl name tvars HsDataDefn {..} = do
31+p_dataDecl style name tpats fixity HsDataDefn {..} = do
28− let HsQTvs {..} = tvars
29 txt $ case dd_ND of
32 txt $ case dd_ND of
30− NewType -> "newtype "
33+ NewType -> "newtype"
31− DataType -> "data "
34+ DataType -> "data"
35+ txt $ case style of
36+ Associated -> mempty
37+ Free -> " instance"
38+ let constructorSpans = getLoc name : fmap getLoc tpats
39+ switchLayout constructorSpans $ do
40+ breakpoint
41+ inci $
42+ p_infixDefHelper
43+ (isInfix fixity)
44+ True
32− located name p_rdrName'
45+ (p_rdrName name)
33− unless (null hsq_explicit) space
46+ (located' p_hsType <$> tpats)
34− spaceSep (located' p_hsTyVarBndr) hsq_explicit
35 case dd_kindSig of
47 case dd_kindSig of
36 Nothing -> return ()
48 Nothing -> return ()
37 Just k -> do
49 Just k -> do
38 space
50 space
39− txt ":: "
51+ txt "::"
52+ space
40− relaxComments (located k p_hsType)
53+ located k p_hsType
41− let gadt = isJust dd_kindSig || any (isGadt . unL) dd_cons
54+ let gadt = isJust dd_kindSig || any (isGadt . unLoc) dd_cons
42− case nonEmpty dd_cons of
55+ unless (null dd_cons) $
43− Nothing -> pure ()
44− Just dd_cons_ne ->
45− if gadt
56+ if gadt
46− then do
57+ then inci $ do
47− txt " where"
58+ switchLayout constructorSpans $ do
48− newline
49− inci $ newlineSep (located' p_conDecl) dd_cons
50− else switchLayout (combineSrcSpans' (getSpan <$> dd_cons_ne)) $ do
51 breakpoint
59 breakpoint
52− inci $ do
60+ txt "where"
53− txt "= "
61+ breakpoint
54− let sep = vlayout (txt " | ") (txt "| ")
62+ sepSemi (located' (p_conDecl False)) dd_cons
63+ else switchLayout (getLoc name : (getLoc <$> dd_cons)) . inci $ do
64+ let singleConstRec = isSingleConstRec dd_cons
65+ if singleConstRec
66+ then space
67+ else
68+ if hasHaddocks dd_cons
69+ then newline
70+ else breakpoint
71+ equals
72+ space
73+ layout <- getLayout
74+ let s =
75+ if layout == MultiLine || hasHaddocks dd_cons
76+ then newline >> txt "|" >> space
77+ else space >> txt "|" >> space
78+ sitcc' =
79+ if singleConstRec
80+ then id
81+ else sitcc
55− velt $ withSep sep (located' p_conDecl) dd_cons
82+ sep s (sitcc' . located' (p_conDecl singleConstRec)) dd_cons
56− newline
83+ unless (null $ unLoc dd_derivs) breakpoint
57 inci . located dd_derivs $ \xs ->
84 inci . located dd_derivs $ \xs ->
58− forM_ xs (line . located' p_hsDerivingClause)
85+ sep newline (located' p_hsDerivingClause) xs
86+p_dataDecl _ _ _ _ (XHsDataDefn x) = noExtCon x
59
87
88+p_conDecl ::
89+ Bool ->
60−p_conDecl :: ConDecl GhcPs -> R ()
90+ ConDecl GhcPs ->
91+ R ()
61−p_conDecl = \case
92+p_conDecl singleConstRec = \case
62− ConDeclGADT {..} -> velt'
93+ ConDeclGADT {..} -> do
94+ mapM_ (p_hsDocString Pipe True) con_doc
95+ let conDeclSpn =
96+ fmap getLoc con_names
97+ <> [getLoc con_forall]
98+ <> conTyVarsSpans con_qvars
99+ <> maybeToList (fmap getLoc con_mb_cxt)
100+ <> conArgsSpans con_args
101+ switchLayout conDeclSpn $ do
102+ case con_names of
103+ [] -> return ()
104+ (c : cs) -> do
63− [ spaceSep (located' p_rdrName') con_names
105+ p_rdrName c
106+ unless (null cs) . inci $ do
107+ commaDel
108+ sep commaDel p_rdrName cs
64− , inci $ do
109+ inci $ do
110+ space
65− txt ":: "
111+ txt "::"
66− relaxComments (locatedVia Nothing (hsib_body con_type) p_hsType)
112+ let interArgBreak =
67− ]
113+ if hasDocStrings (unLoc con_res_ty)
114+ then newline
115+ else breakpoint
116+ interArgBreak
117+ when (unLoc con_forall) $ do
118+ p_forallBndrs ForallInvis p_hsTyVarBndr (hsq_explicit con_qvars)
119+ interArgBreak
120+ forM_ con_mb_cxt p_lhsContext
121+ case con_args of
122+ PrefixCon xs -> do
123+ sep breakpoint (located' p_hsType) xs
124+ unless (null xs) $ do
125+ space
126+ txt "->"
127+ breakpoint
128+ RecCon l -> do
129+ located l p_conDeclFields
130+ unless (null $ unLoc l) $ do
131+ space
132+ txt "->"
133+ breakpoint
134+ InfixCon _ _ -> notImplemented "InfixCon"
135+ p_hsType (unLoc con_res_ty)
68 ConDeclH98 {..} -> do
136 ConDeclH98 {..} -> do
69− case hsq_explicit <$> con_qvars of
137+ mapM_ (p_hsDocString Pipe True) con_doc
70− Nothing -> return ()
138+ let conDeclWithContextSpn =
71− Just bndrs -> do
139+ [getLoc con_forall]
72− txt "forall "
140+ <> fmap getLoc con_ex_tvs
73− spaceSep (located' p_hsTyVarBndr) bndrs
141+ <> maybeToList (fmap getLoc con_mb_cxt)
74− txt "."
142+ <> conDeclSpn
143+ conDeclSpn =
144+ getLoc con_name : conArgsSpans con_args
145+ switchLayout conDeclWithContextSpn $ do
146+ when (unLoc con_forall) $ do
147+ p_forallBndrs ForallInvis p_hsTyVarBndr con_ex_tvs
75 breakpoint
148 breakpoint
76− case con_cxt of
149+ forM_ con_mb_cxt p_lhsContext
77− Nothing -> return ()
150+ switchLayout conDeclSpn $ case con_args of
78− Just ctx -> located ctx $ \case
151+ PrefixCon xs -> do
79− [] -> pure ()
152+ p_rdrName con_name
80− xs -> do
153+ unless (null xs) breakpoint
81− p_hsContext xs
154+ inci . sitcc $ sep breakpoint (sitcc . located' p_hsTypePostDoc) xs
155+ RecCon l -> do
156+ p_rdrName con_name
82 breakpoint
157 breakpoint
158+ inciIf (not singleConstRec) (located l p_conDeclFields)
159+ InfixCon x y -> do
160+ located x p_hsType
161+ breakpoint
162+ inci $ do
163+ p_rdrName con_name
164+ space
165+ located y p_hsType
166+ XConDecl x -> noExtCon x
167+
168+conArgsSpans :: HsConDeclDetails GhcPs -> [SrcSpan]
169+conArgsSpans = \case
170+ PrefixCon xs ->
171+ getLoc <$> xs
172+ RecCon l ->
173+ [getLoc l]
174+ InfixCon x y ->
175+ [getLoc x, getLoc y]
176+
177+conTyVarsSpans :: LHsQTyVars GhcPs -> [SrcSpan]
178+conTyVarsSpans = \case
179+ HsQTvs {..} -> getLoc <$> hsq_explicit
180+ XLHsQTyVars x -> noExtCon x
181+
182+p_lhsContext ::
183+ LHsContext GhcPs ->
184+ R ()
185+p_lhsContext = \case
186+ L _ [] -> pure ()
187+ ctx -> do
188+ located ctx p_hsContext
189+ space
83− txt "=> "
190+ txt "=>"
84− case con_details of
85− PrefixCon xs -> do
86− located con_name p_rdrName'
87− unless (null xs) breakpoint
191+ breakpoint
88− inci $ velt' (located' p_hsType <$> xs)
89− RecCon l -> do
90− located con_name p_rdrName'
91− breakpoint
92− inci $ located l p_conDeclFields
93− InfixCon x y -> velt'
94− [ located x p_hsType
95− , inci $ velt'
96− [ backticks (located con_name p_rdrName')
97− , inci $ located y p_hsType
98− ]
99− ]
100
192
101isGadt :: ConDecl GhcPs -> Bool
193isGadt :: ConDecl GhcPs -> Bool
102isGadt = \case
194isGadt = \case
103 ConDeclGADT {} -> True
195 ConDeclGADT {} -> True
104 ConDeclH98 {} -> False
196 ConDeclH98 {} -> False
197+ XConDecl {} -> False
105
198
106−p_hsDerivingClause
199+p_hsDerivingClause ::
107− :: HsDerivingClause GhcPs
200+ HsDerivingClause GhcPs ->
108− -> R ()
201+ R ()
109p_hsDerivingClause HsDerivingClause {..} = do
202p_hsDerivingClause HsDerivingClause {..} = do
110 txt "deriving"
203 txt "deriving"
204+ let derivingWhat = located deriv_clause_tys $ \case
205+ [] -> txt "()"
206+ xs ->
207+ parens N $
208+ sep
209+ commaDel
210+ (sitcc . located' p_hsType . hsib_body)
211+ xs
212+ space
111 case deriv_clause_strategy of
213 case deriv_clause_strategy of
112− Nothing -> return ()
214+ Nothing -> do
113− Just l -> do
215+ breakpoint
114− space
216+ inci derivingWhat
115− located l $ \case
217+ Just (L _ a) -> case a of
116− StockStrategy -> txt "stock"
218+ StockStrategy -> do
219+ txt "stock"
220+ breakpoint
221+ inci derivingWhat
117− AnyclassStrategy -> txt "anyclass"
222+ AnyclassStrategy -> do
223+ txt "anyclass"
224+ breakpoint
225+ inci derivingWhat
118− NewtypeStrategy -> txt "newtype"
226+ NewtypeStrategy -> do
227+ txt "newtype"
119− breakpoint
228+ breakpoint
120− inci . located deriv_clause_tys $ \case
229+ inci derivingWhat
230+ ViaStrategy HsIB {..} -> do
231+ breakpoint
232+ inci $ do
233+ derivingWhat
234+ breakpoint
121− [] -> txt "()"
235+ txt "via"
236+ space
122− xs -> parens . velt $ withSep comma (located' p_hsType . hsib_body) xs
237+ located hsib_body p_hsType
238+ ViaStrategy (XHsImplicitBndrs x) ->
239+ noExtCon x
240+p_hsDerivingClause (XHsDerivingClause x) = noExtCon x
241+
242+----------------------------------------------------------------------------
243+-- Helpers
244+
245+isInfix :: LexicalFixity -> Bool
246+isInfix = \case
247+ Infix -> True
248+ Prefix -> False
249+
250+isSingleConstRec :: [LConDecl GhcPs] -> Bool
251+isSingleConstRec [(L _ ConDeclH98 {..})] =
252+ case con_args of
253+ RecCon _ -> True
254+ _ -> False
255+isSingleConstRec _ = False
256+
257+hasHaddocks :: [LConDecl GhcPs] -> Bool
258+hasHaddocks = any (f . unLoc)
259+ where
260+ f ConDeclH98 {..} = isJust con_doc
261+ f _ = False
src/Ormolu/Printer/Meat/Declaration/Default.hsnew file+20
@@ -0,0 +1,20 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+
4+module Ormolu.Printer.Meat.Declaration.Default
5+ ( p_defaultDecl,
6+ )
7+where
8+
9+import GHC
10+import Ormolu.Printer.Combinators
11+import Ormolu.Printer.Meat.Type
12+
13+p_defaultDecl :: DefaultDecl GhcPs -> R ()
14+p_defaultDecl = \case
15+ DefaultDecl NoExtField ts -> do
16+ txt "default"
17+ breakpoint
18+ inci . parens N $
19+ sep commaDel (sitcc . located' p_hsType) ts
20+ XDefaultDecl x -> noExtCon x
src/Ormolu/Printer/Meat/Declaration/Foreign.hsnew file+74
@@ -0,0 +1,74 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE NamedFieldPuns #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+
5+module Ormolu.Printer.Meat.Declaration.Foreign
6+ ( p_foreignDecl,
7+ )
8+where
9+
10+import BasicTypes
11+import Control.Monad
12+import Data.Text
13+import ForeignCall
14+import GHC
15+import Ormolu.Printer.Combinators
16+import Ormolu.Printer.Meat.Common
17+import Ormolu.Printer.Meat.Declaration.Signature
18+
19+p_foreignDecl :: ForeignDecl GhcPs -> R ()
20+p_foreignDecl = \case
21+ fd@ForeignImport {fd_fi} -> do
22+ p_foreignImport fd_fi
23+ p_foreignTypeSig fd
24+ fd@ForeignExport {fd_fe} -> do
25+ p_foreignExport fd_fe
26+ p_foreignTypeSig fd
27+ XForeignDecl x -> noExtCon x
28+
29+-- | Printer for the last part of an import\/export, which is function name
30+-- and type signature.
31+p_foreignTypeSig :: ForeignDecl GhcPs -> R ()
32+p_foreignTypeSig fd = do
33+ breakpoint
34+ inci
35+ . switchLayout
36+ [ getLoc (fd_name fd),
37+ (getLoc . hsib_body . fd_sig_ty) fd
38+ ]
39+ $ do
40+ p_rdrName (fd_name fd)
41+ p_typeAscription (HsWC NoExtField (fd_sig_ty fd))
42+
43+-- | Printer for 'ForeignImport'.
44+--
45+-- These have the form:
46+--
47+-- > foreign import callingConvention [safety] [identifier]
48+--
49+-- We need to check whether the safety has a good source, span, as it
50+-- defaults to 'PlaySafe' if you don't have anything in the source.
51+--
52+-- We also layout the identifier using the 'SourceText', because printing
53+-- with the other two fields of 'CImport' is very complicated. See the
54+-- 'Outputable' instance of 'ForeignImport' for details.
55+p_foreignImport :: ForeignImport -> R ()
56+p_foreignImport (CImport cCallConv safety _ _ sourceText) = do
57+ txt "foreign import"
58+ space
59+ located cCallConv atom
60+ -- Need to check for 'noLoc' for the 'safe' annotation
61+ when (isGoodSrcSpan $ getLoc safety) (space >> atom safety)
62+ located sourceText p_sourceText
63+
64+p_foreignExport :: ForeignExport -> R ()
65+p_foreignExport (CExport (L loc (CExportStatic _ _ cCallConv)) sourceText) = do
66+ txt "foreign export"
67+ space
68+ located (L loc cCallConv) atom
69+ located sourceText p_sourceText
70+
71+p_sourceText :: SourceText -> R ()
72+p_sourceText = \case
73+ NoSourceText -> pure ()
74+ SourceText s -> space >> txt (pack s)
src/Ormolu/Printer/Meat/Declaration/Instance.hsnew file+131
@@ -0,0 +1,131 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE RecordWildCards #-}
4+
5+-- | Type class, type family, and data family instance declarations.
6+module Ormolu.Printer.Meat.Declaration.Instance
7+ ( p_clsInstDecl,
8+ p_tyFamInstDecl,
9+ p_dataFamInstDecl,
10+ p_standaloneDerivDecl,
11+ )
12+where
13+
14+import BasicTypes
15+import Control.Arrow
16+import Control.Monad
17+import Data.Foldable
18+import Data.List (sortOn)
19+import GHC
20+import Ormolu.Printer.Combinators
21+import Ormolu.Printer.Meat.Common
22+import {-# SOURCE #-} Ormolu.Printer.Meat.Declaration
23+import Ormolu.Printer.Meat.Declaration.Data
24+import Ormolu.Printer.Meat.Declaration.TypeFamily
25+import Ormolu.Printer.Meat.Type
26+import Ormolu.Utils
27+
28+p_standaloneDerivDecl :: DerivDecl GhcPs -> R ()
29+p_standaloneDerivDecl DerivDecl {..} = do
30+ let typesAfterInstance = located (hsib_body (hswc_body deriv_type)) p_hsType
31+ instTypes toIndent = inci $ do
32+ txt "instance"
33+ breakpoint
34+ match_overlap_mode deriv_overlap_mode breakpoint
35+ inciIf toIndent typesAfterInstance
36+ txt "deriving"
37+ space
38+ case deriv_strategy of
39+ Nothing ->
40+ instTypes False
41+ Just (L _ a) -> case a of
42+ StockStrategy -> do
43+ txt "stock "
44+ instTypes False
45+ AnyclassStrategy -> do
46+ txt "anyclass "
47+ instTypes False
48+ NewtypeStrategy -> do
49+ txt "newtype "
50+ instTypes False
51+ ViaStrategy HsIB {..} -> do
52+ txt "via"
53+ breakpoint
54+ inci (located hsib_body p_hsType)
55+ breakpoint
56+ instTypes True
57+ ViaStrategy (XHsImplicitBndrs x) ->
58+ noExtCon x
59+p_standaloneDerivDecl (XDerivDecl _) = notImplemented "XDerivDecl"
60+
61+p_clsInstDecl :: ClsInstDecl GhcPs -> R ()
62+p_clsInstDecl = \case
63+ ClsInstDecl {..} -> do
64+ txt "instance"
65+ case cid_poly_ty of
66+ HsIB {..} -> do
67+ -- GHC's AST does not necessarily store each kind of element in source
68+ -- location order. This happens because different declarations are stored in
69+ -- different lists. Consequently, to get all the declarations in proper
70+ -- order, they need to be manually sorted.
71+ let sigs = (getLoc &&& fmap (SigD NoExtField)) <$> cid_sigs
72+ vals = (getLoc &&& fmap (ValD NoExtField)) <$> toList cid_binds
73+ tyFamInsts =
74+ ( getLoc &&& fmap (InstD NoExtField . TyFamInstD NoExtField)
75+ )
76+ <$> cid_tyfam_insts
77+ dataFamInsts =
78+ ( getLoc &&& fmap (InstD NoExtField . DataFamInstD NoExtField)
79+ )
80+ <$> cid_datafam_insts
81+ allDecls =
82+ snd <$> sortOn fst (sigs <> vals <> tyFamInsts <> dataFamInsts)
83+ located hsib_body $ \x -> do
84+ breakpoint
85+ inci $ do
86+ match_overlap_mode cid_overlap_mode breakpoint
87+ p_hsType x
88+ unless (null allDecls) $ do
89+ breakpoint
90+ txt "where"
91+ unless (null allDecls) . inci $ do
92+ -- Ensure whitespace is added after where clause.
93+ breakpoint
94+ dontUseBraces $ p_hsDeclsRespectGrouping Associated allDecls
95+ XHsImplicitBndrs x -> noExtCon x
96+ XClsInstDecl x -> noExtCon x
97+
98+p_tyFamInstDecl :: FamilyStyle -> TyFamInstDecl GhcPs -> R ()
99+p_tyFamInstDecl style = \case
100+ TyFamInstDecl {..} -> do
101+ txt $ case style of
102+ Associated -> "type"
103+ Free -> "type instance"
104+ breakpoint
105+ inci (p_tyFamInstEqn tfid_eqn)
106+
107+p_dataFamInstDecl :: FamilyStyle -> DataFamInstDecl GhcPs -> R ()
108+p_dataFamInstDecl style = \case
109+ DataFamInstDecl {dfid_eqn = HsIB {hsib_body = FamEqn {..}}} ->
110+ p_dataDecl style feqn_tycon (map typeArgToType feqn_pats) feqn_fixity feqn_rhs
111+ DataFamInstDecl {dfid_eqn = HsIB {hsib_body = XFamEqn {}}} ->
112+ notImplemented "XFamEqn"
113+ DataFamInstDecl {dfid_eqn = XHsImplicitBndrs {}} ->
114+ notImplemented "XHsImplicitBndrs"
115+
116+match_overlap_mode :: Maybe (Located OverlapMode) -> R () -> R ()
117+match_overlap_mode overlap_mode layoutStrategy =
118+ case unLoc <$> overlap_mode of
119+ Just Overlappable {} -> do
120+ txt "{-# OVERLAPPABLE #-}"
121+ layoutStrategy
122+ Just Overlapping {} -> do
123+ txt "{-# OVERLAPPING #-}"
124+ layoutStrategy
125+ Just Overlaps {} -> do
126+ txt "{-# OVERLAPS #-}"
127+ layoutStrategy
128+ Just Incoherent {} -> do
129+ txt "{-# INCOHERENT #-}"
130+ layoutStrategy
131+ _ -> pure ()
src/Ormolu/Printer/Meat/Declaration/RoleAnnotation.hsnew file+35
@@ -0,0 +1,35 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE TypeFamilies #-}
4+
5+-- | Rendering of Role annotation declarations.
6+module Ormolu.Printer.Meat.Declaration.RoleAnnotation
7+ ( p_roleAnnot,
8+ )
9+where
10+
11+import CoAxiom
12+import GHC
13+import Ormolu.Printer.Combinators
14+import Ormolu.Printer.Meat.Common
15+
16+p_roleAnnot :: RoleAnnotDecl GhcPs -> R ()
17+p_roleAnnot = \case
18+ RoleAnnotDecl NoExtField l_name anns -> p_roleAnnot' l_name anns
19+ XRoleAnnotDecl x -> noExtCon x
20+
21+p_roleAnnot' :: Located RdrName -> [Located (Maybe Role)] -> R ()
22+p_roleAnnot' l_name anns = do
23+ txt "type role"
24+ breakpoint
25+ inci $ do
26+ p_rdrName l_name
27+ breakpoint
28+ let p_role' = maybe (txt "_") p_role
29+ inci . sitcc $ sep breakpoint (sitcc . located' p_role') anns
30+
31+p_role :: Role -> R ()
32+p_role = \case
33+ Nominal -> txt "nominal"
34+ Representational -> txt "representational"
35+ Phantom -> txt "phantom"
src/Ormolu/Printer/Meat/Declaration/Rule.hsnew file+61
@@ -0,0 +1,61 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+
4+module Ormolu.Printer.Meat.Declaration.Rule
5+ ( p_ruleDecls,
6+ )
7+where
8+
9+import BasicTypes
10+import Control.Monad (unless)
11+import GHC
12+import Ormolu.Printer.Combinators
13+import Ormolu.Printer.Meat.Common
14+import Ormolu.Printer.Meat.Declaration.Signature
15+import Ormolu.Printer.Meat.Declaration.Value
16+import Ormolu.Printer.Meat.Type
17+
18+p_ruleDecls :: RuleDecls GhcPs -> R ()
19+p_ruleDecls = \case
20+ HsRules NoExtField _ xs ->
21+ pragma "RULES" $
22+ sep breakpoint (sitcc . located' p_ruleDecl) xs
23+ XRuleDecls x -> noExtCon x
24+
25+p_ruleDecl :: RuleDecl GhcPs -> R ()
26+p_ruleDecl = \case
27+ HsRule NoExtField ruleName activation tyvars ruleBndrs lhs rhs -> do
28+ located ruleName p_ruleName
29+ space
30+ p_activation activation
31+ space
32+ case tyvars of
33+ Nothing -> return ()
34+ Just xs -> do
35+ p_forallBndrs ForallInvis p_hsTyVarBndr xs
36+ space
37+ -- It appears that there is no way to tell if there was an empty forall
38+ -- in the input or no forall at all. We do not want to add redundant
39+ -- foralls, so let's just skip the empty ones.
40+ unless (null ruleBndrs) $
41+ p_forallBndrs ForallInvis p_ruleBndr ruleBndrs
42+ breakpoint
43+ inci $ do
44+ located lhs p_hsExpr
45+ space
46+ equals
47+ inci $ do
48+ breakpoint
49+ located rhs p_hsExpr
50+ XRuleDecl x -> noExtCon x
51+
52+p_ruleName :: (SourceText, RuleName) -> R ()
53+p_ruleName (_, name) = atom $ (HsString NoSourceText name :: HsLit GhcPs)
54+
55+p_ruleBndr :: RuleBndr GhcPs -> R ()
56+p_ruleBndr = \case
57+ RuleBndr NoExtField x -> p_rdrName x
58+ RuleBndrSig NoExtField x hswc -> parens N $ do
59+ p_rdrName x
60+ p_typeAscription hswc
61+ XRuleBndr x -> noExtCon x
src/Ormolu/Printer/Meat/Declaration/Signature.hsnew file+236
@@ -0,0 +1,236 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE RecordWildCards #-}
4+
5+-- | Type signature declarations.
6+module Ormolu.Printer.Meat.Declaration.Signature
7+ ( p_sigDecl,
8+ p_typeAscription,
9+ p_activation,
10+ p_standaloneKindSig,
11+ )
12+where
13+
14+import BasicTypes
15+import BooleanFormula
16+import Control.Monad
17+import GHC
18+import Ormolu.Printer.Combinators
19+import Ormolu.Printer.Meat.Common
20+import Ormolu.Printer.Meat.Type
21+import Ormolu.Utils
22+
23+p_sigDecl :: Sig GhcPs -> R ()
24+p_sigDecl = \case
25+ TypeSig NoExtField names hswc -> p_typeSig True names hswc
26+ PatSynSig NoExtField names hsib -> p_patSynSig names hsib
27+ ClassOpSig NoExtField def names hsib -> p_classOpSig def names hsib
28+ FixSig NoExtField sig -> p_fixSig sig
29+ InlineSig NoExtField name inlinePragma -> p_inlineSig name inlinePragma
30+ SpecSig NoExtField name ts inlinePragma -> p_specSig name ts inlinePragma
31+ SpecInstSig NoExtField _ hsib -> p_specInstSig hsib
32+ MinimalSig NoExtField _ booleanFormula -> p_minimalSig booleanFormula
33+ CompleteMatchSig NoExtField _sourceText cs ty -> p_completeSig cs ty
34+ SCCFunSig NoExtField _ name literal -> p_sccSig name literal
35+ _ -> notImplemented "certain types of signature declarations"
36+
37+p_typeSig ::
38+ -- | Should the tail of the names be indented
39+ Bool ->
40+ -- | Names (before @::@)
41+ [Located RdrName] ->
42+ -- | Type
43+ LHsSigWcType GhcPs ->
44+ R ()
45+p_typeSig _ [] _ = return () -- should not happen though
46+p_typeSig indentTail (n : ns) hswc = do
47+ p_rdrName n
48+ if null ns
49+ then p_typeAscription hswc
50+ else inciIf indentTail $ do
51+ commaDel
52+ sep commaDel p_rdrName ns
53+ p_typeAscription hswc
54+
55+p_typeAscription ::
56+ LHsSigWcType GhcPs ->
57+ R ()
58+p_typeAscription HsWC {..} = inci $ do
59+ space
60+ txt "::"
61+ let t = hsib_body hswc_body
62+ if hasDocStrings (unLoc t)
63+ then newline
64+ else breakpoint
65+ located t p_hsType
66+p_typeAscription (XHsWildCardBndrs x) = noExtCon x
67+
68+p_patSynSig ::
69+ [Located RdrName] ->
70+ HsImplicitBndrs GhcPs (LHsType GhcPs) ->
71+ R ()
72+p_patSynSig names hsib = do
73+ txt "pattern"
74+ let body =
75+ p_typeSig
76+ False
77+ names
78+ HsWC {hswc_ext = NoExtField, hswc_body = hsib}
79+ if length names > 1
80+ then breakpoint >> inci body
81+ else space >> body
82+
83+p_classOpSig ::
84+ -- | Whether this is a \"default\" signature
85+ Bool ->
86+ -- | Names (before @::@)
87+ [Located RdrName] ->
88+ -- | Type
89+ HsImplicitBndrs GhcPs (LHsType GhcPs) ->
90+ R ()
91+p_classOpSig def names hsib = do
92+ when def (txt "default" >> space)
93+ p_typeSig True names HsWC {hswc_ext = NoExtField, hswc_body = hsib}
94+
95+p_fixSig ::
96+ FixitySig GhcPs ->
97+ R ()
98+p_fixSig = \case
99+ FixitySig NoExtField names (Fixity _ n dir) -> do
100+ txt $ case dir of
101+ InfixL -> "infixl"
102+ InfixR -> "infixr"
103+ InfixN -> "infix"
104+ space
105+ atom n
106+ space
107+ sitcc $ sep commaDel p_rdrName names
108+ XFixitySig x -> noExtCon x
109+
110+p_inlineSig ::
111+ -- | Name
112+ Located RdrName ->
113+ -- | Inline pragma specification
114+ InlinePragma ->
115+ R ()
116+p_inlineSig name InlinePragma {..} = pragmaBraces $ do
117+ p_inlineSpec inl_inline
118+ space
119+ case inl_rule of
120+ ConLike -> txt "CONLIKE"
121+ FunLike -> return ()
122+ space
123+ p_activation inl_act
124+ space
125+ p_rdrName name
126+
127+p_specSig ::
128+ -- | Name
129+ Located RdrName ->
130+ -- | The types to specialize to
131+ [LHsSigType GhcPs] ->
132+ -- | For specialize inline
133+ InlinePragma ->
134+ R ()
135+p_specSig name ts InlinePragma {..} = pragmaBraces $ do
136+ txt "SPECIALIZE"
137+ space
138+ p_inlineSpec inl_inline
139+ space
140+ p_activation inl_act
141+ space
142+ p_rdrName name
143+ space
144+ txt "::"
145+ breakpoint
146+ inci $ sep commaDel (located' p_hsType . hsib_body) ts
147+
148+p_inlineSpec :: InlineSpec -> R ()
149+p_inlineSpec = \case
150+ Inline -> txt "INLINE"
151+ Inlinable -> txt "INLINEABLE"
152+ NoInline -> txt "NOINLINE"
153+ NoUserInline -> return ()
154+
155+p_activation :: Activation -> R ()
156+p_activation = \case
157+ NeverActive -> return ()
158+ AlwaysActive -> return ()
159+ ActiveBefore _ n -> do
160+ txt "[~"
161+ atom n
162+ txt "]"
163+ ActiveAfter _ n -> do
164+ txt "["
165+ atom n
166+ txt "]"
167+
168+p_specInstSig :: LHsSigType GhcPs -> R ()
169+p_specInstSig hsib =
170+ pragma "SPECIALIZE instance" . inci $
171+ located (hsib_body hsib) p_hsType
172+
173+p_minimalSig ::
174+ -- | Boolean formula
175+ LBooleanFormula (Located RdrName) ->
176+ R ()
177+p_minimalSig =
178+ located' $ \booleanFormula ->
179+ pragma "MINIMAL" (inci $ p_booleanFormula booleanFormula)
180+
181+p_booleanFormula ::
182+ -- | Boolean formula
183+ BooleanFormula (Located RdrName) ->
184+ R ()
185+p_booleanFormula = \case
186+ Var name -> p_rdrName name
187+ And xs ->
188+ sitcc $
189+ sep
190+ commaDel
191+ (located' p_booleanFormula)
192+ xs
193+ Or xs ->
194+ sitcc $
195+ sep
196+ (breakpoint >> txt "|" >> space)
197+ (located' p_booleanFormula)
198+ xs
199+ Parens l -> located l (parens N . p_booleanFormula)
200+
201+p_completeSig ::
202+ -- | Constructors\/patterns
203+ Located [Located RdrName] ->
204+ -- | Type
205+ Maybe (Located RdrName) ->
206+ R ()
207+p_completeSig cs' mty =
208+ located cs' $ \cs ->
209+ pragma "COMPLETE" . inci $ do
210+ sep commaDel p_rdrName cs
211+ forM_ mty $ \ty -> do
212+ space
213+ txt "::"
214+ breakpoint
215+ inci (p_rdrName ty)
216+
217+p_sccSig :: Located (IdP GhcPs) -> Maybe (Located StringLiteral) -> R ()
218+p_sccSig loc literal = pragma "SCC" . inci $ do
219+ p_rdrName loc
220+ forM_ literal $ \x -> do
221+ breakpoint
222+ atom x
223+
224+p_standaloneKindSig :: StandaloneKindSig GhcPs -> R ()
225+p_standaloneKindSig (StandaloneKindSig NoExtField name bndrs) = do
226+ txt "type"
227+ inci $ do
228+ space
229+ p_rdrName name
230+ space
231+ txt "::"
232+ breakpoint
233+ case bndrs of
234+ HsIB NoExtField sig -> located sig p_hsType
235+ XHsImplicitBndrs x -> noExtCon x
236+p_standaloneKindSig (XStandaloneKindSig c) = noExtCon c
src/Ormolu/Printer/Meat/Declaration/Splice.hsnew file+15
@@ -0,0 +1,15 @@
1+{-# LANGUAGE LambdaCase #-}
2+
3+module Ormolu.Printer.Meat.Declaration.Splice
4+ ( p_spliceDecl,
5+ )
6+where
7+
8+import GHC
9+import Ormolu.Printer.Combinators
10+import Ormolu.Printer.Meat.Declaration.Value (p_hsSplice)
11+
12+p_spliceDecl :: SpliceDecl GhcPs -> R ()
13+p_spliceDecl = \case
14+ SpliceDecl NoExtField splice _explicit -> located splice p_hsSplice
15+ XSpliceDecl x -> noExtCon x
src/Ormolu/Printer/Meat/Declaration/Type.hs+29−21
@@ -1,32 +1,40 @@
1{-# LANGUAGE OverloadedStrings #-}
1{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE RecordWildCards #-}
2+{-# LANGUAGE RecordWildCards #-}
3
3
4-- | Rendering of type synonym declarations.
4-- | Rendering of type synonym declarations.
5−
6module Ormolu.Printer.Meat.Declaration.Type
5module Ormolu.Printer.Meat.Declaration.Type
7− ( p_synDecl
6+ ( p_synDecl,
8 )
7 )
9where
8where
10
9
11−import Control.Monad
10+import GHC
12−import HsTypes
13−import Language.Haskell.GHC.ExactPrint.Types
14import Ormolu.Printer.Combinators
11import Ormolu.Printer.Combinators
15import Ormolu.Printer.Meat.Common
12import Ormolu.Printer.Meat.Common
16import Ormolu.Printer.Meat.Type
13import Ormolu.Printer.Meat.Type
17−import RdrName (RdrName (..))
18−import SrcLoc (Located)
19
14
20−p_synDecl
15+p_synDecl ::
16+ -- | Type constructor
21− :: Located RdrName -- ^ Type constructor
17+ Located RdrName ->
18+ -- | Fixity
19+ LexicalFixity ->
22− -> LHsQTyVars GhcPs -- ^ Type variables
20+ -- | Type variables
21+ LHsQTyVars GhcPs ->
23− -> LHsType GhcPs -- ^ RHS of type declaration
22+ -- | RHS of type declaration
23+ LHsType GhcPs ->
24− -> R ()
24+ R ()
25−p_synDecl name tvars t = line $ do
25+p_synDecl name fixity HsQTvs {..} t = do
26− txt "type "
26+ txt "type"
27− located name p_rdrName'
27+ space
28− let HsQTvs {..} = tvars
28+ switchLayout (getLoc name : map getLoc hsq_explicit) $
29− unless (null hsq_explicit) space
29+ p_infixDefHelper
30+ (case fixity of Infix -> True; _ -> False)
31+ True
32+ (p_rdrName name)
30− spaceSep (located' p_hsTyVarBndr) hsq_explicit
33+ (map (located' p_hsTyVarBndr) hsq_explicit)
34+ space
35+ equals
36+ if hasDocStrings (unLoc t)
37+ then newline
31− breakpoint
38+ else breakpoint
32− inci (txt "= " >> relaxComments (located t p_hsType))
39+ inci (located t p_hsType)
40+p_synDecl _ _ (XLHsQTyVars x) _ = noExtCon x
src/Ormolu/Printer/Meat/Declaration/TypeFamily.hs+89−49
@@ -1,76 +1,116 @@
1−{-# LANGUAGE LambdaCase #-}
1+{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE RecordWildCards #-}
3+{-# LANGUAGE RecordWildCards #-}
4
4
5-- | Rendering of data\/type families.
5-- | Rendering of data\/type families.
6−
7module Ormolu.Printer.Meat.Declaration.TypeFamily
6module Ormolu.Printer.Meat.Declaration.TypeFamily
8− ( p_famDecl
7+ ( p_famDecl,
8+ p_tyFamInstEqn,
9 )
9 )
10where
10where
11
11
12import Control.Monad
12import Control.Monad
13−import Data.Maybe (maybeToList, isJust)
13+import Data.Maybe (isNothing)
14−import HsDecls
14+import GHC
15−import HsTypes
16−import Language.Haskell.GHC.ExactPrint.Types
17import Ormolu.Printer.Combinators
15import Ormolu.Printer.Combinators
18import Ormolu.Printer.Meat.Common
16import Ormolu.Printer.Meat.Common
19import Ormolu.Printer.Meat.Type
17import Ormolu.Printer.Meat.Type
20−import SrcLoc (Located, GenLocated (..))
18+import Ormolu.Utils
21
19
22−p_famDecl :: FamilyDecl GhcPs -> R ()
20+p_famDecl :: FamilyStyle -> FamilyDecl GhcPs -> R ()
23−p_famDecl FamilyDecl {..} = do
21+p_famDecl style FamilyDecl {fdTyVars = HsQTvs {..}, ..} = do
24 mmeqs <- case fdInfo of
22 mmeqs <- case fdInfo of
25− DataFamily -> Nothing <$ txt "data family "
23+ DataFamily -> Nothing <$ txt "data"
26− OpenTypeFamily -> Nothing <$ txt "type family "
24+ OpenTypeFamily -> Nothing <$ txt "type"
27− ClosedTypeFamily eqs -> Just eqs <$ txt "type family "
25+ ClosedTypeFamily eqs -> Just eqs <$ txt "type"
26+ txt $ case style of
27+ Associated -> mempty
28+ Free -> " family"
29+ breakpoint
30+ inci $ do
31+ switchLayout (getLoc fdLName : (getLoc <$> hsq_explicit)) $
32+ p_infixDefHelper
33+ (isInfix fdFixity)
34+ True
28− located fdLName p_rdrName
35+ (p_rdrName fdLName)
29− space
36+ (located' p_hsTyVarBndr <$> hsq_explicit)
30− let HsQTvs {..} = fdTyVars
31− items =
32− maybeToList (p_familyResultSigL (isJust fdInjectivityAnn) fdResultSig)
37+ let resultSig = p_familyResultSigL fdResultSig
33− ++ (located' p_injectivityAnn <$> maybeToList fdInjectivityAnn)
38+ unless (isNothing resultSig && isNothing fdInjectivityAnn) space
34− spaceSep (located' p_hsTyVarBndr) hsq_explicit
39+ inci $ do
35− unless (null items) $
40+ sequence_ resultSig
36− breakpoint
41+ space
37− inci . inci $ spaceSep id items
42+ forM_ fdInjectivityAnn (located' p_injectivityAnn)
38 case mmeqs of
43 case mmeqs of
39− Nothing -> newline
44+ Nothing -> return ()
40 Just meqs -> do
45 Just meqs -> do
46+ inci $ do
47+ breakpoint
41− txt " where"
48+ txt "where"
42 case meqs of
49 case meqs of
43− Nothing -> txt " .." >> newline
50+ Nothing -> do
51+ space
52+ txt ".."
44 Just eqs -> do
53 Just eqs -> do
45 newline
54 newline
46− forM_ eqs (located' (line . inci . p_tyFamInstEqn))
55+ sep newline (located' (inci . p_tyFamInstEqn)) eqs
56+p_famDecl _ FamilyDecl {fdTyVars = XLHsQTyVars {}} =
57+ notImplemented "XLHsQTyVars"
58+p_famDecl _ (XFamilyDecl x) = noExtCon x
47
59
60+p_familyResultSigL ::
48−p_familyResultSigL :: Bool -> Located (FamilyResultSig GhcPs) -> Maybe (R ())
61+ Located (FamilyResultSig GhcPs) ->
62+ Maybe (R ())
49−p_familyResultSigL injAnn l =
63+p_familyResultSigL l =
50 case l of
64 case l of
51 L _ a -> case a of
65 L _ a -> case a of
52− NoSig -> Nothing
66+ NoSig NoExtField -> Nothing
53− KindSig k -> Just $ do
67+ KindSig NoExtField k -> Just $ do
54− if injAnn then txt "= " else txt ":: "
68+ txt "::"
69+ breakpoint
55− relaxComments (located k p_hsType)
70+ located k p_hsType
56− TyVarSig bndr -> Just $ do
71+ TyVarSig NoExtField bndr -> Just $ do
57− if injAnn then txt "= " else txt ":: "
72+ equals
73+ breakpoint
58− relaxComments (located bndr p_hsTyVarBndr)
74+ located bndr p_hsTyVarBndr
75+ XFamilyResultSig x ->
76+ noExtCon x
59
77
60p_injectivityAnn :: InjectivityAnn GhcPs -> R ()
78p_injectivityAnn :: InjectivityAnn GhcPs -> R ()
61p_injectivityAnn (InjectivityAnn a bs) = do
79p_injectivityAnn (InjectivityAnn a bs) = do
62− txt "| "
80+ txt "|"
81+ space
63− located a p_rdrName
82+ p_rdrName a
64 space
83 space
65− txt "-> "
84+ txt "->"
85+ space
66− spaceSep (located' p_rdrName) bs
86+ sep space p_rdrName bs
67
87
68p_tyFamInstEqn :: TyFamInstEqn GhcPs -> R ()
88p_tyFamInstEqn :: TyFamInstEqn GhcPs -> R ()
69−p_tyFamInstEqn HsIB {..} = velt'
89+p_tyFamInstEqn HsIB {hsib_body = FamEqn {..}} = do
70− [ do located feqn_tycon p_rdrName
90+ case feqn_bndrs of
91+ Nothing -> return ()
92+ Just bndrs -> do
93+ p_forallBndrs ForallInvis p_hsTyVarBndr bndrs
94+ breakpoint
95+ inciIf (not $ null feqn_bndrs) $ do
96+ let famLhsSpn = getLoc feqn_tycon : fmap (getLoc . typeArgToType) feqn_pats
97+ switchLayout famLhsSpn $
98+ p_infixDefHelper
99+ (isInfix feqn_fixity)
100+ True
101+ (p_rdrName feqn_tycon)
102+ (located' p_hsType . typeArgToType <$> feqn_pats)
71− space
103+ space
72− spaceSep (located' p_hsType) feqn_pats
104+ equals
105+ breakpoint
73− , inci $ txt "= " >> inci (located feqn_rhs p_hsType)
106+ inci (located feqn_rhs p_hsType)
74− ]
107+p_tyFamInstEqn HsIB {hsib_body = XFamEqn x} = noExtCon x
75− where
108+p_tyFamInstEqn (XHsImplicitBndrs x) = noExtCon x
76− FamEqn {..} = hsib_body
109+
110+----------------------------------------------------------------------------
111+-- Helpers
112+
113+isInfix :: LexicalFixity -> Bool
114+isInfix = \case
115+ Infix -> True
116+ Prefix -> False
src/Ormolu/Printer/Meat/Declaration/Value.hsnew file+1362
@@ -0,0 +1,1362 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE MultiWayIf #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE RecordWildCards #-}
5+{-# LANGUAGE TypeApplications #-}
6+
7+module Ormolu.Printer.Meat.Declaration.Value
8+ ( p_valDecl,
9+ p_pat,
10+ p_hsExpr,
11+ p_hsSplice,
12+ p_stringLit,
13+ )
14+where
15+
16+import Bag (bagToList)
17+import BasicTypes
18+import Control.Monad
19+import Ctype (is_space)
20+import Data.Bool (bool)
21+import Data.Char (isPunctuation, isSymbol)
22+import Data.Data hiding (Infix, Prefix)
23+import Data.Functor ((<&>))
24+import Data.List (intersperse, sortOn)
25+import Data.List.NonEmpty (NonEmpty (..), (<|))
26+import qualified Data.List.NonEmpty as NE
27+import Data.Text (Text)
28+import qualified Data.Text as Text
29+import GHC
30+import OccName (occNameString)
31+import Ormolu.Printer.Combinators
32+import Ormolu.Printer.Internal
33+import Ormolu.Printer.Meat.Common
34+import {-# SOURCE #-} Ormolu.Printer.Meat.Declaration
35+import Ormolu.Printer.Meat.Declaration.Signature
36+import Ormolu.Printer.Meat.Type
37+import Ormolu.Printer.Operators
38+import Ormolu.Utils
39+
40+-- | Style of a group of equations.
41+data MatchGroupStyle
42+ = Function (Located RdrName)
43+ | PatternBind
44+ | Case
45+ | Lambda
46+ | LambdaCase
47+
48+-- | Style of equations in a group.
49+data GroupStyle
50+ = EqualSign
51+ | RightArrow
52+
53+-- | Expression placement. This marks the places where expressions that
54+-- implement handing forms may use them.
55+data Placement
56+ = -- | Multi-line layout should cause
57+ -- insertion of a newline and indentation
58+ -- bump
59+ Normal
60+ | -- | Expressions that have hanging form
61+ -- should use it and avoid bumping one level
62+ -- of indentation
63+ Hanging
64+ deriving (Eq, Show)
65+
66+p_valDecl :: HsBindLR GhcPs GhcPs -> R ()
67+p_valDecl = \case
68+ FunBind NoExtField funId funMatches _ _ -> p_funBind funId funMatches
69+ PatBind NoExtField pat grhss _ -> p_match PatternBind False NoSrcStrict [pat] grhss
70+ VarBind {} -> notImplemented "VarBinds" -- introduced by the type checker
71+ AbsBinds {} -> notImplemented "AbsBinds" -- introduced by the type checker
72+ PatSynBind NoExtField psb -> p_patSynBind psb
73+ XHsBindsLR x -> noExtCon x
74+
75+p_funBind ::
76+ Located RdrName ->
77+ MatchGroup GhcPs (LHsExpr GhcPs) ->
78+ R ()
79+p_funBind name = p_matchGroup (Function name)
80+
81+p_matchGroup ::
82+ MatchGroupStyle ->
83+ MatchGroup GhcPs (LHsExpr GhcPs) ->
84+ R ()
85+p_matchGroup = p_matchGroup' exprPlacement p_hsExpr
86+
87+p_matchGroup' ::
88+ Data body =>
89+ -- | How to get body placement
90+ (body -> Placement) ->
91+ -- | How to print body
92+ (body -> R ()) ->
93+ -- | Style of this group of equations
94+ MatchGroupStyle ->
95+ -- | Match group
96+ MatchGroup GhcPs (Located body) ->
97+ R ()
98+p_matchGroup' placer render style MG {..} = do
99+ let ob = case style of
100+ Case -> id
101+ LambdaCase -> id
102+ _ -> dontUseBraces
103+ -- Since we are forcing braces on 'sepSemi' based on 'ob', we have to
104+ -- restore the brace state inside the sepsemi.
105+ ub <- bool dontUseBraces useBraces <$> canUseBraces
106+ ob $ sepSemi (located' (ub . p_Match)) (unLoc mg_alts)
107+ where
108+ p_Match m@Match {..} =
109+ p_match'
110+ placer
111+ render
112+ (adjustMatchGroupStyle m style)
113+ (isInfixMatch m)
114+ (matchStrictness m)
115+ m_pats
116+ m_grhss
117+ p_Match (XMatch x) = noExtCon x
118+p_matchGroup' _ _ _ (XMatchGroup x) = noExtCon x
119+
120+-- | Function id obtained through pattern matching on 'FunBind' should not
121+-- be used to print the actual equations because the different ‘RdrNames’
122+-- used in the equations may have different “decorations” (such as backticks
123+-- and paretheses) associated with them. It is necessary to use per-equation
124+-- names obtained from 'm_ctxt' of 'Match'. This function replaces function
125+-- name inside of 'Function' accordingly.
126+adjustMatchGroupStyle ::
127+ Match GhcPs body ->
128+ MatchGroupStyle ->
129+ MatchGroupStyle
130+adjustMatchGroupStyle m = \case
131+ Function _ -> (Function . mc_fun . m_ctxt) m
132+ style -> style
133+
134+matchStrictness :: Match id body -> SrcStrictness
135+matchStrictness match =
136+ case m_ctxt match of
137+ FunRhs {mc_strictness = s} -> s
138+ _ -> NoSrcStrict
139+
140+p_match ::
141+ -- | Style of the group
142+ MatchGroupStyle ->
143+ -- | Is this an infix match?
144+ Bool ->
145+ -- | Strictness prefix (FunBind)
146+ SrcStrictness ->
147+ -- | Argument patterns
148+ [LPat GhcPs] ->
149+ -- | Equations
150+ GRHSs GhcPs (LHsExpr GhcPs) ->
151+ R ()
152+p_match = p_match' exprPlacement p_hsExpr
153+
154+p_match' ::
155+ Data body =>
156+ -- | How to get body placement
157+ (body -> Placement) ->
158+ -- | How to print body
159+ (body -> R ()) ->
160+ -- | Style of this group of equations
161+ MatchGroupStyle ->
162+ -- | Is this an infix match?
163+ Bool ->
164+ -- | Strictness prefix (FunBind)
165+ SrcStrictness ->
166+ -- | Argument patterns
167+ [LPat GhcPs] ->
168+ -- | Equations
169+ GRHSs GhcPs (Located body) ->
170+ R ()
171+p_match' placer render style isInfix strictness m_pats GRHSs {..} = do
172+ -- Normally, since patterns may be placed in a multi-line layout, it is
173+ -- necessary to bump indentation for the pattern group so it's more
174+ -- indented than function name. This in turn means that indentation for
175+ -- the body should also be bumped. Normally this would mean that bodies
176+ -- would start with two indentation steps applied, which is ugly, so we
177+ -- need to be a bit more clever here and bump indentation level only when
178+ -- pattern group is multiline.
179+ case strictness of
180+ NoSrcStrict -> return ()
181+ SrcStrict -> txt "!"
182+ SrcLazy -> txt "~"
183+ indentBody <- case NE.nonEmpty m_pats of
184+ Nothing ->
185+ False <$ case style of
186+ Function name -> p_rdrName name
187+ _ -> return ()
188+ Just ne_pats -> do
189+ let combinedSpans = case style of
190+ Function name -> combineSrcSpans (getLoc name) patSpans
191+ _ -> patSpans
192+ patSpans = combineSrcSpans' (getLoc <$> ne_pats)
193+ indentBody = not (isOneLineSpan combinedSpans)
194+ switchLayout [combinedSpans] $ do
195+ let stdCase = sep breakpoint (located' p_pat) m_pats
196+ case style of
197+ Function name ->
198+ p_infixDefHelper
199+ isInfix
200+ indentBody
201+ (p_rdrName name)
202+ (located' p_pat <$> m_pats)
203+ PatternBind -> stdCase
204+ Case -> stdCase
205+ Lambda -> do
206+ let needsSpace = case unLoc (NE.head ne_pats) of
207+ LazyPat _ _ -> True
208+ BangPat _ _ -> True
209+ SplicePat _ _ -> True
210+ _ -> False
211+ txt "\\"
212+ when needsSpace space
213+ sitcc stdCase
214+ LambdaCase -> stdCase
215+ return indentBody
216+ let -- Calculate position of end of patterns. This is useful when we decide
217+ -- about putting certain constructions in hanging positions.
218+ endOfPats = case NE.nonEmpty m_pats of
219+ Nothing -> case style of
220+ Function name -> Just (getLoc name)
221+ _ -> Nothing
222+ Just pats -> (Just . getLoc . NE.last) pats
223+ isCase = \case
224+ Case -> True
225+ LambdaCase -> True
226+ _ -> False
227+ hasGuards = withGuards grhssGRHSs
228+ grhssSpan =
229+ combineSrcSpans' $
230+ getGRHSSpan . unLoc <$> NE.fromList grhssGRHSs
231+ patGrhssSpan =
232+ maybe
233+ grhssSpan
234+ (combineSrcSpans grhssSpan . srcLocSpan . srcSpanEnd)
235+ endOfPats
236+ placement =
237+ case endOfPats of
238+ Nothing -> blockPlacement placer grhssGRHSs
239+ Just spn ->
240+ if onTheSameLine spn grhssSpan
241+ then blockPlacement placer grhssGRHSs
242+ else Normal
243+ p_body = do
244+ let groupStyle =
245+ if isCase style && hasGuards
246+ then RightArrow
247+ else EqualSign
248+ sep newline (located' (p_grhs' placer render groupStyle)) grhssGRHSs
249+ p_where = do
250+ let whereIsEmpty = GHC.isEmptyLocalBindsPR (unLoc grhssLocalBinds)
251+ unless (GHC.eqEmptyLocalBinds (unLoc grhssLocalBinds)) $ do
252+ breakpoint
253+ txt "where"
254+ unless whereIsEmpty breakpoint
255+ inci $ located grhssLocalBinds p_hsLocalBinds
256+ inciIf indentBody $ do
257+ unless (length grhssGRHSs > 1) $
258+ case style of
259+ Function _ | hasGuards -> return ()
260+ Function _ -> space >> inci equals
261+ PatternBind -> space >> inci equals
262+ s | isCase s && hasGuards -> return ()
263+ _ -> space >> txt "->"
264+ switchLayout [patGrhssSpan] $
265+ placeHanging placement p_body
266+ inci p_where
267+p_match' _ _ _ _ _ _ (XGRHSs x) = noExtCon x
268+
269+p_grhs :: GroupStyle -> GRHS GhcPs (LHsExpr GhcPs) -> R ()
270+p_grhs = p_grhs' exprPlacement p_hsExpr
271+
272+p_grhs' ::
273+ Data body =>
274+ -- | How to get body placement
275+ (body -> Placement) ->
276+ -- | How to print body
277+ (body -> R ()) ->
278+ GroupStyle ->
279+ GRHS GhcPs (Located body) ->
280+ R ()
281+p_grhs' placer render style (GRHS NoExtField guards body) =
282+ case guards of
283+ [] -> p_body
284+ xs -> do
285+ txt "|"
286+ space
287+ sitcc (sep commaDel (sitcc . located' p_stmt) xs)
288+ space
289+ inci $ case style of
290+ EqualSign -> equals
291+ RightArrow -> txt "->"
292+ placeHanging placement p_body
293+ where
294+ placement =
295+ case endOfGuards of
296+ Nothing -> placer (unLoc body)
297+ Just spn ->
298+ if onTheSameLine spn (getLoc body)
299+ then placer (unLoc body)
300+ else Normal
301+ endOfGuards =
302+ case NE.nonEmpty guards of
303+ Nothing -> Nothing
304+ Just gs -> (Just . getLoc . NE.last) gs
305+ p_body = located body render
306+p_grhs' _ _ _ (XGRHS x) = noExtCon x
307+
308+p_hsCmd :: HsCmd GhcPs -> R ()
309+p_hsCmd = \case
310+ HsCmdArrApp NoExtField body input arrType _ -> do
311+ located body p_hsExpr
312+ breakpoint
313+ inci $ do
314+ case arrType of
315+ HsFirstOrderApp -> txt "-<"
316+ HsHigherOrderApp -> txt "-<<"
317+ placeHanging (exprPlacement (unLoc input)) $
318+ located input p_hsExpr
319+ HsCmdArrForm NoExtField form Prefix _ cmds -> banana $ do
320+ located form p_hsExpr
321+ unless (null cmds) $ do
322+ breakpoint
323+ inci (sequence_ (intersperse breakpoint (located' p_hsCmdTop <$> cmds)))
324+ HsCmdArrForm NoExtField form Infix _ [left, right] -> do
325+ located left p_hsCmdTop
326+ space
327+ located form p_hsExpr
328+ placeHanging (cmdTopPlacement (unLoc right)) $
329+ located right p_hsCmdTop
330+ HsCmdArrForm NoExtField _ Infix _ _ -> notImplemented "HsCmdArrForm"
331+ HsCmdApp {} ->
332+ -- XXX Does this ever occur in the syntax tree? It does not seem like it
333+ -- does. Open an issue and ping @yumiova if this ever occurs in output.
334+ notImplemented "HsCmdApp"
335+ HsCmdLam NoExtField mgroup -> p_matchGroup' cmdPlacement p_hsCmd Lambda mgroup
336+ HsCmdPar NoExtField c -> parens N (located c p_hsCmd)
337+ HsCmdCase NoExtField e mgroup ->
338+ p_case cmdPlacement p_hsCmd e mgroup
339+ HsCmdIf NoExtField _ if' then' else' ->
340+ p_if cmdPlacement p_hsCmd if' then' else'
341+ HsCmdLet NoExtField localBinds c ->
342+ p_let p_hsCmd localBinds c
343+ HsCmdDo NoExtField es -> do
344+ txt "do"
345+ newline
346+ inci . located es $
347+ sitcc . sep newline (sitcc . withSpacing (p_stmt' cmdPlacement p_hsCmd))
348+ HsCmdWrap {} -> notImplemented "HsCmdWrap"
349+ XCmd x -> noExtCon x
350+
351+p_hsCmdTop :: HsCmdTop GhcPs -> R ()
352+p_hsCmdTop = \case
353+ HsCmdTop NoExtField cmd -> located cmd p_hsCmd
354+ XCmdTop x -> noExtCon x
355+
356+-- | Render an expression preserving blank lines between such consecutive
357+-- expressions found in the original source code.
358+withSpacing ::
359+ -- | Rendering function
360+ (a -> R ()) ->
361+ -- | Entity to render
362+ Located a ->
363+ R ()
364+withSpacing f l = located l $ \x -> do
365+ case getLoc l of
366+ UnhelpfulSpan _ -> f x
367+ RealSrcSpan currentSpn -> do
368+ getSpanMark >>= \case
369+ -- Spacing before comments will be handled by the code
370+ -- that prints comments, so we just have to deal with
371+ -- blank lines between statements here.
372+ Just (StatementSpan lastSpn) ->
373+ if srcSpanStartLine currentSpn > srcSpanEndLine lastSpn + 1
374+ then newline
375+ else return ()
376+ _ -> return ()
377+ f x
378+ -- In some cases the (f x) expression may insert a new mark. We want
379+ -- to be careful not to override comment marks.
380+ getSpanMark >>= \case
381+ Just (HaddockSpan _ _) -> return ()
382+ Just (CommentSpan _) -> return ()
383+ _ -> setSpanMark (StatementSpan currentSpn)
384+
385+p_stmt :: Stmt GhcPs (LHsExpr GhcPs) -> R ()
386+p_stmt = p_stmt' exprPlacement p_hsExpr
387+
388+p_stmt' ::
389+ Data body =>
390+ -- | Placer
391+ (body -> Placement) ->
392+ -- | Render
393+ (body -> R ()) ->
394+ -- | Statement to render
395+ Stmt GhcPs (Located body) ->
396+ R ()
397+p_stmt' placer render = \case
398+ LastStmt NoExtField body _ _ -> located body render
399+ BindStmt NoExtField p f _ _ -> do
400+ located p p_pat
401+ space
402+ txt "<-"
403+ let loc = getLoc p
404+ placement =
405+ case f of
406+ L l' x ->
407+ if isOneLineSpan
408+ (mkSrcSpan (srcSpanEnd loc) (srcSpanStart l'))
409+ then placer x
410+ else Normal
411+ switchLayout [loc, getLoc f] $
412+ placeHanging placement (located f render)
413+ ApplicativeStmt {} -> notImplemented "ApplicativeStmt" -- generated by renamer
414+ BodyStmt NoExtField body _ _ -> located body render
415+ LetStmt NoExtField binds -> do
416+ txt "let"
417+ space
418+ sitcc $ located binds p_hsLocalBinds
419+ ParStmt {} ->
420+ -- 'ParStmt' should always be eliminated in 'gatherStmt' already, such
421+ -- that it never occurs in 'p_stmt''. Consequently, handling it here
422+ -- would be redundant.
423+ notImplemented "ParStmt"
424+ TransStmt {..} ->
425+ -- 'TransStmt' only needs to account for render printing itself, since
426+ -- pretty printing of relevant statements (e.g., in 'trS_stmts') is
427+ -- handled through 'gatherStmt'.
428+ case (trS_form, trS_by) of
429+ (ThenForm, Nothing) -> do
430+ txt "then"
431+ breakpoint
432+ inci $ located trS_using p_hsExpr
433+ (ThenForm, Just e) -> do
434+ txt "then"
435+ breakpoint
436+ inci $ located trS_using p_hsExpr
437+ breakpoint
438+ txt "by"
439+ breakpoint
440+ inci $ located e p_hsExpr
441+ (GroupForm, Nothing) -> do
442+ txt "then group using"
443+ breakpoint
444+ inci $ located trS_using p_hsExpr
445+ (GroupForm, Just e) -> do
446+ txt "then group by"
447+ breakpoint
448+ inci $ located e p_hsExpr
449+ breakpoint
450+ txt "using"
451+ breakpoint
452+ inci $ located trS_using p_hsExpr
453+ RecStmt {..} -> do
454+ txt "rec"
455+ space
456+ sitcc $ sepSemi (withSpacing (p_stmt' placer render)) recS_stmts
457+ XStmtLR c -> noExtCon c
458+
459+gatherStmt :: ExprLStmt GhcPs -> [[ExprLStmt GhcPs]]
460+gatherStmt (L _ (ParStmt NoExtField block _ _)) =
461+ foldr ((<>) . gatherStmtBlock) [] block
462+gatherStmt (L s stmt@TransStmt {..}) =
463+ foldr liftAppend [] ((gatherStmt <$> trS_stmts) <> pure [[L s stmt]])
464+gatherStmt stmt = [[stmt]]
465+
466+gatherStmtBlock :: ParStmtBlock GhcPs GhcPs -> [[ExprLStmt GhcPs]]
467+gatherStmtBlock (ParStmtBlock _ stmts _ _) =
468+ foldr (liftAppend . gatherStmt) [] stmts
469+gatherStmtBlock (XParStmtBlock x) = noExtCon x
470+
471+p_hsLocalBinds :: HsLocalBindsLR GhcPs GhcPs -> R ()
472+p_hsLocalBinds = \case
473+ HsValBinds NoExtField (ValBinds NoExtField bag lsigs) -> do
474+ -- When in a single-line layout, there is a chance that the inner
475+ -- elements will also contain semicolons and they will confuse the
476+ -- parser. so we request braces around every element except the last.
477+ br <- layoutToBraces <$> getLayout
478+ let items =
479+ let injectLeft (L l x) = L l (Left x)
480+ injectRight (L l x) = L l (Right x)
481+ in (injectLeft <$> bagToList bag) ++ (injectRight <$> lsigs)
482+ positionToBracing = \case
483+ SinglePos -> id
484+ FirstPos -> br
485+ MiddlePos -> br
486+ LastPos -> id
487+ p_item' (p, item) =
488+ positionToBracing p $
489+ withSpacing (either p_valDecl p_sigDecl) item
490+ binds = sortOn (srcSpanStart . getLoc) items
491+ sitcc $ sepSemi p_item' (attachRelativePos binds)
492+ HsValBinds NoExtField _ -> notImplemented "HsValBinds"
493+ HsIPBinds NoExtField (IPBinds NoExtField xs) ->
494+ -- Second argument of IPBind is always Left before type-checking.
495+ let p_ipBind (IPBind NoExtField (Left name) expr) = do
496+ atom name
497+ space
498+ equals
499+ breakpoint
500+ useBraces $ inci $ located expr p_hsExpr
501+ p_ipBind (IPBind NoExtField (Right _) _) =
502+ -- Should only occur after the type checker
503+ notImplemented "IPBind _ (Right _) _"
504+ p_ipBind (XIPBind x) = noExtCon x
505+ in sepSemi (located' p_ipBind) xs
506+ HsIPBinds NoExtField _ -> notImplemented "HsIpBinds"
507+ EmptyLocalBinds NoExtField -> return ()
508+ XHsLocalBindsLR x -> noExtCon x
509+
510+p_hsRecField ::
511+ HsRecField' RdrName (LHsExpr GhcPs) ->
512+ R ()
513+p_hsRecField HsRecField {..} = do
514+ p_rdrName hsRecFieldLbl
515+ unless hsRecPun $ do
516+ space
517+ equals
518+ let placement =
519+ if onTheSameLine (getLoc hsRecFieldLbl) (getLoc hsRecFieldArg)
520+ then exprPlacement (unLoc hsRecFieldArg)
521+ else Normal
522+ placeHanging placement (located hsRecFieldArg p_hsExpr)
523+
524+p_hsExpr :: HsExpr GhcPs -> R ()
525+p_hsExpr = p_hsExpr' N
526+
527+p_hsExpr' :: BracketStyle -> HsExpr GhcPs -> R ()
528+p_hsExpr' s = \case
529+ HsVar NoExtField name -> p_rdrName name
530+ HsUnboundVar NoExtField v -> atom (unboundVarOcc v)
531+ HsConLikeOut NoExtField _ -> notImplemented "HsConLikeOut"
532+ HsRecFld NoExtField x ->
533+ case x of
534+ Unambiguous NoExtField name -> p_rdrName name
535+ Ambiguous NoExtField name -> p_rdrName name
536+ XAmbiguousFieldOcc xx -> noExtCon xx
537+ HsOverLabel NoExtField _ v -> do
538+ txt "#"
539+ atom v
540+ HsIPVar NoExtField (HsIPName name) -> do
541+ txt "?"
542+ atom name
543+ HsOverLit NoExtField v -> atom (ol_val v)
544+ HsLit NoExtField lit ->
545+ case lit of
546+ HsString (SourceText stxt) _ -> p_stringLit stxt
547+ HsStringPrim (SourceText stxt) _ -> p_stringLit stxt
548+ r -> atom r
549+ HsLam NoExtField mgroup ->
550+ p_matchGroup Lambda mgroup
551+ HsLamCase NoExtField mgroup -> do
552+ txt "\\case"
553+ breakpoint
554+ inci (p_matchGroup LambdaCase mgroup)
555+ HsApp NoExtField f x -> do
556+ let -- In order to format function applications with multiple parameters
557+ -- nicer, traverse the AST to gather the function and all the
558+ -- parameters together.
559+ gatherArgs f' knownArgs =
560+ case f' of
561+ L _ (HsApp _ l r) -> gatherArgs l (r <| knownArgs)
562+ _ -> (f', knownArgs)
563+ (func, args) = gatherArgs f (x :| [])
564+ -- We need to handle the last argument specially if it is a
565+ -- hanging construct, so separate it from the rest.
566+ (initp, lastp) = (NE.init args, NE.last args)
567+ initSpan =
568+ combineSrcSpans' $
569+ getLoc f :| [(srcLocSpan . srcSpanStart . getLoc) lastp]
570+ -- Hang the last argument only if the initial arguments span one
571+ -- line.
572+ placement =
573+ if isOneLineSpan initSpan
574+ then exprPlacement (unLoc lastp)
575+ else Normal
576+ -- If the last argument is not hanging, just separate every argument as
577+ -- usual. If it is hanging, print the initial arguments and hang the
578+ -- last one. Also, use braces around the every argument except the last
579+ -- one.
580+ case placement of
581+ Normal -> do
582+ let -- Usually we want to bump indentation for arguments for the
583+ -- sake of readability. However, when the function itself is a
584+ -- do-block or case expression it is not a good idea. It seems
585+ -- to be safe to always bump indentation when the function
586+ -- expression is parenthesised.
587+ doIndent =
588+ case func of
589+ L _ (HsPar NoExtField _) -> True
590+ L _ (HsAppType NoExtField _ _) -> True
591+ L _ (HsMultiIf NoExtField _) -> True
592+ L spn _ -> isOneLineSpan spn
593+ ub <-
594+ getLayout <&> \case
595+ SingleLine -> useBraces
596+ MultiLine -> id
597+ ub $ do
598+ located func (p_hsExpr' s)
599+ breakpoint
600+ inciIf doIndent $ sep breakpoint (located' p_hsExpr) initp
601+ inciIf doIndent $ do
602+ unless (null initp) breakpoint
603+ located lastp p_hsExpr
604+ Hanging -> do
605+ useBraces . switchLayout [initSpan] $ do
606+ located func (p_hsExpr' s)
607+ breakpoint
608+ sep breakpoint (located' p_hsExpr) initp
609+ placeHanging placement $
610+ located lastp p_hsExpr
611+ HsAppType NoExtField e a -> do
612+ located e p_hsExpr
613+ breakpoint
614+ inci $ do
615+ txt "@"
616+ -- Insert a space when the type is represented as a TH splice to avoid
617+ -- gluing @ and $ together.
618+ case unLoc (hswc_body a) of
619+ HsSpliceTy {} -> space
620+ _ -> return ()
621+ located (hswc_body a) p_hsType
622+ OpApp NoExtField x op y -> do
623+ let opTree = OpBranch (exprOpTree x) op (exprOpTree y)
624+ p_exprOpTree s (reassociateOpTree getOpName opTree)
625+ NegApp NoExtField e _ -> do
626+ txt "-"
627+ space
628+ located e p_hsExpr
629+ HsPar NoExtField e ->
630+ parens s (located e (dontUseBraces . p_hsExpr))
631+ SectionL NoExtField x op -> do
632+ located x p_hsExpr
633+ breakpoint
634+ inci (located op p_hsExpr)
635+ SectionR NoExtField op x -> do
636+ located op p_hsExpr
637+ useRecordDot' <- useRecordDot
638+ let isRecordDot' = isRecordDot (unLoc op) (getLoc x)
639+ unless (useRecordDot' && isRecordDot') breakpoint
640+ inci (located x p_hsExpr)
641+ ExplicitTuple NoExtField args boxity ->
642+ let isSection = any (isMissing . unLoc) args
643+ isMissing = \case
644+ Missing NoExtField -> True
645+ _ -> False
646+ p_arg = \case
647+ Present NoExtField x -> located x p_hsExpr
648+ Missing NoExtField -> pure ()
649+ XTupArg x -> noExtCon x
650+ p_larg = sitcc . located' p_arg
651+ parens' =
652+ case boxity of
653+ Boxed -> parens
654+ Unboxed -> parensHash
655+ in if isSection
656+ then
657+ switchLayout [] . parens' s $
658+ sep comma p_larg args
659+ else
660+ switchLayout (getLoc <$> args) . parens' s $
661+ sep commaDel p_larg args
662+ ExplicitSum NoExtField tag arity e ->
663+ p_unboxedSum N tag arity (located e p_hsExpr)
664+ HsCase NoExtField e mgroup ->
665+ p_case exprPlacement p_hsExpr e mgroup
666+ HsIf NoExtField _ if' then' else' ->
667+ p_if exprPlacement p_hsExpr if' then' else'
668+ HsMultiIf NoExtField guards -> do
669+ txt "if"
670+ breakpoint
671+ inci . inci $ sep newline (located' (p_grhs RightArrow)) guards
672+ HsLet NoExtField localBinds e ->
673+ p_let p_hsExpr localBinds e
674+ HsDo NoExtField ctx es -> do
675+ let doBody header = do
676+ txt header
677+ breakpoint
678+ ub <- layoutToBraces <$> getLayout
679+ inci $
680+ sepSemi
681+ (ub . withSpacing (p_stmt' exprPlacement (p_hsExpr' S)))
682+ (unLoc es)
683+ compBody = brackets N . located es $ \xs -> do
684+ let p_parBody =
685+ sep
686+ (breakpoint >> txt "|" >> space)
687+ p_seqBody
688+ p_seqBody =
689+ sitcc
690+ . sep
691+ commaDel
692+ (located' (sitcc . p_stmt))
693+ stmts = init xs
694+ yield = last xs
695+ lists = foldr (liftAppend . gatherStmt) [] stmts
696+ located yield p_stmt
697+ breakpoint
698+ txt "|"
699+ space
700+ p_parBody lists
701+ case ctx of
702+ DoExpr -> doBody "do"
703+ MDoExpr -> doBody "mdo"
704+ ListComp -> compBody
705+ MonadComp -> notImplemented "MonadComp"
706+ ArrowExpr -> notImplemented "ArrowExpr"
707+ GhciStmtCtxt -> notImplemented "GhciStmtCtxt"
708+ PatGuard _ -> notImplemented "PatGuard"
709+ ParStmtCtxt _ -> notImplemented "ParStmtCtxt"
710+ TransStmtCtxt _ -> notImplemented "TransStmtCtxt"
711+ ExplicitList _ _ xs ->
712+ brackets s $
713+ sep commaDel (sitcc . located' p_hsExpr) xs
714+ RecordCon {..} -> do
715+ located rcon_con_name atom
716+ breakpoint
717+ let HsRecFields {..} = rcon_flds
718+ updName f =
719+ (f :: HsRecField GhcPs (LHsExpr GhcPs))
720+ { hsRecFieldLbl = case unLoc $ hsRecFieldLbl f of
721+ FieldOcc _ n -> n
722+ XFieldOcc x -> noExtCon x
723+ }
724+ fields = located' (p_hsRecField . updName) <$> rec_flds
725+ dotdot =
726+ case rec_dotdot of
727+ Just {} -> [txt ".."]
728+ Nothing -> []
729+ inci . braces N $
730+ sep commaDel sitcc (fields <> dotdot)
731+ RecordUpd {..} -> do
732+ located rupd_expr p_hsExpr
733+ useRecordDot' <- useRecordDot
734+ let mrs sp = case getLoc sp of
735+ RealSrcSpan r -> Just r
736+ _ -> Nothing
737+ let isPluginForm =
738+ ((1 +) . srcSpanEndCol <$> mrs rupd_expr)
739+ == (srcSpanStartCol <$> mrs (head rupd_flds))
740+ unless (useRecordDot' && isPluginForm) breakpoint
741+ let updName f =
742+ (f :: HsRecUpdField GhcPs)
743+ { hsRecFieldLbl = case unLoc $ hsRecFieldLbl f of
744+ Ambiguous _ n -> n
745+ Unambiguous _ n -> n
746+ XAmbiguousFieldOcc x -> noExtCon x
747+ }
748+ inci . braces N $
749+ sep
750+ commaDel
751+ (sitcc . located' (p_hsRecField . updName))
752+ rupd_flds
753+ ExprWithTySig NoExtField x HsWC {hswc_body = HsIB {..}} -> sitcc $ do
754+ located x p_hsExpr
755+ space
756+ txt "::"
757+ breakpoint
758+ inci $ located hsib_body p_hsType
759+ ExprWithTySig NoExtField _ HsWC {hswc_body = XHsImplicitBndrs x} -> noExtCon x
760+ ExprWithTySig NoExtField _ (XHsWildCardBndrs x) -> noExtCon x
761+ ArithSeq NoExtField _ x ->
762+ case x of
763+ From from -> brackets s $ do
764+ located from p_hsExpr
765+ breakpoint
766+ txt ".."
767+ FromThen from next -> brackets s $ do
768+ sep commaDel (located' p_hsExpr) [from, next]
769+ breakpoint
770+ txt ".."
771+ FromTo from to -> brackets s $ do
772+ located from p_hsExpr
773+ breakpoint
774+ txt ".."
775+ space
776+ located to p_hsExpr
777+ FromThenTo from next to -> brackets s $ do
778+ sep commaDel (located' p_hsExpr) [from, next]
779+ breakpoint
780+ txt ".."
781+ space
782+ located to p_hsExpr
783+ HsSCC NoExtField _ name x -> do
784+ txt "{-# SCC "
785+ atom name
786+ txt " #-}"
787+ breakpoint
788+ located x p_hsExpr
789+ HsCoreAnn NoExtField _ value x -> do
790+ txt "{-# CORE "
791+ atom value
792+ txt " #-}"
793+ breakpoint
794+ located x p_hsExpr
795+ HsBracket NoExtField x -> p_hsBracket x
796+ HsRnBracketOut {} -> notImplemented "HsRnBracketOut"
797+ HsTcBracketOut {} -> notImplemented "HsTcBracketOut"
798+ HsSpliceE NoExtField splice -> p_hsSplice splice
799+ HsProc NoExtField p e -> do
800+ txt "proc"
801+ located p $ \x -> do
802+ breakpoint
803+ inci (p_pat x)
804+ breakpoint
805+ txt "->"
806+ placeHanging (cmdTopPlacement (unLoc e)) $
807+ located e p_hsCmdTop
808+ HsStatic _ e -> do
809+ txt "static"
810+ breakpoint
811+ inci (located e p_hsExpr)
812+ HsTick {} -> notImplemented "HsTick"
813+ HsBinTick {} -> notImplemented "HsBinTick"
814+ HsTickPragma {} -> notImplemented "HsTickPragma"
815+ HsWrap {} -> notImplemented "HsWrap"
816+ XExpr x -> noExtCon x
817+
818+p_patSynBind :: PatSynBind GhcPs GhcPs -> R ()
819+p_patSynBind PSB {..} = do
820+ let rhs = do
821+ space
822+ case psb_dir of
823+ Unidirectional -> do
824+ txt "<-"
825+ breakpoint
826+ located psb_def p_pat
827+ ImplicitBidirectional -> do
828+ equals
829+ breakpoint
830+ located psb_def p_pat
831+ ExplicitBidirectional mgroup -> do
832+ txt "<-"
833+ breakpoint
834+ located psb_def p_pat
835+ newline
836+ txt "where"
837+ newline
838+ inci (p_matchGroup (Function psb_id) mgroup)
839+ txt "pattern"
840+ case psb_args of
841+ PrefixCon xs -> do
842+ space
843+ p_rdrName psb_id
844+ inci $ do
845+ switchLayout (getLoc <$> xs) $ do
846+ unless (null xs) breakpoint
847+ sitcc (sep breakpoint p_rdrName xs)
848+ rhs
849+ RecCon xs -> do
850+ space
851+ p_rdrName psb_id
852+ inci $ do
853+ switchLayout (getLoc . recordPatSynPatVar <$> xs) $ do
854+ unless (null xs) breakpoint
855+ braces N $
856+ sep commaDel (p_rdrName . recordPatSynPatVar) xs
857+ rhs
858+ InfixCon l r -> do
859+ switchLayout [getLoc l, getLoc r] $ do
860+ space
861+ p_rdrName l
862+ breakpoint
863+ inci $ do
864+ p_rdrName psb_id
865+ space
866+ p_rdrName r
867+ inci rhs
868+p_patSynBind (XPatSynBind x) = noExtCon x
869+
870+p_case ::
871+ Data body =>
872+ -- | Placer
873+ (body -> Placement) ->
874+ -- | Render
875+ (body -> R ()) ->
876+ -- | Expression
877+ LHsExpr GhcPs ->
878+ -- | Match group
879+ MatchGroup GhcPs (Located body) ->
880+ R ()
881+p_case placer render e mgroup = do
882+ txt "case"
883+ space
884+ located e p_hsExpr
885+ space
886+ txt "of"
887+ breakpoint
888+ inci (p_matchGroup' placer render Case mgroup)
889+
890+p_if ::
891+ Data body =>
892+ -- | Placer
893+ (body -> Placement) ->
894+ -- | Render
895+ (body -> R ()) ->
896+ -- | If
897+ LHsExpr GhcPs ->
898+ -- | Then
899+ Located body ->
900+ -- | Else
901+ Located body ->
902+ R ()
903+p_if placer render if' then' else' = do
904+ txt "if"
905+ space
906+ located if' p_hsExpr
907+ breakpoint
908+ inci $ do
909+ txt "then"
910+ space
911+ located then' $ \x ->
912+ placeHanging (placer x) (render x)
913+ breakpoint
914+ txt "else"
915+ space
916+ located else' $ \x ->
917+ placeHanging (placer x) (render x)
918+
919+p_let ::
920+ Data body =>
921+ -- | Render
922+ (body -> R ()) ->
923+ Located (HsLocalBindsLR GhcPs GhcPs) ->
924+ Located body ->
925+ R ()
926+p_let render localBinds e = sitcc $ do
927+ txt "let"
928+ space
929+ dontUseBraces $ sitcc (located localBinds p_hsLocalBinds)
930+ vlayout space (newline >> txt " ")
931+ txt "in"
932+ space
933+ sitcc (located e render)
934+
935+p_pat :: Pat GhcPs -> R ()
936+p_pat = \case
937+ WildPat NoExtField -> txt "_"
938+ VarPat NoExtField name -> p_rdrName name
939+ LazyPat NoExtField pat -> do
940+ txt "~"
941+ located pat p_pat
942+ AsPat NoExtField name pat -> do
943+ p_rdrName name
944+ txt "@"
945+ located pat p_pat
946+ ParPat NoExtField pat ->
947+ located pat (parens S . p_pat)
948+ BangPat NoExtField pat -> do
949+ txt "!"
950+ located pat p_pat
951+ ListPat NoExtField pats ->
952+ brackets S $ sep commaDel (located' p_pat) pats
953+ TuplePat NoExtField pats boxing -> do
954+ let parens' =
955+ case boxing of
956+ Boxed -> parens S
957+ Unboxed -> parensHash S
958+ parens' $ sep commaDel (sitcc . located' p_pat) pats
959+ SumPat NoExtField pat tag arity ->
960+ p_unboxedSum S tag arity (located pat p_pat)
961+ ConPatIn pat details ->
962+ case details of
963+ PrefixCon xs -> sitcc $ do
964+ p_rdrName pat
965+ unless (null xs) $ do
966+ breakpoint
967+ inci . sitcc $ sep breakpoint (sitcc . located' p_pat) xs
968+ RecCon (HsRecFields fields dotdot) -> do
969+ p_rdrName pat
970+ breakpoint
971+ let f = \case
972+ Nothing -> txt ".."
973+ Just x -> located x p_pat_hsRecField
974+ inci . braces N . sep commaDel f $
975+ case dotdot of
976+ Nothing -> Just <$> fields
977+ Just (L _ n) -> (Just <$> take n fields) ++ [Nothing]
978+ InfixCon l r -> do
979+ switchLayout [getLoc l, getLoc r] $ do
980+ located l p_pat
981+ breakpoint
982+ inci $ do
983+ p_rdrName pat
984+ space
985+ located r p_pat
986+ ConPatOut {} -> notImplemented "ConPatOut" -- presumably created by renamer?
987+ ViewPat NoExtField expr pat -> sitcc $ do
988+ located expr p_hsExpr
989+ space
990+ txt "->"
991+ breakpoint
992+ inci (located pat p_pat)
993+ SplicePat NoExtField splice -> p_hsSplice splice
994+ LitPat NoExtField p -> atom p
995+ NPat NoExtField v _ _ -> located v (atom . ol_val)
996+ NPlusKPat NoExtField n k _ _ _ -> sitcc $ do
997+ p_rdrName n
998+ breakpoint
999+ inci $ do
1000+ txt "+"
1001+ space
1002+ located k (atom . ol_val)
1003+ SigPat NoExtField pat hswc -> do
1004+ located pat p_pat
1005+ p_typeAscription hswc
1006+ CoPat {} -> notImplemented "CoPat" -- apparently created at some later stage
1007+ XPat x -> noExtCon x
1008+
1009+p_pat_hsRecField :: HsRecField' (FieldOcc GhcPs) (LPat GhcPs) -> R ()
1010+p_pat_hsRecField HsRecField {..} = do
1011+ located hsRecFieldLbl $ \x ->
1012+ p_rdrName (rdrNameFieldOcc x)
1013+ unless hsRecPun $ do
1014+ space
1015+ equals
1016+ breakpoint
1017+ inci (located hsRecFieldArg p_pat)
1018+
1019+p_unboxedSum :: BracketStyle -> ConTag -> Arity -> R () -> R ()
1020+p_unboxedSum s tag arity m = do
1021+ let before = tag - 1
1022+ after = arity - before - 1
1023+ args = replicate before Nothing <> [Just m] <> replicate after Nothing
1024+ f x =
1025+ case x :: Maybe (R ()) of
1026+ Nothing ->
1027+ space
1028+ Just m' -> do
1029+ space
1030+ m'
1031+ space
1032+ parensHash s $ sep (txt "|") f args
1033+
1034+p_hsSplice :: HsSplice GhcPs -> R ()
1035+p_hsSplice = \case
1036+ HsTypedSplice NoExtField deco _ expr -> p_hsSpliceTH True expr deco
1037+ HsUntypedSplice NoExtField deco _ expr -> p_hsSpliceTH False expr deco
1038+ HsQuasiQuote NoExtField _ quoterName srcSpan str -> do
1039+ txt "["
1040+ p_rdrName (L srcSpan quoterName)
1041+ txt "|"
1042+ -- QuasiQuoters often rely on precise custom strings. We cannot do any
1043+ -- formatting here without potentially breaking someone's code.
1044+ atom str
1045+ txt "|]"
1046+ HsSpliced {} -> notImplemented "HsSpliced"
1047+ HsSplicedT {} -> notImplemented "HsSplicedT"
1048+ XSplice x -> noExtCon x
1049+
1050+p_hsSpliceTH ::
1051+ -- | Typed splice?
1052+ Bool ->
1053+ -- | Splice expression
1054+ LHsExpr GhcPs ->
1055+ -- | Splice decoration
1056+ SpliceDecoration ->
1057+ R ()
1058+p_hsSpliceTH isTyped expr = \case
1059+ HasParens -> do
1060+ txt decoSymbol
1061+ parens N (located expr (sitcc . p_hsExpr))
1062+ HasDollar -> do
1063+ txt decoSymbol
1064+ located expr (sitcc . p_hsExpr)
1065+ NoParens ->
1066+ located expr (sitcc . p_hsExpr)
1067+ where
1068+ decoSymbol = if isTyped then "$$" else "$"
1069+
1070+p_hsBracket :: HsBracket GhcPs -> R ()
1071+p_hsBracket = \case
1072+ ExpBr NoExtField expr -> do
1073+ anns <- getEnclosingAnns
1074+ let name = case anns of
1075+ AnnOpenEQ : _ -> ""
1076+ _ -> "e"
1077+ quote name (located expr p_hsExpr)
1078+ PatBr NoExtField pat -> located pat (quote "p" . p_pat)
1079+ DecBrL NoExtField decls -> quote "d" (p_hsDecls Free decls)
1080+ DecBrG NoExtField _ -> notImplemented "DecBrG" -- result of renamer
1081+ TypBr NoExtField ty -> quote "t" (located ty p_hsType)
1082+ VarBr NoExtField isSingleQuote name -> do
1083+ txt (bool "''" "'" isSingleQuote)
1084+ -- HACK As you can see we use 'noLoc' here to be able to pass name into
1085+ -- 'p_rdrName' since the latter expects a "located" thing. The problem
1086+ -- is that 'VarBr' doesn't provide us with location of the name. This in
1087+ -- turn makes it impossible to detect if there are parentheses around
1088+ -- it, etc. So we have to add parentheses manually assuming they are
1089+ -- necessary for all operators.
1090+ let isOperator =
1091+ all
1092+ (\i -> isPunctuation i || isSymbol i)
1093+ (showOutputable (rdrNameOcc name))
1094+ && not (doesNotNeedExtraParens name)
1095+ wrapper = if isOperator then parens N else id
1096+ wrapper $ p_rdrName (noLoc name)
1097+ TExpBr NoExtField expr -> do
1098+ txt "[||"
1099+ breakpoint'
1100+ located expr p_hsExpr
1101+ breakpoint'
1102+ txt "||]"
1103+ XBracket x -> noExtCon x
1104+ where
1105+ quote :: Text -> R () -> R ()
1106+ quote name body = do
1107+ txt "["
1108+ txt name
1109+ txt "|"
1110+ breakpoint'
1111+ inci $ do
1112+ dontUseBraces body
1113+ breakpoint'
1114+ txt "|]"
1115+
1116+-- Print the source text of a string literal while indenting
1117+-- gaps correctly.
1118+
1119+p_stringLit :: String -> R ()
1120+p_stringLit src =
1121+ let s = splitGaps src
1122+ singleLine =
1123+ txt $ Text.pack (mconcat s)
1124+ multiLine =
1125+ sitcc $ sep breakpoint (txt . Text.pack) (backslashes s)
1126+ in vlayout singleLine multiLine
1127+ where
1128+ -- Split a string on gaps (backslash delimited whitespaces)
1129+ --
1130+ -- > splitGaps "bar\\ \\fo\\&o" == ["bar", "fo\\&o"]
1131+ splitGaps :: String -> [String]
1132+ splitGaps "" = []
1133+ splitGaps s =
1134+ let -- A backslash and a whitespace starts a "gap"
1135+ p (Just '\\', _, _) = True
1136+ p (_, '\\', Just c) | ghcSpace c = False
1137+ p _ = True
1138+ in case span p (zipPrevNext s) of
1139+ (l, r) ->
1140+ let -- drop the initial '\', any amount of 'ghcSpace', and another '\'
1141+ r' = drop 1 . dropWhile ghcSpace . drop 1 $ map orig r
1142+ in map orig l : splitGaps r'
1143+ -- GHC's definition of whitespaces in strings
1144+ -- See: https://gitlab.haskell.org/ghc/ghc/blob/86753475/compiler/parser/Lexer.x#L1653
1145+ ghcSpace :: Char -> Bool
1146+ ghcSpace c = c <= '\x7f' && is_space c
1147+ -- Add backslashes to the inner side of the strings
1148+ --
1149+ -- > backslashes ["a", "b", "c"] == ["a\\", "\\b\\", "\\c"]
1150+ backslashes :: [String] -> [String]
1151+ backslashes (x : y : xs) = (x ++ "\\") : backslashes (('\\' : y) : xs)
1152+ backslashes xs = xs
1153+ -- Attaches previous and next items to each list element
1154+ zipPrevNext :: [a] -> [(Maybe a, a, Maybe a)]
1155+ zipPrevNext xs =
1156+ let z =
1157+ zip
1158+ (zip (Nothing : map Just xs) xs)
1159+ (map Just (tail xs) ++ repeat Nothing)
1160+ in map (\((p, x), n) -> (p, x, n)) z
1161+ orig (_, x, _) = x
1162+
1163+----------------------------------------------------------------------------
1164+-- Helpers
1165+
1166+-- | Return the wrapping function controlling the use of braces according to
1167+-- the current layout.
1168+layoutToBraces :: Layout -> R () -> R ()
1169+layoutToBraces = \case
1170+ SingleLine -> useBraces
1171+ MultiLine -> id
1172+
1173+-- | Append each element in both lists with semigroups. If one list is shorter
1174+-- than the other, return the rest of the longer list unchanged.
1175+liftAppend :: Semigroup a => [a] -> [a] -> [a]
1176+liftAppend [] [] = []
1177+liftAppend [] (y : ys) = y : ys
1178+liftAppend (x : xs) [] = x : xs
1179+liftAppend (x : xs) (y : ys) = x <> y : liftAppend xs ys
1180+
1181+getGRHSSpan :: GRHS GhcPs (Located body) -> SrcSpan
1182+getGRHSSpan (GRHS NoExtField guards body) =
1183+ combineSrcSpans' $ getLoc body :| map getLoc guards
1184+getGRHSSpan (XGRHS x) = noExtCon x
1185+
1186+-- | Place a thing that may have a hanging form. This function handles how
1187+-- to separate it from preceding expressions and whether to bump indentation
1188+-- depending on what sort of expression we have.
1189+placeHanging :: Placement -> R () -> R ()
1190+placeHanging placement m =
1191+ case placement of
1192+ Hanging -> do
1193+ space
1194+ m
1195+ Normal -> do
1196+ breakpoint
1197+ inci m
1198+
1199+-- | Check if given block contains single expression which has a hanging
1200+-- form.
1201+blockPlacement ::
1202+ (body -> Placement) ->
1203+ [LGRHS GhcPs (Located body)] ->
1204+ Placement
1205+blockPlacement placer [L _ (GRHS NoExtField _ (L _ x))] = placer x
1206+blockPlacement _ _ = Normal
1207+
1208+-- | Check if given command has a hanging form.
1209+cmdPlacement :: HsCmd GhcPs -> Placement
1210+cmdPlacement = \case
1211+ HsCmdLam NoExtField _ -> Hanging
1212+ HsCmdCase NoExtField _ _ -> Hanging
1213+ HsCmdDo NoExtField _ -> Hanging
1214+ _ -> Normal
1215+
1216+cmdTopPlacement :: HsCmdTop GhcPs -> Placement
1217+cmdTopPlacement = \case
1218+ HsCmdTop NoExtField (L _ x) -> cmdPlacement x
1219+ XCmdTop x -> noExtCon x
1220+
1221+-- | Check if given expression has a hanging form.
1222+exprPlacement :: HsExpr GhcPs -> Placement
1223+exprPlacement = \case
1224+ -- Only hang lambdas with single line parameter lists
1225+ HsLam NoExtField mg -> case mg of
1226+ MG _ (L _ [L _ (Match NoExtField _ (x : xs) _)]) _
1227+ | isOneLineSpan (combineSrcSpans' $ fmap getLoc (x :| xs)) ->
1228+ Hanging
1229+ _ -> Normal
1230+ HsLamCase NoExtField _ -> Hanging
1231+ HsCase NoExtField _ _ -> Hanging
1232+ HsDo NoExtField DoExpr _ -> Hanging
1233+ HsDo NoExtField MDoExpr _ -> Hanging
1234+ OpApp NoExtField _ op y ->
1235+ case (fmap getOpNameStr . getOpName . unLoc) op of
1236+ Just "$" -> exprPlacement (unLoc y)
1237+ _ -> Normal
1238+ HsApp NoExtField _ y -> exprPlacement (unLoc y)
1239+ HsProc NoExtField p _ ->
1240+ -- Indentation breaks if pattern is longer than one line and left
1241+ -- hanging. Consequently, only apply hanging when it is safe.
1242+ if isOneLineSpan (getLoc p)
1243+ then Hanging
1244+ else Normal
1245+ _ -> Normal
1246+
1247+withGuards :: [LGRHS GhcPs (Located body)] -> Bool
1248+withGuards = any (checkOne . unLoc)
1249+ where
1250+ checkOne :: GRHS GhcPs (Located body) -> Bool
1251+ checkOne (GRHS NoExtField [] _) = False
1252+ checkOne _ = True
1253+
1254+exprOpTree :: LHsExpr GhcPs -> OpTree (LHsExpr GhcPs) (LHsExpr GhcPs)
1255+exprOpTree (L _ (OpApp NoExtField x op y)) = OpBranch (exprOpTree x) op (exprOpTree y)
1256+exprOpTree n = OpNode n
1257+
1258+getOpName :: HsExpr GhcPs -> Maybe RdrName
1259+getOpName = \case
1260+ HsVar NoExtField (L _ a) -> Just a
1261+ _ -> Nothing
1262+
1263+getOpNameStr :: RdrName -> String
1264+getOpNameStr = occNameString . rdrNameOcc
1265+
1266+p_exprOpTree ::
1267+ -- | Bracket style to use
1268+ BracketStyle ->
1269+ OpTree (LHsExpr GhcPs) (LHsExpr GhcPs) ->
1270+ R ()
1271+p_exprOpTree s (OpNode x) = located x (p_hsExpr' s)
1272+p_exprOpTree s (OpBranch x op y) = do
1273+ -- If the beginning of the first argument and the second argument are on
1274+ -- the same line, and the second argument has a hanging form, use hanging
1275+ -- placement.
1276+ let placement =
1277+ if isOneLineSpan
1278+ (mkSrcSpan (srcSpanStart (opTreeLoc x)) (srcSpanStart (opTreeLoc y)))
1279+ then case y of
1280+ OpNode (L _ n) -> exprPlacement n
1281+ _ -> Normal
1282+ else Normal
1283+ -- Distinguish holes used in infix notation.
1284+ -- eg. '1 _foo 2' and '1 `_foo` 2'
1285+ opWrapper = case unLoc op of
1286+ HsUnboundVar NoExtField _ -> backticks
1287+ _ -> id
1288+ layout <- getLayout
1289+ let ub = case layout of
1290+ SingleLine -> useBraces
1291+ MultiLine -> case placement of
1292+ Hanging -> useBraces
1293+ Normal -> dontUseBraces
1294+ opNameStr = (fmap getOpNameStr . getOpName . unLoc) op
1295+ gotDollar = opNameStr == Just "$"
1296+ gotColon = opNameStr == Just ":"
1297+ gotRecordDot = isRecordDot (unLoc op) (opTreeLoc y)
1298+ lhs =
1299+ switchLayout [opTreeLoc x] $
1300+ p_exprOpTree s x
1301+ p_op = located op (opWrapper . p_hsExpr)
1302+ p_y = switchLayout [opTreeLoc y] (p_exprOpTree N y)
1303+ isSection = case (opTreeLoc x, getLoc op) of
1304+ (RealSrcSpan treeSpan, RealSrcSpan opSpan) ->
1305+ srcSpanEndCol treeSpan /= srcSpanStartCol opSpan
1306+ _ -> False
1307+ isDoBlock = \case
1308+ OpNode (L _ HsDo {}) -> True
1309+ _ -> False
1310+ useRecordDot' <- useRecordDot
1311+ if
1312+ | gotColon -> do
1313+ lhs
1314+ space
1315+ p_op
1316+ case placement of
1317+ Hanging -> do
1318+ space
1319+ p_y
1320+ Normal -> do
1321+ breakpoint
1322+ inciIf (isDoBlock y) p_y
1323+ | gotDollar
1324+ && isOneLineSpan (opTreeLoc x)
1325+ && placement == Normal -> do
1326+ useBraces lhs
1327+ space
1328+ p_op
1329+ breakpoint
1330+ inci p_y
1331+ | useRecordDot' && gotRecordDot -> do
1332+ lhs
1333+ when isSection space
1334+ p_op
1335+ p_y
1336+ | otherwise -> do
1337+ ub lhs
1338+ placeHanging placement $ do
1339+ p_op
1340+ space
1341+ p_y
1342+
1343+-- | Return 'True' if given expression is a record-dot operator expression.
1344+isRecordDot ::
1345+ -- | Operator expression
1346+ HsExpr GhcPs ->
1347+ -- | Span of the expression on the right-hand side of the operator
1348+ SrcSpan ->
1349+ Bool
1350+isRecordDot op (RealSrcSpan ySpan) = case op of
1351+ HsVar NoExtField (L (RealSrcSpan opSpan) opName) ->
1352+ (getOpNameStr opName == ".") && (srcSpanEndCol opSpan == srcSpanStartCol ySpan)
1353+ _ -> False
1354+isRecordDot _ _ = False
1355+
1356+-- | Get annotations for the enclosing element.
1357+getEnclosingAnns :: R [AnnKeywordId]
1358+getEnclosingAnns = do
1359+ e <- getEnclosingSpan (const True)
1360+ case e of
1361+ Nothing -> return []
1362+ Just e' -> getAnns (RealSrcSpan e')
src/Ormolu/Printer/Meat/Declaration/Value.hs-bootnew file+17
@@ -0,0 +1,17 @@
1+module Ormolu.Printer.Meat.Declaration.Value
2+ ( p_valDecl,
3+ p_pat,
4+ p_hsExpr,
5+ p_hsSplice,
6+ p_stringLit,
7+ )
8+where
9+
10+import GHC
11+import Ormolu.Printer.Combinators
12+
13+p_valDecl :: HsBindLR GhcPs GhcPs -> R ()
14+p_pat :: Pat GhcPs -> R ()
15+p_hsExpr :: HsExpr GhcPs -> R ()
16+p_hsSplice :: HsSplice GhcPs -> R ()
17+p_stringLit :: String -> R ()
src/Ormolu/Printer/Meat/Declaration/Warning.hsnew file+49
@@ -0,0 +1,49 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+
4+module Ormolu.Printer.Meat.Declaration.Warning
5+ ( p_warnDecls,
6+ p_moduleWarning,
7+ )
8+where
9+
10+import BasicTypes
11+import Data.Foldable
12+import Data.Text (Text)
13+import GHC
14+import Ormolu.Printer.Combinators
15+import Ormolu.Printer.Meat.Common
16+
17+p_warnDecls :: WarnDecls GhcPs -> R ()
18+p_warnDecls (Warnings NoExtField _ warnings) =
19+ traverse_ (located' p_warnDecl) warnings
20+p_warnDecls (XWarnDecls x) = noExtCon x
21+
22+p_warnDecl :: WarnDecl GhcPs -> R ()
23+p_warnDecl (Warning NoExtField functions warningTxt) =
24+ p_topLevelWarning functions warningTxt
25+p_warnDecl (XWarnDecl x) = noExtCon x
26+
27+p_moduleWarning :: WarningTxt -> R ()
28+p_moduleWarning wtxt = do
29+ let (pragmaText, lits) = warningText wtxt
30+ inci $ pragma pragmaText $ inci $ p_lits lits
31+
32+p_topLevelWarning :: [Located RdrName] -> WarningTxt -> R ()
33+p_topLevelWarning fnames wtxt = do
34+ let (pragmaText, lits) = warningText wtxt
35+ switchLayout (fmap getLoc fnames ++ fmap getLoc lits) $
36+ pragma pragmaText . inci $ do
37+ sep commaDel p_rdrName fnames
38+ breakpoint
39+ p_lits lits
40+
41+warningText :: WarningTxt -> (Text, [Located StringLiteral])
42+warningText = \case
43+ WarningTxt _ lits -> ("WARNING", lits)
44+ DeprecatedTxt _ lits -> ("DEPRECATED", lits)
45+
46+p_lits :: [Located StringLiteral] -> R ()
47+p_lits = \case
48+ [l] -> atom l
49+ ls -> brackets N $ sep commaDel atom ls
src/Ormolu/Printer/Meat/ImportExport.hs+109−58
@@ -1,75 +1,126 @@
1−{-# LANGUAGE LambdaCase #-}
1+{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE RecordWildCards #-}
3+{-# LANGUAGE RecordWildCards #-}
4
4
5-- | Rendering of import and export lists.
5-- | Rendering of import and export lists.
6−
7module Ormolu.Printer.Meat.ImportExport
6module Ormolu.Printer.Meat.ImportExport
8− ( p_hsmodExports
7+ ( p_hsmodExports,
9− , p_hsmodImport
8+ p_hsmodImport,
10 )
9 )
11where
10where
12
11
13import Control.Monad
12import Control.Monad
14−import GHC hiding (GhcPs, IE)
13+import GHC
15−import HsImpExp (IE (..))
16−import Language.Haskell.GHC.ExactPrint.Types
17import Ormolu.Printer.Combinators
14import Ormolu.Printer.Combinators
18import Ormolu.Printer.Meat.Common
15import Ormolu.Printer.Meat.Common
16+import Ormolu.Utils (RelativePos (..), attachRelativePos)
19
17
20p_hsmodExports :: [LIE GhcPs] -> R ()
18p_hsmodExports :: [LIE GhcPs] -> R ()
21−p_hsmodExports xs = do
19+p_hsmodExports [] = do
22− parens . velt $ withSep comma (located' p_lie) xs
20+ txt "("
21+ breakpoint'
22+ txt ")"
23+p_hsmodExports xs =
24+ parens N $ do
25+ layout <- getLayout
26+ sep
27+ breakpoint
28+ (\(p, l) -> sitcc (located l (p_lie layout p)))
29+ (attachRelativePos xs)
23
30
24−p_hsmodImport :: ImportDecl GhcPs -> R ()
31+p_hsmodImport :: Bool -> ImportDecl GhcPs -> R ()
25−p_hsmodImport ImportDecl {..} = line $ do
32+p_hsmodImport useQualifiedPost ImportDecl {..} = do
26− txt "import "
33+ txt "import"
34+ space
27− when ideclSource $
35+ when ideclSource (txt "{-# SOURCE #-}")
28− txt "{-# SOURCE #-} "
36+ space
29− when ideclSafe $
37+ when ideclSafe (txt "safe")
30− txt "safe "
38+ space
31− when ideclQualified $
39+ when
40+ (isImportDeclQualified ideclQualified && not useQualifiedPost)
32− txt "qualified "
41+ (txt "qualified")
42+ space
33 case ideclPkgQual of
43 case ideclPkgQual of
34 Nothing -> return ()
44 Nothing -> return ()
35− Just slit -> do
36− atom slit
45+ Just slit -> atom slit
37− space
46+ space
47+ inci $ do
38− located ideclName atom
48+ located ideclName atom
49+ when
50+ (isImportDeclQualified ideclQualified && useQualifiedPost)
51+ (space >> txt "qualified")
39− case ideclAs of
52+ case ideclAs of
40− Nothing -> return ()
53+ Nothing -> return ()
41− Just l -> do
54+ Just l -> do
55+ space
42− txt " as "
56+ txt "as"
57+ space
43− located l atom
58+ located l atom
59+ space
44− case ideclHiding of
60+ case ideclHiding of
45− Nothing -> return ()
61+ Nothing -> return ()
46− Just (hiding, _) ->
62+ Just (hiding, _) ->
47− when hiding $
63+ when hiding (txt "hiding")
48− txt " hiding"
49− case ideclHiding of
64+ case ideclHiding of
50− Nothing -> return ()
65+ Nothing -> return ()
51− Just (_, l) -> do
66+ Just (_, L _ xs) -> do
52− breakpoint
67+ breakpoint
53− inci . locatedVia Nothing l $
68+ parens N $ do
54− parens . velt . withSep comma (located' p_lie)
69+ layout <- getLayout
70+ sep
71+ breakpoint
72+ (\(p, l) -> sitcc (located l (p_lie layout p)))
73+ (attachRelativePos xs)
74+ newline
75+p_hsmodImport _ (XImportDecl x) = noExtCon x
55
76
56−p_lie :: IE GhcPs -> R ()
77+p_lie :: Layout -> RelativePos -> IE GhcPs -> R ()
57−p_lie = \case
78+p_lie encLayout relativePos = \case
79+ IEVar NoExtField l1 -> do
58− IEVar l1 -> located l1 p_ieWrappedName
80+ located l1 p_ieWrappedName
81+ p_comma
82+ IEThingAbs NoExtField l1 -> do
59− IEThingAbs l1 -> located l1 p_ieWrappedName
83+ located l1 p_ieWrappedName
84+ p_comma
60− IEThingAll l1 -> do
85+ IEThingAll NoExtField l1 -> do
86+ located l1 p_ieWrappedName
87+ space
88+ txt "(..)"
89+ p_comma
90+ IEThingWith NoExtField l1 w xs _ -> sitcc $ do
61 located l1 p_ieWrappedName
91 located l1 p_ieWrappedName
62− txt " (..)"
92+ breakpoint
63− IEThingWith l1 w xs _ -> velt'
64− [ located l1 p_ieWrappedName
65− , inci $ do
93+ inci $ do
66− p_ieWildcard w
94+ let names :: [R ()]
67− parens . velt $ withSep comma (located' p_ieWrappedName) xs
95+ names = located' p_ieWrappedName <$> xs
68− ]
96+ parens N . sep commaDel sitcc $
69− -- XXX I have no idea what field labels are in this context.
97+ case w of
70− -- parens . velt $ withSep comma (located' p_FieldLbl) fls
98+ NoIEWildcard -> names
99+ IEWildcard n ->
100+ let (before, after) = splitAt n names
101+ in before ++ [txt ".."] ++ after
102+ p_comma
103+ IEModuleContents NoExtField l1 -> do
71− IEModuleContents l1 -> located l1 p_hsmodName
104+ located l1 p_hsmodName
72− -- XXX I have no idea what these things are for.
105+ p_comma
106+ IEGroup NoExtField n str -> do
107+ case relativePos of
73− IEGroup _ _ -> return ()
108+ SinglePos -> return ()
74− IEDoc _ -> return ()
109+ FirstPos -> return ()
75− IEDocNamed _ -> return ()
110+ MiddlePos -> newline
111+ LastPos -> newline
112+ p_hsDocString (Asterisk n) False (noLoc str)
113+ IEDoc NoExtField str ->
114+ p_hsDocString Pipe False (noLoc str)
115+ IEDocNamed NoExtField str -> p_hsDocName str
116+ XIE x -> noExtCon x
117+ where
118+ p_comma =
119+ case encLayout of
120+ SingleLine ->
121+ case relativePos of
122+ SinglePos -> return ()
123+ FirstPos -> comma
124+ MiddlePos -> comma
125+ LastPos -> return ()
126+ MultiLine -> comma
src/Ormolu/Printer/Meat/Module.hs+59−26
@@ -1,44 +1,77 @@
1+{-# LANGUAGE LambdaCase #-}
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE RecordWildCards #-}
3+{-# LANGUAGE RecordWildCards #-}
3
4
4-- | Rendering of modules.
5-- | Rendering of modules.
5−
6module Ormolu.Printer.Meat.Module
6module Ormolu.Printer.Meat.Module
7− ( p_hsModule
7+ ( p_hsModule,
8 )
8 )
9where
9where
10
10
11import Control.Monad
11import Control.Monad
12−import GHC hiding (GhcPs, IE)
12+import qualified Data.Text as T
13+import GHC
14+import Ormolu.Imports (normalizeImports)
13−import Ormolu.Imports
15+import Ormolu.Parser.CommentStream
16+import Ormolu.Parser.Pragma
17+import Ormolu.Parser.Shebang
14import Ormolu.Printer.Combinators
18import Ormolu.Printer.Combinators
19+import Ormolu.Printer.Comments
15import Ormolu.Printer.Meat.Common
20import Ormolu.Printer.Meat.Common
16import Ormolu.Printer.Meat.Declaration
21import Ormolu.Printer.Meat.Declaration
22+import Ormolu.Printer.Meat.Declaration.Warning
17import Ormolu.Printer.Meat.ImportExport
23import Ormolu.Printer.Meat.ImportExport
18−import SrcLoc (combineSrcSpans)
24+import Ormolu.Printer.Meat.Pragma
19
25
26+-- | Render a module.
20−p_hsModule :: ParsedSource -> R ()
27+p_hsModule ::
21−p_hsModule loc@(L moduleSpan hsModule) = do
28+ -- | Stack header
22− -- NOTE If span of exports in multiline, the whole thing is multiline.
29+ Maybe (RealLocated Comment) ->
23− -- This is especially important because span of module itself always seems
30+ -- | Shebangs
24− -- to have length zero, so it's not reliable for layout selection.
31+ [Shebang] ->
25− let spn =
32+ -- | Pragmas and the associated comments
33+ [([RealLocated Comment], Pragma)] ->
34+ -- | Whether to use postfix qualified imports
35+ Bool ->
36+ -- | AST to print
37+ HsModule GhcPs ->
38+ R ()
39+p_hsModule mstackHeader shebangs pragmas qualifiedPost HsModule {..} = do
40+ let deprecSpan = maybe [] (\(L s _) -> [s]) hsmodDeprecMessage
26− case hsmodExports hsModule of
41+ exportSpans = maybe [] (\(L s _) -> [s]) hsmodExports
27− Nothing -> moduleSpan
42+ switchLayout (deprecSpan <> exportSpans) $ do
28− Just (L exportsSpan _) -> combineSrcSpans moduleSpan exportsSpan
43+ forM_ shebangs $ \(Shebang x) ->
29− locatedVia (Just spn) loc $ \HsModule {..} -> do
44+ located x $ \shebang -> do
45+ txt (T.pack shebang)
46+ newline
47+ forM_ mstackHeader $ \(L spn comment) -> do
48+ spitCommentNow spn comment
49+ newline
50+ newline
51+ p_pragmas pragmas
52+ newline
30 case hsmodName of
53 case hsmodName of
31− Nothing -> pure ()
54+ Nothing -> return ()
32− Just hsmodName' -> line $ do
55+ Just hsmodName' -> do
33− located hsmodName' p_hsmodName
56+ located hsmodName' $ \name -> do
57+ forM_ hsmodHaddockModHeader (p_hsDocString Pipe True)
58+ p_hsmodName name
59+ breakpoint
60+ forM_ hsmodDeprecMessage $ \w -> do
61+ located' p_moduleWarning w
62+ breakpoint
34 case hsmodExports of
63 case hsmodExports of
35 Nothing -> return ()
64 Nothing -> return ()
36− Just hsmodExports' -> do
65+ Just l -> do
66+ located l $ \exports -> do
67+ inci (p_hsmodExports exports)
37 breakpoint
68 breakpoint
38− inci (locatedVia Nothing hsmodExports' p_hsmodExports)
39− breakpoint
40 txt "where"
69 txt "where"
41− unless (null hsmodImports) newline
70+ newline
71+ newline
42− forM_ (sortImports hsmodImports) (located' p_hsmodImport)
72+ forM_ (normalizeImports hsmodImports) (located' (p_hsmodImport qualifiedPost))
43− when (not (null hsmodImports) && not (null hsmodDecls)) newline
73+ newline
44− newlineSep (located' p_hsDecl) hsmodDecls
74+ switchLayout (getLoc <$> hsmodDecls) $ do
75+ p_hsDecls Free hsmodDecls
76+ newline
77+ spitRemainingComments
src/Ormolu/Printer/Meat/Pragma.hsnew file+91
@@ -0,0 +1,91 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE TupleSections #-}
4+
5+-- | Pretty-printing of language pragmas.
6+module Ormolu.Printer.Meat.Pragma
7+ ( p_pragmas,
8+ )
9+where
10+
11+import Control.Monad
12+import Data.Char (isUpper)
13+import qualified Data.List as L
14+import Data.Maybe (listToMaybe)
15+import qualified Data.Text as T
16+import Ormolu.Parser.CommentStream
17+import Ormolu.Parser.Pragma (Pragma (..))
18+import Ormolu.Printer.Combinators
19+import Ormolu.Printer.Comments
20+import SrcLoc
21+
22+-- | Pragma classification.
23+data PragmaTy
24+ = Language LanguagePragmaClass
25+ | OptionsGHC
26+ | OptionsHaddock
27+ deriving (Eq, Ord)
28+
29+-- | Language pragma classification.
30+--
31+-- The order in which language pragmas are put in the input sometimes
32+-- matters. This is because some language extensions can enable other
33+-- extensions, yet the extensions coming later in the list have the ability
34+-- to change it. So here we classify all extensions by assigning one of the
35+-- four groups to them. Then we only sort inside of the groups.
36+--
37+-- 'Ord' instance of this data type is what affects the sorting.
38+--
39+-- See also: <https://github.com/tweag/ormolu/issues/404>
40+data LanguagePragmaClass
41+ = -- | All other extensions
42+ Normal
43+ | -- | Extensions starting with "No"
44+ Disabling
45+ | -- | Extensions that should go after everything else
46+ Final
47+ deriving (Eq, Ord)
48+
49+-- | Print a collection of 'Pragma's with their associated comments.
50+p_pragmas :: [([RealLocated Comment], Pragma)] -> R ()
51+p_pragmas ps = do
52+ let prepare = L.sortOn snd . L.nub . concatMap analyze
53+ analyze = \case
54+ (cs, PragmaLanguage xs) ->
55+ let f x = (cs, (Language (classifyLanguagePragma x), x))
56+ in f <$> xs
57+ (cs, PragmaOptionsGHC x) -> [(cs, (OptionsGHC, x))]
58+ (cs, PragmaOptionsHaddock x) -> [(cs, (OptionsHaddock, x))]
59+ forM_ (prepare ps) $ \(cs, (pragmaTy, x)) ->
60+ p_pragma cs pragmaTy x
61+
62+p_pragma :: [RealLocated Comment] -> PragmaTy -> String -> R ()
63+p_pragma comments ty x = do
64+ forM_ comments $ \(L l comment) -> do
65+ spitCommentNow l comment
66+ newline
67+ txt "{-# "
68+ txt $ case ty of
69+ Language _ -> "LANGUAGE"
70+ OptionsGHC -> "OPTIONS_GHC"
71+ OptionsHaddock -> "OPTIONS_HADDOCK"
72+ space
73+ txt (T.pack x)
74+ txt " #-}"
75+ newline
76+
77+-- | Classify a 'LanguagePragma'.
78+classifyLanguagePragma :: String -> LanguagePragmaClass
79+classifyLanguagePragma = \case
80+ "ImplicitPrelude" -> Final
81+ "CUSKs" -> Final
82+ str ->
83+ case splitAt 2 str of
84+ ("No", rest) ->
85+ case listToMaybe rest of
86+ Nothing -> Normal
87+ Just x ->
88+ if isUpper x
89+ then Disabling
90+ else Normal
91+ _ -> Normal
src/Ormolu/Printer/Meat/Type.hs+236−105
@@ -1,144 +1,275 @@
1−{-# LANGUAGE LambdaCase #-}
1+{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3−{-# LANGUAGE RecordWildCards #-}
3+{-# LANGUAGE RecordWildCards #-}
4
4
5-- | Rendering of types.
5-- | Rendering of types.
6−
7module Ormolu.Printer.Meat.Type
6module Ormolu.Printer.Meat.Type
8− ( p_hsType
7+ ( p_hsType,
8+ p_hsTypePostDoc,
9+ hasDocStrings,
9− , p_hsContext
10+ p_hsContext,
10− , p_hsTyVarBndr
11+ p_hsTyVarBndr,
12+ p_forallBndrs,
11− , p_conDeclFields
13+ p_conDeclFields,
14+ tyVarsToTypes,
12 )
15 )
13where
16where
14
17
15−import GHC hiding (GhcPs, IE)
18+import Data.Data (Data)
16−import Language.Haskell.GHC.ExactPrint.Types
19+import GHC hiding (isPromoted)
17import Ormolu.Printer.Combinators
20import Ormolu.Printer.Combinators
18import Ormolu.Printer.Meat.Common
21import Ormolu.Printer.Meat.Common
22+import {-# SOURCE #-} Ormolu.Printer.Meat.Declaration.Value (p_hsSplice, p_stringLit)
23+import Ormolu.Printer.Operators
24+import Ormolu.Utils
19
25
20p_hsType :: HsType GhcPs -> R ()
26p_hsType :: HsType GhcPs -> R ()
21−p_hsType = \case
27+p_hsType t = p_hsType' (hasDocStrings t) PipeStyle t
28+
29+p_hsTypePostDoc :: HsType GhcPs -> R ()
30+p_hsTypePostDoc t = p_hsType' (hasDocStrings t) CaretStyle t
31+
32+-- | How to render Haddocks associated with a type.
33+data TypeDocStyle
34+ = PipeStyle
35+ | CaretStyle
36+
37+p_hsType' :: Bool -> TypeDocStyle -> HsType GhcPs -> R ()
38+p_hsType' multilineArgs docStyle = \case
22− HsForAllTy bndrs t -> do
39+ HsForAllTy NoExtField visibility bndrs t -> do
23− txt "forall "
24− spaceSep (located' p_hsTyVarBndr) bndrs
40+ p_forallBndrs visibility p_hsTyVarBndr bndrs
25− txt ". "
41+ interArgBreak
26− locatedVia Nothing t p_hsType
42+ p_hsTypeR (unLoc t)
27− HsQualTy qs t -> do
43+ HsQualTy NoExtField qs t -> do
28− locatedVia Nothing qs p_hsContext
44+ located qs p_hsContext
29− breakpoint
45+ space
30− txt "=> "
46+ txt "=>"
31− locatedVia Nothing t p_hsType
47+ interArgBreak
48+ case unLoc t of
49+ HsQualTy {} -> p_hsTypeR (unLoc t)
50+ HsFunTy {} -> p_hsTypeR (unLoc t)
51+ _ -> located t p_hsTypeR
32− HsTyVar p n -> do
52+ HsTyVar NoExtField p n -> do
33 case p of
53 case p of
54+ IsPromoted -> do
34− Promoted -> txt "'"
55+ txt "'"
56+ case showOutputable (unLoc n) of
57+ _ : '\'' : _ -> space
58+ _ -> return ()
35 NotPromoted -> return ()
59 NotPromoted -> return ()
36− located n p_rdrName
60+ p_rdrName n
37− HsAppsTy apps ->
61+ HsAppTy NoExtField f x -> do
38− velt' $ case apps of
62+ let -- In order to format type applications with multiple parameters
39− [] -> []
63+ -- nicer, traverse the AST to gather the function and all the
40− (x:xs) -> located' p_hsAppType x : (located' (inci . p_hsAppType) <$> xs)
64+ -- parameters together.
41− HsAppTy f x -> velt'
65+ gatherArgs f' knownArgs =
42− [ located f p_hsType
66+ case f' of
43− , inci $ located x p_hsType
67+ L _ (HsAppTy _ l r) -> gatherArgs l (r : knownArgs)
44− ]
68+ _ -> (f', knownArgs)
45− HsFunTy f x@(L _ x') -> do
69+ (func, args) = gatherArgs f [x]
70+ switchLayout (getLoc f : fmap getLoc args) . sitcc $ do
71+ located func p_hsType
72+ breakpoint
73+ inci $
74+ sep breakpoint (located' p_hsType) args
75+ HsAppKindTy _ ty kd -> sitcc $ do
76+ -- The first argument is the location of the "@..." part. Not 100% sure,
77+ -- but I think we can ignore it as long as we use 'located' on both the
78+ -- type and the kind.
46− located f p_hsType
79+ located ty p_hsType
47 breakpoint
80 breakpoint
81+ inci $ do
48− txt "-> "
82+ txt "@"
83+ located kd p_hsType
84+ HsFunTy NoExtField x y@(L _ y') -> do
85+ located x p_hsType
86+ space
87+ txt "->"
88+ interArgBreak
49− let located_ = case x' of
89+ case y' of
50− HsFunTy{} -> locatedVia Nothing
90+ HsFunTy {} -> p_hsTypeR y'
51− _ -> located
91+ _ -> located y p_hsTypeR
52− located_ x p_hsType
92+ HsListTy NoExtField t ->
53− HsListTy t -> located t (brackets . p_hsType)
93+ located t (brackets N . p_hsType)
54− HsPArrTy t -> located t (bracketsPar . p_hsType)
55− HsTupleTy tsort xs ->
94+ HsTupleTy NoExtField tsort xs ->
56 let parens' =
95 let parens' =
57 case tsort of
96 case tsort of
58− HsUnboxedTuple -> parensHash
97+ HsUnboxedTuple -> parensHash N
59− HsBoxedTuple -> parens
98+ HsBoxedTuple -> parens N
60− HsConstraintTuple -> parens
99+ HsConstraintTuple -> parens N
61− HsBoxedOrConstraintTuple -> parens
100+ HsBoxedOrConstraintTuple -> parens N
62− in parens' . velt $ withSep comma (located' p_hsType) xs
101+ in parens' $ sep commaDel (sitcc . located' p_hsType) xs
63− HsSumTy xs ->
102+ HsSumTy NoExtField xs ->
103+ parensHash N $
64− parensHash . velt $ withSep (txt "| ") (located' p_hsType) xs
104+ sep (txt "|" >> breakpoint) (sitcc . located' p_hsType) xs
65− HsOpTy x op y -> velt'
105+ HsOpTy NoExtField x op y ->
66− [ located x p_hsType
106+ sitcc $
67− , inci $ located op p_rdrName >> space >> located y p_hsType
107+ let opTree = OpBranch (tyOpTree x) op (tyOpTree y)
68− ]
108+ in p_tyOpTree (reassociateOpTree Just opTree)
69− HsParTy t ->
109+ HsParTy NoExtField t ->
70− parens (located t p_hsType)
110+ parens N (located t p_hsType)
71− HsIParamTy n t -> velt'
111+ HsIParamTy NoExtField n t -> sitcc $ do
72− [ located n atom
112+ located n atom
113+ space
114+ txt "::"
115+ breakpoint
73− , inci $ txt ":: " >> located t p_hsType
116+ inci (located t p_hsType)
74− ]
117+ HsStarTy NoExtField _ -> txt "*"
75− HsEqTy x y -> velt'
76− [ located x p_hsType
77− , inci $ txt "~ " >> located y p_hsType
78− ]
79− HsKindSig t k -> velt'
118+ HsKindSig NoExtField t k -> sitcc $ do
80− [ located t p_hsType
119+ located t p_hsType
120+ space
121+ txt "::"
122+ breakpoint
81− , inci $ txt ":: " >> located k p_hsType
123+ inci (located k p_hsType)
82− ]
124+ HsSpliceTy NoExtField splice -> p_hsSplice splice
83− HsSpliceTy _ _ -> error "HsSpliceTy"
125+ HsDocTy NoExtField t str ->
84− HsDocTy _ _ -> error "HsDocTy"
126+ case docStyle of
127+ PipeStyle -> do
128+ p_hsDocString Pipe True str
129+ located t p_hsType
130+ CaretStyle -> do
131+ located t p_hsType
132+ newline
133+ p_hsDocString Caret False str
85− HsBangTy (HsSrcBang _ u s) t -> do
134+ HsBangTy NoExtField (HsSrcBang _ u s) t -> do
86 case u of
135 case u of
87− SrcUnpack -> txt "{-# UNPACK #-} "
136+ SrcUnpack -> txt "{-# UNPACK #-}" >> space
88− SrcNoUnpack -> txt "{-# NOUNPACK #-} "
137+ SrcNoUnpack -> txt "{-# NOUNPACK #-}" >> space
89 NoSrcUnpack -> return ()
138 NoSrcUnpack -> return ()
90 case s of
139 case s of
91 SrcLazy -> txt "~"
140 SrcLazy -> txt "~"
92 SrcStrict -> txt "!"
141 SrcStrict -> txt "!"
93 NoSrcStrict -> return ()
142 NoSrcStrict -> return ()
94 located t p_hsType
143 located t p_hsType
95− HsRecTy fields ->
144+ HsRecTy NoExtField fields ->
96 p_conDeclFields fields
145 p_conDeclFields fields
97− HsCoreTy t -> atom t
98− HsExplicitListTy p _ xs -> do
146+ HsExplicitListTy NoExtField p xs -> do
99− case p of -- XXX not sure about this one
147+ case p of
100− Promoted -> txt "'"
148+ IsPromoted -> txt "'"
101 NotPromoted -> return ()
149 NotPromoted -> return ()
150+ brackets N $ do
151+ -- If both this list itself and the first element is promoted,
152+ -- we need to put a space in between or it fails to parse.
153+ case (p, xs) of
154+ (IsPromoted, L _ t : _) | isPromoted t -> space
155+ _ -> return ()
102− brackets . velt $ withSep comma (located' p_hsType) xs
156+ sep commaDel (sitcc . located' p_hsType) xs
103− HsExplicitTupleTy _ xs -> do
157+ HsExplicitTupleTy NoExtField xs -> do
104 txt "'"
158 txt "'"
159+ parens N $ do
160+ case xs of
161+ L _ t : _ | isPromoted t -> space
162+ _ -> return ()
105− parens . velt $ withSep comma (located' p_hsType) xs
163+ sep commaDel (located' p_hsType) xs
106− HsTyLit t -> atom t
164+ HsTyLit NoExtField t ->
165+ case t of
166+ HsStrTy (SourceText s) _ -> p_stringLit s
167+ a -> atom a
107− HsWildCardTy (AnonWildCard PlaceHolder) -> txt "_"
168+ HsWildCardTy NoExtField -> txt "_"
169+ XHsType (NHsCoreTy t) -> atom t
170+ where
171+ isPromoted = \case
172+ HsTyVar _ IsPromoted _ -> True
173+ HsExplicitTupleTy {} -> True
174+ HsExplicitListTy {} -> True
175+ _ -> False
176+ interArgBreak =
177+ if multilineArgs
178+ then newline
179+ else breakpoint
180+ p_hsTypeR = p_hsType' multilineArgs docStyle
181+
182+-- | Return 'True' if at least one argument in 'HsType' has a doc string
183+-- attached to it.
184+hasDocStrings :: HsType GhcPs -> Bool
185+hasDocStrings = \case
186+ HsDocTy {} -> True
187+ HsFunTy _ (L _ x) (L _ y) -> hasDocStrings x || hasDocStrings y
188+ _ -> False
108
189
109p_hsContext :: HsContext GhcPs -> R ()
190p_hsContext :: HsContext GhcPs -> R ()
110p_hsContext = \case
191p_hsContext = \case
111 [] -> txt "()"
192 [] -> txt "()"
112 [x] -> located x p_hsType
193 [x] -> located x p_hsType
113− xs -> parens . velt $ withSep comma (located' p_hsType) xs
194+ xs -> parens N $ sep commaDel (sitcc . located' p_hsType) xs
114
195
115p_hsTyVarBndr :: HsTyVarBndr GhcPs -> R ()
196p_hsTyVarBndr :: HsTyVarBndr GhcPs -> R ()
116p_hsTyVarBndr = \case
197p_hsTyVarBndr = \case
117− UserTyVar l ->
198+ UserTyVar NoExtField x ->
118− located l p_rdrName
199+ p_rdrName x
119− KindedTyVar l k -> parens $ velt'
200+ KindedTyVar NoExtField l k -> parens N $ do
120− [ located l atom
201+ located l atom
121− , inci $ txt ":: " >> located k p_hsType
202+ space
122− ]
203+ txt "::"
123−
204+ breakpoint
124−p_hsAppType :: HsAppType GhcPs -> R ()
205+ inci (located k p_hsType)
125−p_hsAppType = \case
206+ XTyVarBndr x -> noExtCon x
126− HsAppInfix l ->
207+
127− located l p_rdrName'
208+-- | Render several @forall@-ed variables.
128− HsAppPrefix l ->
209+p_forallBndrs :: Data a => ForallVisFlag -> (a -> R ()) -> [Located a] -> R ()
129− located l p_hsType
210+p_forallBndrs ForallInvis _ [] = txt "forall."
211+p_forallBndrs ForallVis _ [] = txt "forall ->"
212+p_forallBndrs vis p tyvars =
213+ switchLayout (getLoc <$> tyvars) $ do
214+ txt "forall"
215+ breakpoint
216+ inci $ do
217+ sitcc $ sep breakpoint (sitcc . located' p) tyvars
218+ case vis of
219+ ForallInvis -> txt "."
220+ ForallVis -> space >> txt "->"
130
221
131p_conDeclFields :: [LConDeclField GhcPs] -> R ()
222p_conDeclFields :: [LConDeclField GhcPs] -> R ()
132−p_conDeclFields =
223+p_conDeclFields xs =
133− braces . velt . withSep comma (located' p_conDeclField)
224+ braces N $ sep commaDel (sitcc . located' p_conDeclField) xs
134
225
135p_conDeclField :: ConDeclField GhcPs -> R ()
226p_conDeclField :: ConDeclField GhcPs -> R ()
136−p_conDeclField ConDeclField {..} = velt'
227+p_conDeclField ConDeclField {..} = do
137− [ velt $ withSep
228+ mapM_ (p_hsDocString Pipe True) cd_fld_doc
138− comma
229+ sitcc $
230+ sep
231+ commaDel
139− (located' (located' p_rdrName . rdrNameFieldOcc))
232+ (located' (p_rdrName . rdrNameFieldOcc))
140 cd_fld_names
233 cd_fld_names
141− , inci $ do
234+ space
142− txt ":: "
235+ txt "::"
143− relaxComments (locatedVia Nothing cd_fld_type p_hsType)
236+ breakpoint
144− ]
237+ sitcc . inci $ p_hsType (unLoc cd_fld_type)
238+p_conDeclField (XConDeclField x) = noExtCon x
239+
240+tyOpTree :: LHsType GhcPs -> OpTree (LHsType GhcPs) (Located RdrName)
241+tyOpTree (L _ (HsOpTy NoExtField l op r)) =
242+ OpBranch (tyOpTree l) op (tyOpTree r)
243+tyOpTree n = OpNode n
244+
245+p_tyOpTree :: OpTree (LHsType GhcPs) (Located RdrName) -> R ()
246+p_tyOpTree (OpNode n) = located n p_hsType
247+p_tyOpTree (OpBranch l op r) = do
248+ switchLayout [opTreeLoc l] $
249+ p_tyOpTree l
250+ breakpoint
251+ inci . switchLayout [opTreeLoc r] $ do
252+ p_rdrName op
253+ space
254+ p_tyOpTree r
255+
256+----------------------------------------------------------------------------
257+-- Conversion functions
258+
259+tyVarsToTypes :: LHsQTyVars GhcPs -> [LHsType GhcPs]
260+tyVarsToTypes = \case
261+ HsQTvs {..} -> fmap tyVarToType <$> hsq_explicit
262+ XLHsQTyVars x -> noExtCon x
263+
264+tyVarToType :: HsTyVarBndr GhcPs -> HsType GhcPs
265+tyVarToType = \case
266+ UserTyVar NoExtField tvar -> HsTyVar NoExtField NotPromoted tvar
267+ KindedTyVar NoExtField tvar kind ->
268+ -- Note: we always add parentheses because for whatever reason GHC does
269+ -- not use HsParTy for left-hand sides of declarations. Please see
270+ -- <https://gitlab.haskell.org/ghc/ghc/issues/17404>. This is fine as
271+ -- long as 'tyVarToType' does not get applied to right-hand sides of
272+ -- declarations.
273+ HsParTy NoExtField . noLoc $
274+ HsKindSig NoExtField (noLoc (HsTyVar NoExtField NotPromoted tvar)) kind
275+ XTyVarBndr x -> noExtCon x
src/Ormolu/Printer/Operators.hsnew file+177
@@ -0,0 +1,177 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+
4+-- | This module helps handle operator chains composed of different
5+-- operators that may have different precedence and fixities.
6+module Ormolu.Printer.Operators
7+ ( OpTree (..),
8+ opTreeLoc,
9+ reassociateOpTree,
10+ )
11+where
12+
13+import Data.Function (on)
14+import qualified Data.List as L
15+import Data.Map.Strict (Map)
16+import qualified Data.Map.Strict as M
17+import Data.Maybe (fromMaybe, mapMaybe)
18+import GHC
19+import OccName (occNameString)
20+import Ormolu.Utils (unSrcSpan)
21+
22+-- | Intermediate representation of operator trees. It has two type
23+-- parameters: @ty@ is the type of sub-expressions, while @op@ is the type
24+-- of operators.
25+data OpTree ty op
26+ = OpNode ty
27+ | OpBranch
28+ (OpTree ty op)
29+ op
30+ (OpTree ty op)
31+
32+-- | Return combined 'SrcSpan's of all elements in this 'OpTree'.
33+opTreeLoc :: OpTree (Located a) b -> SrcSpan
34+opTreeLoc (OpNode (L l _)) = l
35+opTreeLoc (OpBranch l _ r) = combineSrcSpans (opTreeLoc l) (opTreeLoc r)
36+
37+-- | Re-associate an 'OpTree' taking into account automagically inferred
38+-- relative precedence of operators. Users are expected to first construct
39+-- an initial 'OpTree', then re-associate it using this function before
40+-- printing.
41+reassociateOpTree ::
42+ -- | How to get name of an operator
43+ (op -> Maybe RdrName) ->
44+ -- | Original 'OpTree'
45+ OpTree (Located ty) (Located op) ->
46+ -- | Re-associated 'OpTree'
47+ OpTree (Located ty) (Located op)
48+reassociateOpTree getOpName opTree =
49+ reassociateOpTreeWith
50+ (buildFixityMap getOpName normOpTree)
51+ (getOpName . unLoc)
52+ normOpTree
53+ where
54+ normOpTree = normalizeOpTree opTree
55+
56+-- | Re-associate an 'OpTree' given the map with operator fixities.
57+reassociateOpTreeWith ::
58+ forall ty op.
59+ -- | Fixity map for operators
60+ Map String Fixity ->
61+ -- | How to get the name of an operator
62+ (op -> Maybe RdrName) ->
63+ -- | Original 'OpTree'
64+ OpTree ty op ->
65+ -- | Re-associated 'OpTree'
66+ OpTree ty op
67+reassociateOpTreeWith fixityMap getOpName = go
68+ where
69+ fixityOf :: op -> Fixity
70+ fixityOf op = fromMaybe defaultFixity $ do
71+ s <- occNameString . rdrNameOcc <$> getOpName op
72+ M.lookup s fixityMap
73+ -- Here, left branch is already associated and the root alongside with
74+ -- the right branch is right-associated. This function picks up one item
75+ -- from the right and inserts it correctly to the left.
76+ --
77+ -- Also, we are using the 'compareFixity' function which tells if the
78+ -- expression should associate to right.
79+ go :: OpTree ty op -> OpTree ty op
80+ -- base cases
81+ go t@(OpNode _) = t
82+ go t@(OpBranch (OpNode _) _ (OpNode _)) = t
83+ -- shift one operator to the left at the beginning
84+ go (OpBranch l@(OpNode _) op (OpBranch l' op' r')) =
85+ go (OpBranch (OpBranch l op l') op' r')
86+ -- at the last operator, place the operator and don't recurse
87+ go (OpBranch (OpBranch l op r) op' r'@(OpNode _)) =
88+ if snd $ compareFixity (fixityOf op) (fixityOf op')
89+ then OpBranch l op (go $ OpBranch r op' r')
90+ else OpBranch (OpBranch l op r) op' r'
91+ -- else, shift one operator to left and recurse.
92+ go (OpBranch (OpBranch l op r) op' (OpBranch l' op'' r')) =
93+ if snd $ compareFixity (fixityOf op) (fixityOf op')
94+ then go $ OpBranch (OpBranch l op (go $ OpBranch r op' l')) op'' r'
95+ else go $ OpBranch (OpBranch (OpBranch l op r) op' l') op'' r'
96+
97+-- | A score assigned to an operator.
98+data Score
99+ = -- | The operator was placed at the beginning of a line
100+ AtBeginning Int
101+ | -- | The operator was placed at the end of a line
102+ AtEnd
103+ | -- | The operator was placed in between arguments on a single line
104+ InBetween
105+ deriving (Eq, Ord)
106+
107+-- | Build a map of inferred 'Fixity's from an 'OpTree'.
108+buildFixityMap ::
109+ forall ty op.
110+ -- | How to get the name of an operator
111+ (op -> Maybe RdrName) ->
112+ -- | Operator tree
113+ OpTree (Located ty) (Located op) ->
114+ -- | Fixity map
115+ Map String Fixity
116+buildFixityMap getOpName opTree =
117+ addOverrides
118+ . M.fromList
119+ . concatMap (\(i, ns) -> map (\(n, _) -> (n, fixity i InfixL)) ns)
120+ . zip [2 ..]
121+ . L.groupBy ((==) `on` snd)
122+ . selectScores
123+ $ score opTree
124+ where
125+ addOverrides :: Map String Fixity -> Map String Fixity
126+ addOverrides m =
127+ M.fromList
128+ [ ("$", fixity 0 InfixR),
129+ (":", fixity 1 InfixR),
130+ (".", fixity 100 InfixL)
131+ ]
132+ `M.union` m
133+ fixity = Fixity NoSourceText
134+ score :: OpTree (Located ty) (Located op) -> [(String, Score)]
135+ score (OpNode _) = []
136+ score (OpBranch l o r) = fromMaybe (score r) $ do
137+ -- If we fail to get any of these, 'defaultFixity' will be used by
138+ -- 'reassociateOpTreeWith'.
139+ le <- srcSpanEndLine <$> unSrcSpan (opTreeLoc l) -- left end
140+ ob <- srcSpanStartLine <$> unSrcSpan (getLoc o) -- operator begin
141+ oe <- srcSpanEndLine <$> unSrcSpan (getLoc o) -- operator end
142+ rb <- srcSpanStartLine <$> unSrcSpan (opTreeLoc r) -- right begin
143+ oc <- srcSpanStartCol <$> unSrcSpan (getLoc o) -- operator column
144+ opName <- occNameString . rdrNameOcc <$> getOpName (unLoc o)
145+ let s
146+ | le < ob = AtBeginning oc
147+ | oe < rb = AtEnd
148+ | otherwise = InBetween
149+ return $ (opName, s) : score r
150+ selectScores :: [(String, Score)] -> [(String, Score)]
151+ selectScores =
152+ L.sortOn snd
153+ . mapMaybe
154+ ( \case
155+ [] -> Nothing
156+ xs@((n, _) : _) -> Just (n, selectScore $ map snd xs)
157+ )
158+ . L.groupBy ((==) `on` fst)
159+ . L.sort
160+ selectScore :: [Score] -> Score
161+ selectScore xs =
162+ case filter (/= InBetween) xs of
163+ [] -> InBetween
164+ xs' -> maximum xs'
165+
166+----------------------------------------------------------------------------
167+-- Helpers
168+
169+-- | Convert an 'OpTree' to with all operators having the same fixity and
170+-- associativity (left infix).
171+normalizeOpTree :: OpTree ty op -> OpTree ty op
172+normalizeOpTree (OpNode n) =
173+ OpNode n
174+normalizeOpTree (OpBranch (OpNode l) lop r) =
175+ OpBranch (OpNode l) lop (normalizeOpTree r)
176+normalizeOpTree (OpBranch (OpBranch l' lop' r') lop r) =
177+ normalizeOpTree (OpBranch l' lop' (OpBranch r' lop r))
src/Ormolu/Printer/SpanStream.hsnew file+46
@@ -0,0 +1,46 @@
1+{-# LANGUAGE DeriveDataTypeable #-}
2+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3+
4+-- | Build span stream from AST.
5+module Ormolu.Printer.SpanStream
6+ ( SpanStream (..),
7+ mkSpanStream,
8+ )
9+where
10+
11+import Data.DList (DList)
12+import qualified Data.DList as D
13+import Data.Data (Data)
14+import Data.Generics (everything, ext2Q)
15+import Data.List (sortOn)
16+import Data.Typeable (cast)
17+import SrcLoc
18+
19+-- | A stream of 'RealSrcSpan's in ascending order. This allows us to tell
20+-- e.g. whether there is another \"located\" element of AST between current
21+-- element and comment we're considering for printing.
22+newtype SpanStream = SpanStream [RealSrcSpan]
23+ deriving (Eq, Show, Data, Semigroup, Monoid)
24+
25+-- | Create 'SpanStream' from a data structure containing \"located\"
26+-- elements.
27+mkSpanStream ::
28+ Data a =>
29+ -- | Data structure to inspect (AST)
30+ a ->
31+ SpanStream
32+mkSpanStream a =
33+ SpanStream
34+ . sortOn realSrcSpanStart
35+ . D.toList
36+ $ everything mappend (const mempty `ext2Q` queryLocated) a
37+ where
38+ queryLocated ::
39+ (Data e0) =>
40+ GenLocated e0 e1 ->
41+ DList RealSrcSpan
42+ queryLocated (L mspn _) =
43+ case cast mspn :: Maybe SrcSpan of
44+ Nothing -> mempty
45+ Just (UnhelpfulSpan _) -> mempty
46+ Just (RealSrcSpan spn) -> D.singleton spn
src/Ormolu/Processing/Common.hsnew file+27
@@ -0,0 +1,27 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+-- | Common definitions for pre- and post- processing.
4+module Ormolu.Processing.Common
5+ ( OrmoluState (..),
6+ startDisabling,
7+ endDisabling,
8+ )
9+where
10+
11+import Data.String (IsString (..))
12+
13+-- | Ormolu state.
14+data OrmoluState
15+ = -- | Enabled
16+ OrmoluEnabled
17+ | -- | Disabled
18+ OrmoluDisabled
19+ deriving (Eq, Show)
20+
21+-- | Marker for the beginning of the region where Ormolu should be disabled.
22+startDisabling :: IsString s => s
23+startDisabling = "{- ORMOLU_DISABLE_START"
24+
25+-- | Marker for the end of the region where Ormolu should be disabled.
26+endDisabling :: IsString s => s
27+endDisabling = "ORMOLU_DISABLE_END -}"
src/Ormolu/Processing/Cpp.hsnew file+70
@@ -0,0 +1,70 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+-- | Support for CPP.
4+module Ormolu.Processing.Cpp
5+ ( State (..),
6+ processLine,
7+ unmaskLine,
8+ )
9+where
10+
11+import Control.Monad
12+import Data.Char (isSpace)
13+import qualified Data.List as L
14+import Data.Maybe (isJust)
15+import Data.String
16+import Data.Text (Text)
17+import qualified Data.Text as T
18+
19+-- | State of the CPP processor.
20+data State
21+ = -- | Outside of CPP directives
22+ Outside
23+ | -- | In a conditional expression
24+ InConditional
25+ | -- | In a continuation (after @\\@)
26+ InContinuation
27+ deriving (Eq, Show)
28+
29+-- | Automatically mask the line when needed and update the 'State'.
30+processLine :: String -> State -> (String, State)
31+processLine line state
32+ | for "define " = (masked, state')
33+ | for "include " = (masked, state')
34+ | for "undef " = (masked, state')
35+ | for "ifdef " = (masked, InConditional)
36+ | for "ifndef " = (masked, InConditional)
37+ | for "if " = (masked, InConditional)
38+ | for "else" = (masked, InConditional)
39+ | for "elif" = (masked, InConditional)
40+ | for "endif" = (masked, state')
41+ | otherwise =
42+ case state of
43+ Outside -> (line, Outside)
44+ InConditional -> (masked, InConditional)
45+ InContinuation -> (masked, state')
46+ where
47+ for directive = isJust $ do
48+ s <- dropWhile isSpace <$> L.stripPrefix "#" line
49+ void (L.stripPrefix directive s)
50+ masked = maskLine line
51+ state' =
52+ if "\\" `L.isSuffixOf` line
53+ then InContinuation
54+ else Outside
55+
56+-- | Mask the given line.
57+maskLine :: String -> String
58+maskLine x = maskPrefix ++ x
59+
60+-- | If the given line is masked, unmask it. Otherwise return the line
61+-- unchanged.
62+unmaskLine :: Text -> Text
63+unmaskLine x =
64+ case T.stripPrefix maskPrefix (T.stripStart x) of
65+ Nothing -> x
66+ Just x' -> x'
67+
68+-- | Mask prefix for CPP.
69+maskPrefix :: IsString s => s
70+maskPrefix = "-- ORMOLU_CPP_MASK"
src/Ormolu/Processing/Postprocess.hsnew file+31
@@ -0,0 +1,31 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE ViewPatterns #-}
3+
4+-- | Postprocessing for the results of printing.
5+module Ormolu.Processing.Postprocess
6+ ( postprocess,
7+ )
8+where
9+
10+import Data.Text (Text)
11+import qualified Data.Text as T
12+import Ormolu.Processing.Common
13+import qualified Ormolu.Processing.Cpp as Cpp
14+
15+-- | Postprocess output of the formatter.
16+postprocess ::
17+ -- | Desired indentation level
18+ Int ->
19+ -- | Input to process
20+ Text ->
21+ Text
22+postprocess indent =
23+ T.unlines
24+ . fmap indentLine
25+ . fmap Cpp.unmaskLine
26+ . filter (not . magicComment)
27+ . T.lines
28+ where
29+ magicComment (T.stripStart -> x) =
30+ x == startDisabling || x == endDisabling
31+ indentLine x = T.replicate indent " " <> x
src/Ormolu/Processing/Preprocess.hsnew file+149
@@ -0,0 +1,149 @@
1+{-# LANGUAGE BangPatterns #-}
2+{-# LANGUAGE LambdaCase #-}
3+{-# LANGUAGE RecordWildCards #-}
4+
5+-- | Preprocessing for input source code.
6+module Ormolu.Processing.Preprocess
7+ ( preprocess,
8+ )
9+where
10+
11+import Control.Monad
12+import Data.Char (isSpace)
13+import qualified Data.List as L
14+import Data.Maybe (isJust, maybeToList)
15+import FastString
16+import Ormolu.Config (RegionDeltas (..))
17+import Ormolu.Parser.Shebang (isShebang)
18+import Ormolu.Processing.Common
19+import qualified Ormolu.Processing.Cpp as Cpp
20+import SrcLoc
21+
22+-- | Transform given input possibly returning comments extracted from it.
23+-- This handles LINE pragmas, CPP, shebangs, and the magic comments for
24+-- enabling\/disabling of Ormolu.
25+preprocess ::
26+ -- | File name, just to use in the spans
27+ FilePath ->
28+ -- | Input to process
29+ String ->
30+ -- | Region deltas
31+ RegionDeltas ->
32+ -- | Literal prefix, pre-processed input, literal suffix, extra comments
33+ (String, String, String, [Located String])
34+preprocess path input RegionDeltas {..} =
35+ go 1 OrmoluEnabled Cpp.Outside id id regionLines
36+ where
37+ (prefixLines, otherLines) = splitAt regionPrefixLength (lines input)
38+ (regionLines, suffixLines) =
39+ let regionLength = length otherLines - regionSuffixLength
40+ in splitAt regionLength otherLines
41+ go !n ormoluState cppState inputSoFar csSoFar = \case
42+ [] ->
43+ let input' = unlines (inputSoFar [])
44+ in ( unlines prefixLines,
45+ case ormoluState of
46+ OrmoluEnabled -> input'
47+ OrmoluDisabled -> input' ++ endDisabling,
48+ unlines suffixLines,
49+ csSoFar []
50+ )
51+ (x : xs) ->
52+ let (x', ormoluState', cppState', cs) =
53+ processLine path n ormoluState cppState x
54+ in go
55+ (n + 1)
56+ ormoluState'
57+ cppState'
58+ (inputSoFar . (x' :))
59+ (csSoFar . (maybeToList cs ++))
60+ xs
61+
62+-- | Transform a given line possibly returning a comment extracted from it.
63+processLine ::
64+ -- | File name, just to use in the spans
65+ FilePath ->
66+ -- | Line number of this line
67+ Int ->
68+ -- | Whether Ormolu is currently enabled
69+ OrmoluState ->
70+ -- | CPP state
71+ Cpp.State ->
72+ -- | The actual line
73+ String ->
74+ -- | Adjusted line and possibly a comment extracted from it
75+ (String, OrmoluState, Cpp.State, Maybe (Located String))
76+processLine path n ormoluState Cpp.Outside line
77+ | "{-# LINE" `L.isPrefixOf` line =
78+ let (pragma, res) = getPragma line
79+ size = length pragma
80+ ss = mkSrcSpan (mkSrcLoc' 1) (mkSrcLoc' (size + 1))
81+ in (res, ormoluState, Cpp.Outside, Just (L ss pragma))
82+ | isOrmoluEnable line =
83+ case ormoluState of
84+ OrmoluEnabled ->
85+ (enableMarker, OrmoluEnabled, Cpp.Outside, Nothing)
86+ OrmoluDisabled ->
87+ (endDisabling ++ enableMarker, OrmoluEnabled, Cpp.Outside, Nothing)
88+ | isOrmoluDisable line =
89+ case ormoluState of
90+ OrmoluEnabled ->
91+ (disableMarker ++ startDisabling, OrmoluDisabled, Cpp.Outside, Nothing)
92+ OrmoluDisabled ->
93+ (disableMarker, OrmoluDisabled, Cpp.Outside, Nothing)
94+ | isShebang line =
95+ let ss = mkSrcSpan (mkSrcLoc' 1) (mkSrcLoc' (length line))
96+ in ("", ormoluState, Cpp.Outside, Just (L ss line))
97+ | otherwise =
98+ let (line', cppState') = Cpp.processLine line Cpp.Outside
99+ in (line', ormoluState, cppState', Nothing)
100+ where
101+ mkSrcLoc' = mkSrcLoc (mkFastString path) n
102+processLine _ _ ormoluState cppState line =
103+ let (line', cppState') = Cpp.processLine line cppState
104+ in (line', ormoluState, cppState', Nothing)
105+
106+-- | Take a line pragma and output its replacement (where line pragma is
107+-- replaced with spaces) and the contents of the pragma itself.
108+getPragma ::
109+ -- | Pragma line to analyze
110+ String ->
111+ -- | Contents of the pragma and its replacement line
112+ (String, String)
113+getPragma [] = error "Ormolu.Preprocess.getPragma: input must not be empty"
114+getPragma s@(x : xs)
115+ | "#-}" `L.isPrefixOf` s = ("#-}", " " ++ drop 3 s)
116+ | otherwise =
117+ let (prag, remline) = getPragma xs
118+ in (x : prag, ' ' : remline)
119+
120+-- | Canonical enable marker.
121+enableMarker :: String
122+enableMarker = "{- ORMOLU_ENABLE -}"
123+
124+-- | Canonical disable marker.
125+disableMarker :: String
126+disableMarker = "{- ORMOLU_DISABLE -}"
127+
128+-- | Return 'True' if the given string is an enabling marker.
129+isOrmoluEnable :: String -> Bool
130+isOrmoluEnable = magicComment "ORMOLU_ENABLE"
131+
132+-- | Return 'True' if the given string is a disabling marker.
133+isOrmoluDisable :: String -> Bool
134+isOrmoluDisable = magicComment "ORMOLU_DISABLE"
135+
136+-- | Construct a function for whitespace-insensitive matching of string.
137+magicComment ::
138+ -- | What to expect
139+ String ->
140+ -- | String to test
141+ String ->
142+ -- | Whether or not the two strings watch
143+ Bool
144+magicComment expected s0 = isJust $ do
145+ let trim = dropWhile isSpace
146+ s1 <- trim <$> L.stripPrefix "{-" (trim s0)
147+ s2 <- trim <$> L.stripPrefix expected s1
148+ s3 <- L.stripPrefix "-}" s2
149+ guard (all isSpace s3)
src/Ormolu/Utils.hsnew file+155
@@ -0,0 +1,155 @@
1+{-# LANGUAGE LambdaCase #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE ViewPatterns #-}
4+
5+-- | Random utilities used by the code.
6+module Ormolu.Utils
7+ ( RelativePos (..),
8+ attachRelativePos,
9+ combineSrcSpans',
10+ notImplemented,
11+ showOutputable,
12+ splitDocString,
13+ typeArgToType,
14+ unSrcSpan,
15+ incSpanLine,
16+ separatedByBlank,
17+ separatedByBlankNE,
18+ onTheSameLine,
19+ removeIndentation,
20+ )
21+where
22+
23+import Data.Char (isSpace)
24+import Data.List (dropWhileEnd)
25+import Data.List.NonEmpty (NonEmpty (..))
26+import qualified Data.List.NonEmpty as NE
27+import Data.Maybe (fromMaybe)
28+import Data.Text (Text)
29+import qualified Data.Text as T
30+import GHC
31+import GHC.DynFlags (baseDynFlags)
32+import qualified Outputable as GHC
33+
34+-- | Relative positions in a list.
35+data RelativePos
36+ = SinglePos
37+ | FirstPos
38+ | MiddlePos
39+ | LastPos
40+ deriving (Eq, Show)
41+
42+-- | Attach 'RelativePos'es to elements of a given list.
43+attachRelativePos :: [a] -> [(RelativePos, a)]
44+attachRelativePos = \case
45+ [] -> []
46+ [x] -> [(SinglePos, x)]
47+ (x : xs) -> (FirstPos, x) : markLast xs
48+ where
49+ markLast [] = []
50+ markLast [x] = [(LastPos, x)]
51+ markLast (x : xs) = (MiddlePos, x) : markLast xs
52+
53+-- | Combine all source spans from the given list.
54+combineSrcSpans' :: NonEmpty SrcSpan -> SrcSpan
55+combineSrcSpans' (x :| xs) = foldr combineSrcSpans x xs
56+
57+-- | Placeholder for things that are not yet implemented.
58+notImplemented :: String -> a
59+notImplemented msg = error $ "not implemented yet: " ++ msg
60+
61+-- | Pretty-print an 'GHC.Outputable' thing.
62+showOutputable :: GHC.Outputable o => o -> String
63+showOutputable = GHC.showSDoc baseDynFlags . GHC.ppr
64+
65+-- | Split and normalize a doc string. The result is a list of lines that
66+-- make up the comment.
67+splitDocString :: HsDocString -> [Text]
68+splitDocString docStr =
69+ case r of
70+ [] -> [""]
71+ _ -> r
72+ where
73+ r =
74+ fmap escapeLeadingDollar
75+ . dropPaddingSpace
76+ . dropWhileEnd T.null
77+ . fmap (T.stripEnd . T.pack)
78+ . lines
79+ $ unpackHDS docStr
80+ -- We cannot have the first character to be a dollar because in that
81+ -- case it'll be a parse error (apparently collides with named docs
82+ -- syntax @-- $name@ somehow).
83+ escapeLeadingDollar txt =
84+ case T.uncons txt of
85+ Just ('$', _) -> T.cons '\\' txt
86+ _ -> txt
87+ dropPaddingSpace xs =
88+ case dropWhile T.null xs of
89+ [] -> []
90+ (x : _) ->
91+ let leadingSpace txt = case T.uncons txt of
92+ Just (' ', _) -> True
93+ _ -> False
94+ dropSpace txt =
95+ if leadingSpace txt
96+ then T.drop 1 txt
97+ else txt
98+ in if leadingSpace x
99+ then dropSpace <$> xs
100+ else xs
101+
102+-- | Get 'LHsType' out of 'LHsTypeArg'.
103+typeArgToType :: LHsTypeArg p -> LHsType p
104+typeArgToType = \case
105+ HsValArg tm -> tm
106+ HsTypeArg _ ty -> ty
107+ HsArgPar _ -> notImplemented "HsArgPar"
108+
109+-- | Get 'RealSrcSpan' out of 'SrcSpan' if the span is “helpful”.
110+unSrcSpan :: SrcSpan -> Maybe RealSrcSpan
111+unSrcSpan = \case
112+ RealSrcSpan r -> Just r
113+ UnhelpfulSpan _ -> Nothing
114+
115+-- | Increment line number in a 'SrcSpan'.
116+incSpanLine :: Int -> SrcSpan -> SrcSpan
117+incSpanLine i = \case
118+ RealSrcSpan s ->
119+ let start = realSrcSpanStart s
120+ end = realSrcSpanEnd s
121+ incLine x =
122+ let file = srcLocFile x
123+ line = srcLocLine x
124+ col = srcLocCol x
125+ in mkRealSrcLoc file (line + i) col
126+ in RealSrcSpan (mkRealSrcSpan (incLine start) (incLine end))
127+ UnhelpfulSpan x -> UnhelpfulSpan x
128+
129+-- | Do two declarations have a blank between them?
130+separatedByBlank :: (a -> SrcSpan) -> a -> a -> Bool
131+separatedByBlank loc a b =
132+ fromMaybe False $ do
133+ endA <- srcSpanEndLine <$> unSrcSpan (loc a)
134+ startB <- srcSpanStartLine <$> unSrcSpan (loc b)
135+ pure (startB - endA >= 2)
136+
137+-- | Do two declaration groups have a blank between them?
138+separatedByBlankNE :: (a -> SrcSpan) -> NonEmpty a -> NonEmpty a -> Bool
139+separatedByBlankNE loc a b = separatedByBlank loc (NE.last a) (NE.head b)
140+
141+-- | Return 'True' if one span ends on the same line the second one starts.
142+onTheSameLine :: SrcSpan -> SrcSpan -> Bool
143+onTheSameLine a b =
144+ isOneLineSpan (mkSrcSpan (srcSpanEnd a) (srcSpanStart b))
145+
146+-- | Remove indentation from a given 'String'. Return the input with
147+-- indentation removed and the detected indentation level.
148+removeIndentation :: String -> (String, Int)
149+removeIndentation (lines -> xs) = (unlines (drop n <$> xs), n)
150+ where
151+ n = minimum (getIndent <$> xs)
152+ getIndent y =
153+ if all isSpace y
154+ then 0
155+ else length (takeWhile isSpace y)
tests/Ormolu/Parser/PragmaSpec.hsnew file+26
@@ -0,0 +1,26 @@
1+module Ormolu.Parser.PragmaSpec (spec) where
2+
3+import Ormolu.Parser.Pragma
4+import Test.Hspec
5+
6+spec :: Spec
7+spec =
8+ describe "parsePragma" $ do
9+ stdTest "{-# LANGUAGE Foo #-}" (Just (PragmaLanguage ["Foo"]))
10+ stdTest "{-# language Foo #-}" (Just (PragmaLanguage ["Foo"]))
11+ stdTest "{-#LANGUAGE Foo#-}" (Just (PragmaLanguage ["Foo"]))
12+ stdTest "{-# LANGUAGE Foo#-}" (Just (PragmaLanguage ["Foo"]))
13+ stdTest "{-#language Foo#-}" (Just (PragmaLanguage ["Foo"]))
14+ stdTest "{-# lAngUAGe Foo #-}" (Just (PragmaLanguage ["Foo"]))
15+ stdTest "{-# LANGUAGE Foo, Bar #-}" (Just (PragmaLanguage ["Foo", "Bar"]))
16+ stdTest "{-# LANGUAGE Foo Bar #-}" Nothing
17+ stdTest "{-# BOO Foo #-}" Nothing
18+ stdTest "something" Nothing
19+ stdTest "{-# LANGUAGE foo, Bar #-}" Nothing
20+ stdTest "{-# OPTIONS_GHC foo bar baz #-}" (Just $ PragmaOptionsGHC "foo bar baz")
21+ stdTest "{-#OPTIONS_HADDOCK foo, bar, baz #-}" (Just $ PragmaOptionsHaddock "foo, bar, baz")
22+
23+stdTest :: String -> Maybe Pragma -> Spec
24+stdTest input result =
25+ it input $
26+ parsePragma input `shouldBe` result
tests/Ormolu/Printer/CombinatorsSpec.hsdeleted−110
@@ -1,110 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−
3−module Ormolu.Printer.CombinatorsSpec (spec) where
4−
5−import Ormolu.Printer.Combinators
6−import Ormolu.Printer.Internal
7−import Test.Hspec
8−import qualified Data.Map.Strict as M
9−import qualified Data.Text.IO as T
10−
11−-- NOTE Testing combinators in separation is easy, but it's not very useful
12−-- either because interesting things happen only when combinators are used
13−-- together. However, there are too many combinations to test, so we test
14−-- just a few things here and expect new tests to be added on demand when
15−-- particularly tricky or problematic use cases are discovered.
16−--
17−-- The printing logic is indirectly tested in the main bulk of reformatting
18−-- tests.
19−
20−spec :: Spec
21−spec = do
22− stdTest "simple signature" rSimpleSig "ssig"
23− stdTest "list" rList0 "list0"
24− stdTest "list with annotated name in it" rList1 "list1"
25− stdTest "module header" rModuleHeader "mhdr"
26−
27−-- | Do a standard test prodedure testing both single-line and multi-line
28−-- layouts.
29−
30−stdTest
31− :: String -- ^ Test name
32− -> R () -- ^ Computation to test
33− -> FilePath -- ^ Base file name where expected result is stored
34− -> Spec
35−stdTest name m path = describe name $ do
36− let spath = "data/printer/" ++ path ++ "-single.hs"
37− mpath = "data/printer/" ++ path ++ "-multi.hs"
38− it "single-line works" $
39− singleLine m `shouldRender` spath
40− it "multi-line works" $
41− multiLine m `shouldRender` mpath
42−
43−----------------------------------------------------------------------------
44−-- Test computations
45−
46−rSimpleSig :: R ()
47−rSimpleSig = line rFn
48−
49−rList0 :: R ()
50−rList0 = line . brackets $
51− velt
52− [ txt "foo"
53− , comma >> txt "bar"
54− , comma >> txt "baz"
55− ]
56−
57−rList1 :: R ()
58−rList1 = line . brackets $
59− velt
60− [ txt "foo"
61− , comma >> txt "bar"
62− , comma >> rFn
63− ]
64−
65−rFn :: R ()
66−rFn = velt'
67− [ txt "foo"
68− , inci $ velt'
69− [ do txt ":: "
70− parens $ velt'
71− [ txt "Int"
72− , txt "-> " >> txt "Int"
73− ]
74− , txt "-> " >> txt "Bool"
75− ]
76− ]
77−
78−rModuleHeader :: R ()
79−rModuleHeader = do
80− line $ do
81− txt "module "
82− txt "MyModule"
83− line . inci . parens . velt $
84− [ txt "R"
85− , comma >> txt "runR"
86− , comma >> txt "txt"
87− , comma >> txt "blah"
88− ]
89− line (txt "where")
90−
91−----------------------------------------------------------------------------
92−-- Helpers
93−
94−-- | Run given computation in @'R' ()@ monad and compare result of rendering
95−-- with contents of a given file.
96−
97−shouldRender :: R () -> FilePath -> Expectation
98−shouldRender m path = do
99− expected <- T.readFile path
100− runR False m M.empty `shouldBe` expected
101−
102−-- | Render using single-line layout.
103−
104−singleLine :: R () -> R ()
105−singleLine = enterLayout SingleLine
106−
107−-- | Render using multi-line layout.
108−
109−multiLine :: R () -> R ()
110−multiLine = enterLayout MultiLine
tests/Ormolu/PrinterSpec.hs+51−36
@@ -2,17 +2,18 @@
2
2
3module Ormolu.PrinterSpec (spec) where
3module Ormolu.PrinterSpec (spec) where
4
4
5+import Control.Exception
5import Control.Monad
6import Control.Monad
6import Control.Monad.IO.Class
7import Control.Monad.IO.Class
7import Data.List (isSuffixOf)
8import Data.List (isSuffixOf)
8import Data.Text (Text)
9import Data.Text (Text)
10+import qualified Data.Text as T
11+import qualified Data.Text.IO as T
9import Ormolu
12import Ormolu
10import Path
13import Path
11import Path.IO
14import Path.IO
12−import System.FilePath (addExtension, dropExtensions, splitExtensions)
15+import qualified System.FilePath as F
13import Test.Hspec
16import Test.Hspec
14−import qualified Data.Text as T
15−import qualified Data.Text.IO as T
16
17
17spec :: Spec
18spec :: Spec
18spec = do
19spec = do
@@ -20,57 +21,71 @@ spec = do
20 forM_ es checkExample
21 forM_ es checkExample
21
22
22-- | Check a single given example.
23-- | Check a single given example.
23−
24checkExample :: Path Rel File -> Spec
24checkExample :: Path Rel File -> Spec
25−checkExample srcPath' = it (fromRelFile srcPath' ++ " works") $ do
25+checkExample srcPath' = it (fromRelFile srcPath' ++ " works") . withNiceExceptions $ do
26− let srcPath = examplesDir </> srcPath'
26+ let srcPath = examplesDir </> srcPath'
27− expectedOutputPath <- deriveOutput srcPath
27+ expectedOutputPath <- deriveOutput srcPath
28− -- 1. Given input snippet of source code parse it and pretty print it.
28+ -- 1. Given input snippet of source code parse it and pretty print it.
29− -- 2. Parse the result of pretty-printing again and make sure that AST
29+ -- 2. Parse the result of pretty-printing again and make sure that AST
30− -- is the same as AST of the original snippet. (This happens in
30+ -- is the same as AST of the original snippet. (This happens in
31− -- 'ormoluFile' automatically.)
31+ -- 'ormoluFile' automatically.)
32− formatted0 <- ormoluFile defaultConfig (fromRelFile srcPath)
32+ formatted0 <- ormoluFile defaultConfig (fromRelFile srcPath)
33− -- 3. Check the output against expected output. Thus all tests should
33+ -- 3. Check the output against expected output. Thus all tests should
34− -- include two files: input and expected output.
34+ -- include two files: input and expected output.
35+ -- T.writeFile (fromRelFile expectedOutputPath) formatted0
35− expected <- (liftIO . T.readFile . fromRelFile) expectedOutputPath
36+ expected <- (liftIO . T.readFile . fromRelFile) expectedOutputPath
36− formatted0 `shouldMatch` expected
37+ shouldMatch False formatted0 expected
37− -- 4. Check that running the formatter on the output produces the same
38+ -- 4. Check that running the formatter on the output produces the same
38− -- output again (the transformation is idempotent).
39+ -- output again (the transformation is idempotent).
39− formatted1 <- ormolu defaultConfig "<formatted>" (T.unpack formatted0)
40+ formatted1 <- ormolu defaultConfig "<formatted>" (T.unpack formatted0)
40− formatted1 `shouldMatch` formatted0
41+ shouldMatch True formatted1 formatted0
41
42
42-- | Build list of examples for testing.
43-- | Build list of examples for testing.
43−
44locateExamples :: IO [Path Rel File]
44locateExamples :: IO [Path Rel File]
45locateExamples =
45locateExamples =
46 filter isInput . snd <$> listDirRecurRel examplesDir
46 filter isInput . snd <$> listDirRecurRel examplesDir
47
47
48-- | Does given path look like input path (as opposed to expected output
48-- | Does given path look like input path (as opposed to expected output
49-- path)?
49-- path)?
50−
51isInput :: Path Rel File -> Bool
50isInput :: Path Rel File -> Bool
52isInput path =
51isInput path =
53 let s = fromRelFile path
52 let s = fromRelFile path
54− (s', exts) = splitExtensions s
53+ (s', exts) = F.splitExtensions s
55− in exts == ".hs" && not ("-out" `isSuffixOf` s')
54+ in exts == ".hs" && not ("-out" `isSuffixOf` s')
56
55
57-- | For given path of input file return expected name of output.
56-- | For given path of input file return expected name of output.
58−
59deriveOutput :: Path Rel File -> IO (Path Rel File)
57deriveOutput :: Path Rel File -> IO (Path Rel File)
60−deriveOutput path = parseRelFile $
58+deriveOutput path =
59+ parseRelFile $
61− addExtension (dropExtensions (fromRelFile path) ++ "-out") "hs"
60+ F.addExtension (F.dropExtensions (fromRelFile path) ++ "-out") "hs"
62
61
63-- | A version of 'shouldBe' that is specialized to comparing 'Text' values.
62-- | A version of 'shouldBe' that is specialized to comparing 'Text' values.
64-- It also prints multi-line snippets in a more readable form.
63-- It also prints multi-line snippets in a more readable form.
65−
66−shouldMatch :: Text -> Text -> Expectation
64+shouldMatch :: Bool -> Text -> Text -> Expectation
67−shouldMatch actual expected =
65+shouldMatch idempotenceTest actual expected =
68− when (actual /= expected) . expectationFailure $ unlines
66+ when (actual /= expected) . expectationFailure $
67+ unlines
69− [ "expected:"
68+ [ ">>>>>>>>>>>>>>>>>>>>>> expected (" ++ pass ++ "):",
70− , T.unpack expected
69+ T.unpack expected,
71− , "but got:"
70+ ">>>>>>>>>>>>>>>>>>>>>> but got:",
72− , T.unpack actual
71+ T.unpack actual
73− ]
72+ ]
73+ where
74+ pass =
75+ if idempotenceTest
76+ then "idempotence pass"
77+ else "first pass"
74
78
75examplesDir :: Path Rel Dir
79examplesDir :: Path Rel Dir
76examplesDir = $(mkRelDir "data/examples")
80examplesDir = $(mkRelDir "data/examples")
81+
82+-- | Inside this wrapper 'OrmoluException' will be caught and displayed
83+-- nicely using 'displayException'.
84+withNiceExceptions ::
85+ -- | Action that may throw the exception
86+ Expectation ->
87+ Expectation
88+withNiceExceptions m = m `catch` h
89+ where
90+ h :: OrmoluException -> IO ()
91+ h = expectationFailure . displayException