Skip to content

feat: allow opt-out of grouping in formatter#867

Merged
Kha merged 23 commits intoleanprover:masterfrom
gebner:allowungrouped
Dec 15, 2021
Merged

feat: allow opt-out of grouping in formatter#867
Kha merged 23 commits intoleanprover:masterfrom
gebner:allowungrouped

Conversation

@gebner
Copy link
Copy Markdown
Member

@gebner gebner commented Dec 11, 2021

Currently, the pretty-printer formats tactics proofs like this:

theorem foo : True → True :=
  by
    intro
    trivial

The main goal of this PR is to format theorems as follows (which is important for mathport because we use the formatter to generate the Lean 4 source code):

theorem foo : True → True := by
  intro
  trivial

The reason why the by is indented at the moment is that the formatter for category parsers automatically inserts fill+nest nodes around the produced format object (confusingly, this is called a group in the formatter).

We add a new no-op parser combinator called ppAllowUngrouped that instructs the category pretty-printer to omit this fill+nest operation, and add this combinator to by/do/fun. This causes theorems with tactics proofs to be printed in the desired way

-- Omit group (i.e., fill+nest) in the enclosing category parser:
syntax ppAllowUngrouped "do " tacticSeq : term

There are also two new pretty-printing combinators which can do different things depending on whether the following parser was ungrouped or not. ppDedentIfGrouped undos the nest step (but keeps the fill) if the parser is grouped (used in parentheses), and ppHardLineUnlessUngrouped prints a hard newline if the parser is grouped, and a soft newline otherwise (used in declarations after :=).

I have prepared a branch where all Lean source files have been reformatted with these changes: https://github.com/leanprover/lean4/compare/master...gebner:formatted?diff=split There is of course still lots of low-hanging fruit left (and some more serious bugs).

There are several changes in this PR, I can split it up if desired:

  1. I have added a small script that reformats lean files ("feat: add script to reformat lean files"). In contrast to the Reformat.lean file in the tests directory, this also works if the lean file defines notation and hence requires elaboration.
  2. There was a bug in the pushToken function in the formatter which printed extra spaces, for example two spaces after have and very often trailing spaces ("fix: suppress extra spaces in formatter").
  3. The main change adding ppAllowUngrouped ("feat: allow opt-out of grouping in formatter")
  4. The rest is minor changes (such as adding spaces to notations, etc.), which was helpful to clean up the reformatted output and make it easier to see if the ungrouping change had unintended side effects.


abbrev Function.comp {α : Sort u} {β : Sort v} {δ : Sort w} (f : β → δ) (g : α → β) : α → δ :=
fun x => f (g x)
abbrev Function.comp {α : Sort u} {β : Sort v} {δ : Sort w} (f : β → δ) (g : α → β) : α → δ := fun x => f (g x)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that fun but not other terms can now be used in a single line is an interesting consequence... I think we should really introduce ppLineUnlessUngrouped and use it instead of ppHardline... but that doesn't have to be in this PR

Comment on lines +58 to +61
do
discard (pure 2)
let y : Nat := 3
pure (x + y))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we care about this one? Arguably the indent of do was wrong to begin with.

IO.println x
IO.println "even" else do
IO.println x
IO.println "odd"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...oh, except for the elses? :)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I've pushed a changed that puts newlines after then and before/after else (by exposing Format.group as a pretty-printing combinator, which requires a stage0 update).

There's still the structure instance issue, where the formatter produces { a := 42 b:= 1 }. I've tried replacing optional ", " by ", " <|> (ppLine >> group skip). This produces parseable syntax, but formats every structure instance in multi-line format... Ideally we'd define structure instances in terms of sepBy ", " structInstField (", " <|> (checkColGe >> ppLine)) (so that the final ppLine is omitted), but that requires big changes in the structure instance elaborator (with the accompanying bootstrapping problems).

@Kha Kha merged commit 230d6d2 into leanprover:master Dec 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants