This change modifies the ‘HsApp’ printer to handle all function parameters
at once instead of following the AST order.
This allows us to consistently put each function argument on separate lines.
Previously, when printing the function f a b c, the AST would look like (((f
a) b) c), which would cause inconsistencies regarding to newlines (imagine f
a\n b).
Otherwise I tried to preserve the same behaviour as the previous printer,
and added a few tests.
This only changes the ‘p_hsExpr’ function, rest of the changes are caused by
the formatting change.
The commit changes how type signatures are printed. The new style looks like
this:
foo ::
Int ->
Char ->
String
This works better with foralls and other features of the type system that
will be added in the near future, like linear arrows.
In order to print Haddocks nicely (this seems to be the only acceptable
placement):
foo ::
-- | First argument
Int ->
-- | Second argument
Char ->
-- | Result
String
It is often necessary to re-arrange them completely and use the “pipe style”
instead of “caret style”. It proved to be a very hard task with our older
comment-handling system, if not impossible.
Here we start parsing Haddocks so that they are treated as components of AST
and we now render them as part of rendering of those components. The
existing framework for handling comments only prints non-Haddock comments
now.
The change caused a fair number of new problems and failures which I added
new tests for.
Haskell strings can have "gaps", where any amount of whitespace between
two backslashes are ignored. This allows writing multi-line strings. As
an example, all strings below are the same:
```
"foobar"
"foo\ \bar"
"foo\
\bar"
```
When parsing a string literal, lexer usually produces two fields, one
of them is the actual string user wrote as a 'SourceText', the other one
is the sanitized version where gaps and other special characters removed.
While printing the string, GHC's Outputable instance uses the 'SourceText'
field, however since that text contains gaps as-is, we can not change
the original indentation. In order to fix this, this commit splits the
strings by the gaps and print each line separately applying the layout
rules.
Also, it applies the same logic to type-level strings.
I implemented a custom logic where we assign a score to every occurance of
an operator based on their location, and the average of that score determine
the fixity of the operator.
As you can imagine, the solution is a bit brittle; and it is easy to mislead
it if you knowingly craft an input, but it gave acceptable results for every
code snippet I found online. And since it returns the same AST no matter how
we infer the fixities, it is not the end of the world if we infer something
incorrectly.
The code is not really optimised, and I think it has quadratic time
complexity. Notably, we use opTreeLoc function quite often and it traverses
the whole tree every time. Memoizing that on the OpBranch constructor would
make formatting files with reeeally long operator chains a lot faster. We
can do this once we decide to optimize for speed.
Here is an example which fails to parse with bang patterns but succeeds
otherwise:
(!) :: Foo -> Int -> Int
(Foo n) ! p = n + p
To run Ormolu on this we must not enable bang patterns by default.
This removes (or rather puts it to a lower level) logic around “modifying
newline” because it was very hard to reason about and almost blocked my work
on fixing issue #337.
I also dropped debugging output because it's too verbose and I'm not using
it anyway.
As part of these changes I also changed now the ‘newline’ combinator works.
Now, similar to ‘space’, the second ‘newline’ in a row just tells the
rendering engine to prefix next thing with a newline, using the ‘newline’
combinator more than twice in a row has no effect.
To take full advantage of the new feature I also went through the code and
simplified some logic around outputting exact amount of newlines because now
it's harder to get things wrong, so we can be less careful with counting
newlines.
Turns out when ‘--unsafe’ is not set, exceptions thrown in formatting code
are caught in the subsequent parsing check, which wraps them as GHC errors
adding a text like:
Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug
Which is misleading since the error is not caused by GHC.
This PR avoids it by strictly binding the result of ‘printModule’.