Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: print minimal amount of round brackets in sniper mode #3823

Conversation

slarse
Copy link
Collaborator

@slarse slarse commented Mar 4, 2021

Fix #3809

Related to #3811

This PR provides functionality in the default pretty-printer for printing only parentheses that are strictly necessary to preserve the syntactical structure of the AST in nested operators. Do note that this applies only to nesting of operators that are actually modeled as operators in Spoon (i.e. CtUnaryOperator and CtBinaryOperator). Redundant parentheses will therefore still be printed around e.g. casts, fixing that is a TODO!

As a brief example, all of the following expressions are printed exactly as given when parsed and re-printed:

1 + 2 + 3
1 + (2 + 3)
1 + 2 + -3
1 + 2 + -(2 + 3)
"Sum: " + (1 + 2)
"Sum: " + 1 + 2
-(1 + 2 + 3)
true || true && false
(true || false) && false
1 | 2 | 3
1 | (2 | 3)
1 | 2 & 3
(1 | 2) & 3
1 | 2 ^ 3
(1 | 2) ^ 3

Note that e.g. 1 + (2 + 3) is re-printed as 1 + (2 + 3). Even though 1 + 2 + 3 is semantically equivalent and requires fewer parentheses, it provides a different AST (see more elaborate description in #3809).

This functionality is currently disabled by default, and can be activated only with the package-private method DefaultJavaPrettyPrinter::setOptimizeParentheses(bool). In other words, this is strictly internal at the moment and can't be activated by clients.

I tried running with the entire test suite with parenthesis optimization enabled, and only 7 tests fail, all due to having redundant parentheses in the assertions. In terms of only the Spoon test suite, it therefore seems feasible to enable this feature right away, and the Jenkins tests should be pretty swift in telling us that something has gone wrong.

@jrfaller Any thoughts on the approach taken here? This is pretty much a straight implementation of the idea I laid out in #3809

@monperrus Would you like me to go for enabling this feature by default, or should we keep it internal/semi-internal for the time being? To be clear, my intention here is that minimizing the amount of printed parentheses should be the way DJPP works, it shouldn't be configurable. Given the binary choice of on or off, I can't imagine anyone would choose to turn parenthesis minimization off, and so it seems reasonable to me to omit such configuration entirely.

Comment on lines +57 to +62
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.7.1</version>
<scope>test</scope>
</dependency>
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This dependency is necessary for using the @ParameterizedTest annotation.

@slarse slarse changed the title wip: feat: Print minimal brackets for nested operators wip: feat: Print minimal amount of parenthesis for nested operators Mar 4, 2021
@jrfaller
Copy link

jrfaller commented Mar 5, 2021

Hi @slarse! It seems neat! I don't see in the diff when this method is triggered but I believe this will only be applied to transformed nodes, to keep the unmodified code with its original parentheses?

@slarse
Copy link
Collaborator Author

slarse commented Mar 5, 2021

Hi @slarse! It seems neat! I don't see in the diff when this method is triggered but I believe this will only be applied to transformed nodes, to keep the unmodified code with its original parentheses?

In terms of sniper printing, yes. This patch applies to the default printer (DJPP = DefaultJavaPrettyPrinter), which has its own printing style, and is what we must use when we can't sniper print for some reason (modified node, new node, etc), or when we just don't want to sniper print.

In terms of the current state of affairs, it will also improve the sniper printing itself in some cases, as there will be far fewer parentheses to try to match to actual parentheses that exist in the source code. Parentheses should now never appear out of thin air, as has previously been a problem both in default printing and sniper printing. It will be less beneficial for sniper printing if we manage to implement our ideas in #3794, but it'll still be useful when we need to print new or changed expressions.

@jrfaller
Copy link

jrfaller commented Mar 5, 2021

Thanks for the explanation! Therefore LGTM!

@slarse slarse changed the title wip: feat: Print minimal amount of parenthesis for nested operators wip: feat: Print minimal amount of parentheses for nested operators Mar 8, 2021
@slarse slarse changed the title wip: feat: Print minimal amount of parentheses for nested operators review: feat: Print minimal amount of parentheses for nested operators Mar 8, 2021
@slarse
Copy link
Collaborator Author

slarse commented Mar 8, 2021

@monperrus This is ready for your consideration. Here are a a couple of thoughts I have:

  • The word "brackets" is used internally in the printers. I think "parentheses" is more precise, as brackets more often refer to square brackets [], while I've never heard parentheses refer to anything but (). Thoughts?
  • Currently, the parenthesis optimization is enabled by default for the sniper printer, but not for the default printer. There is no way to use the public API to enable it, as I didn't want to introduce more clutter to the DJPP API. Keep this way, or enable for DJPP, or make it possible to enable through DJPP API?
  • I'm not sure "optimization" is the best word to use here, it's a bit vague. Minimization? Redundancy elimination?

@monperrus
Copy link
Collaborator

Thanks a lot @slarse

The word "brackets" is used internally in the printers. I think "parentheses" is more precise, as brackets more often refer to square brackets [], while I've never heard parentheses refer to anything but (). Thoughts?

Both are valid AFAIK, but it's good to be consistent. All comment and name changes outside the public API are welcome!

Currently, the parenthesis optimization is enabled by default for the sniper printer, but not for the default printer.

This is good this way.

I'm not sure "optimization" is the best word to use here, it's a bit vague. Minimization? Redundancy elimination?

I like "Minimization" (optimization is either minimization or maximization)

Overall, excellent PR, and we love parametrized tests! Will merge.

@slarse
Copy link
Collaborator Author

slarse commented Mar 9, 2021

Thanks a lot @slarse

Both are valid AFAIK, but it's good to be consistent. All comment and name changes outside the public API are welcome!

Yes, both are valid: "bracket" is British and "parenthesis" is American English. The problem I find in Spoon is that the word "bracket" is used for everything (square bracket, round bracket, curly bracket are all just denoted bracket). This is a bit confusing to me when reading the code. This is all internal, though, I couldn't find a single mention in the public API.

However, I think that this PR is not the one to change widespread terminology use in Spoon. I'll use the term "round bracket".

Currently, the parenthesis optimization is enabled by default for the sniper printer, but not for the default printer.

This is good this way.

Right, so just to be clear here, it also can't be enabled for the default printer via the public API as the setter is protected. That's intentional, I think it's good we keep this internal until it's been field tested a bit in the Sniper.

I like "Minimization" (optimization is either minimization or maximization)

That is true. I'll migrate over to use "minimization".

@slarse slarse changed the title review: feat: Print minimal amount of parentheses for nested operators review: feat: Print minimal amount of round brackets for nested operators Mar 9, 2021
@slarse
Copy link
Collaborator Author

slarse commented Mar 9, 2021

On the note of reproducing formatting under AST transformations, a6a43e9 and 73338f7 show that IntelliJ isn't perfect either ...

@monperrus monperrus changed the title review: feat: Print minimal amount of round brackets for nested operators feat: print minimal amount of round brackets in sniper mode Mar 10, 2021
@monperrus monperrus merged commit 7fa0071 into INRIA:master Mar 10, 2021
@monperrus
Copy link
Collaborator

Thanks a lot @slarse . This is a very important contribution for the sniper mode.

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.

extraneous parentheses at pretty-printing
3 participants