Reduce parenthesis prevalence - #183
Draft
glelouet wants to merge 2 commits into
Draft
Conversation
JOp has enum Precedence. First one has higher priority. IGenerable defaults to TOKEN precedence. unary, binary, ternary operator have that value replaced with the one of their operator. Cast, array comp redefine that value with their own precedence. FormatterSetting has option for parentheses.operator : - ALWAYS to add all the parenthesis we can - NONTOKEN to only skip token parts - REQUIRED to only parenthesis around element with lower precedence Previously mentioned elements use that value to add () when needed. This is formatting, yet some behavior should be the same in the end whatever formatting we choose : there are test classes to obv. showcase and track the changes, but also actually test the behavior.
Collaborator
Author
|
I think it's minor because it removes a few internal things, and add a few public things |
Collaborator
Author
|
What is needed now is more tests, to be sure there is no case where an expression does not receive parenthesis that leads to semantic change. Then maybe change the settings to specify not on operators as it is now in the options, but on binaryoperators, unaryoperators, caseoperator, etc. I don't want to have the spec of the settings vague or unpolished. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Objective
The goal of this PR is to allow expressions to have surrounding parenthesis only when required.
For example in
return Math.sqrt(((x*x)+(y*y)));(this is an example from actually generated code) there are two couples or parenthesis that can be removed to makereturn Math.sqrt(x*x + y*y);instead (this is the actual result of this PR)For this, we need to know when an operator needs be parenthesized. This is the case, when applying an operator to the left or right of an expression could have priority over the top-level operator of that expression.
For example, applying a multiplication on top of an addition can change that addition :
a * b + cis nota * ( b + c ). This happens when the operator applied to an expression (here , ×) has higher precedence than the root operator in that expression (here, +).To represent this, I added an enum for operator precedence, and the IGenerable class has a new operatorPrecedence method that returns this enum.
How this new value is used, depends on the operators applied. For example, the arraycomponent
[ ]operator does not interact with its index expression : it only applies to its array expression . For example, if it is a cast like((int []) myObject)[42], since(int []) myObject[42]would apply the cast to the result oft the array component (higher prevalence of[]against cast).But more generally, this means IJExpression generation does not parenthesis itself anymore : the parenthesis are managed at the upper level.
That option is applied by default, but can be changed in the formatter settings.
Internal changes
As written, new enum for precedence.
The unary, binary, and ternary operators have been changed to have this information : they each have their own enum class, that contains the string representation (eg "==" for equality operator) and the precedence. This is because it's easier to have each operator hardcoded in an enum, to change later.
The unary also has the prefix of the operator, thus the "JOpUnaryTight" is not needed anymore.
The default precedence for a IGenerable is the highest, so TOKEN, as most are not operators :
myField.get()[1]does not need additional parenthesis. same fora=b;The addition of the parenthesis can still be forced with new formatter settings. There are three modes : add parenthesis only when required (default), always, or always except on token precedence. The last one is because token is max precedence, so there is no need to parenthesis an expression with max precedence.
Talking about those, a new example module is dedicated to generating the formatter default settings, both in yaml and json. This automatically rewrites the default settings in a root file. It is not in generated/ or resources/ folder because it's not supposed to be used by anything, it's just a documentation.
Since such a heavy change can easily break, some tests are present to check that the resulting behavior of a code generated using several precedence mixes produces the correct behavior.
Already existing test cases were updated to match the new values. Generated classes (in the plugin examples, or for other tests) were also changed as a result of this PR, showing what actually changed.
Commit
JOp has added enum Precedence. First one has higher priority.
IGenerable defaults to TOKEN precedence, because most IGenerable are not operators (higher precedence).
unary, binary, ternary operator have that value replaced with the one of their operator(s).
Cast, array comp redefine that value with their own precedence.
FormatterSetting has option for parentheses.operator :
Previously mentioned elements use that value to add () when needed.
This is formatting, yet some behavior should be the same in the end whatever formatting we choose : there are test classes to obv. showcase and track the changes, but also actually test the behavior.