]>
crepu.dev Git - config.git/blob - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/yapf/pytree/split_penalty.py
1 # Copyright 2015 Google Inc. All Rights Reserved.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 """Computation of split penalties before/between tokens."""
18 from yapf_third_party
._ylib
2to
3 import pytree
19 from yapf_third_party
._ylib
2to
3.pgen2
import token
as grammar_token
21 from yapf
.pytree
import pytree_utils
22 from yapf
.pytree
import pytree_visitor
23 from yapf
.yapflib
import style
24 from yapf
.yapflib
import subtypes
26 # TODO(morbo): Document the annotations in a centralized place. E.g., the
28 UNBREAKABLE
= 1000 * 1000
31 VERY_STRONGLY_CONNECTED
= 3500
32 STRONGLY_CONNECTED
= 3000
50 ONE_ELEMENT_ARGUMENT
= 500
54 def ComputeSplitPenalties(tree
):
55 """Compute split penalties on tokens in the given parse tree.
58 tree: the top-level pytree node to annotate with penalties.
60 _SplitPenaltyAssigner().Visit(tree
)
63 class _SplitPenaltyAssigner(pytree_visitor
.PyTreeVisitor
):
64 """Assigns split penalties to tokens, based on parse tree structure.
66 Split penalties are attached as annotations to tokens.
69 def Visit(self
, node
):
70 if not hasattr(node
, 'is_pseudo'): # Ignore pseudo tokens.
71 super(_SplitPenaltyAssigner
, self
).Visit(node
)
73 def Visit_import_as_names(self
, node
): # pyline: disable=invalid-name
74 # import_as_names ::= import_as_name (',' import_as_name)* [',']
75 self
.DefaultNodeVisit(node
)
77 for child
in node
.children
:
78 if (prev_child
and isinstance(prev_child
, pytree
.Leaf
) and
79 prev_child
.value
== ','):
80 _SetSplitPenalty(child
, style
.Get('SPLIT_PENALTY_IMPORT_NAMES'))
83 def Visit_classdef(self
, node
): # pylint: disable=invalid-name
84 # classdef ::= 'class' NAME ['(' [arglist] ')'] ':' suite
87 _SetUnbreakable(node
.children
[1])
88 if len(node
.children
) > 4:
90 _SetUnbreakable(node
.children
[2])
92 _SetUnbreakable(node
.children
[-2])
93 self
.DefaultNodeVisit(node
)
95 def Visit_funcdef(self
, node
): # pylint: disable=invalid-name
96 # funcdef ::= 'def' NAME parameters ['->' test] ':' suite
98 # Can't break before the function name and before the colon. The parameters
99 # are handled by child iteration.
101 while pytree_utils
.NodeName(node
.children
[colon_idx
]) == 'simple_stmt':
103 _SetUnbreakable(node
.children
[colon_idx
])
105 while colon_idx
< len(node
.children
):
106 if isinstance(node
.children
[colon_idx
], pytree
.Leaf
):
107 if node
.children
[colon_idx
].value
== ':':
109 if node
.children
[colon_idx
].value
== '->':
110 arrow_idx
= colon_idx
112 _SetUnbreakable(node
.children
[colon_idx
])
113 self
.DefaultNodeVisit(node
)
116 pytree_utils
.LastLeafNode(node
.children
[arrow_idx
- 1]), 0)
117 _SetUnbreakable(node
.children
[arrow_idx
])
118 _SetStronglyConnected(node
.children
[arrow_idx
+ 1])
120 def Visit_lambdef(self
, node
): # pylint: disable=invalid-name
121 # lambdef ::= 'lambda' [varargslist] ':' test
122 # Loop over the lambda up to and including the colon.
123 allow_multiline_lambdas
= style
.Get('ALLOW_MULTILINE_LAMBDAS')
124 if not allow_multiline_lambdas
:
125 for child
in node
.children
:
126 if child
.type == grammar_token
.COMMENT
:
127 if re
.search(r
'pylint:.*disable=.*\bg-long-lambda', child
.value
):
128 allow_multiline_lambdas
= True
131 if allow_multiline_lambdas
:
132 _SetExpressionPenalty(node
, STRONGLY_CONNECTED
)
134 _SetExpressionPenalty(node
, VERY_STRONGLY_CONNECTED
)
136 def Visit_parameters(self
, node
): # pylint: disable=invalid-name
137 # parameters ::= '(' [typedargslist] ')'
138 self
.DefaultNodeVisit(node
)
140 # Can't break before the opening paren of a parameter list.
141 _SetUnbreakable(node
.children
[0])
142 if not (style
.Get('INDENT_CLOSING_BRACKETS') or
143 style
.Get('DEDENT_CLOSING_BRACKETS')):
144 _SetStronglyConnected(node
.children
[-1])
146 def Visit_arglist(self
, node
): # pylint: disable=invalid-name
147 # arglist ::= argument (',' argument)* [',']
148 if node
.children
[0].type == grammar_token
.STAR
:
149 # Python 3 treats a star expression as a specific expression type.
150 # Process it in that method.
151 self
.Visit_star_expr(node
)
154 self
.DefaultNodeVisit(node
)
156 for index
in range(1, len(node
.children
)):
157 child
= node
.children
[index
]
158 if isinstance(child
, pytree
.Leaf
) and child
.value
== ',':
159 _SetUnbreakable(child
)
161 for child
in node
.children
:
162 if pytree_utils
.NodeName(child
) == 'atom':
163 _IncreasePenalty(child
, CONNECTED
)
165 def Visit_argument(self
, node
): # pylint: disable=invalid-name
166 # argument ::= test [comp_for] | test '=' test # Really [keyword '='] test
167 self
.DefaultNodeVisit(node
)
169 for index
in range(1, len(node
.children
) - 1):
170 child
= node
.children
[index
]
171 if isinstance(child
, pytree
.Leaf
) and child
.value
== '=':
173 pytree_utils
.FirstLeafNode(node
.children
[index
]), NAMED_ASSIGN
)
175 pytree_utils
.FirstLeafNode(node
.children
[index
+ 1]), NAMED_ASSIGN
)
177 def Visit_tname(self
, node
): # pylint: disable=invalid-name
178 # tname ::= NAME [':' test]
179 self
.DefaultNodeVisit(node
)
181 for index
in range(1, len(node
.children
) - 1):
182 child
= node
.children
[index
]
183 if isinstance(child
, pytree
.Leaf
) and child
.value
== ':':
185 pytree_utils
.FirstLeafNode(node
.children
[index
]), NAMED_ASSIGN
)
187 pytree_utils
.FirstLeafNode(node
.children
[index
+ 1]), NAMED_ASSIGN
)
189 def Visit_dotted_name(self
, node
): # pylint: disable=invalid-name
190 # dotted_name ::= NAME ('.' NAME)*
191 for child
in node
.children
:
193 start
= 2 if hasattr(node
.children
[0], 'is_pseudo') else 1
194 for i
in range(start
, len(node
.children
)):
195 _SetUnbreakable(node
.children
[i
])
197 def Visit_dictsetmaker(self
, node
): # pylint: disable=invalid-name
198 # dictsetmaker ::= ( (test ':' test
199 # (comp_for | (',' test ':' test)* [','])) |
200 # (test (comp_for | (',' test)* [','])) )
201 for child
in node
.children
:
203 if child
.type == grammar_token
.COLON
:
204 # This is a key to a dictionary. We don't want to split the key if at
206 _SetStronglyConnected(child
)
208 def Visit_trailer(self
, node
): # pylint: disable=invalid-name
209 # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
210 if node
.children
[0].value
== '.':
211 before
= style
.Get('SPLIT_BEFORE_DOT')
212 _SetSplitPenalty(node
.children
[0],
213 VERY_STRONGLY_CONNECTED
if before
else DOTTED_NAME
)
214 _SetSplitPenalty(node
.children
[1],
215 DOTTED_NAME
if before
else VERY_STRONGLY_CONNECTED
)
216 elif len(node
.children
) == 2:
217 # Don't split an empty argument list if at all possible.
218 _SetSplitPenalty(node
.children
[1], VERY_STRONGLY_CONNECTED
)
219 elif len(node
.children
) == 3:
220 name
= pytree_utils
.NodeName(node
.children
[1])
221 if name
in {'argument', 'comparison'}:
222 # Don't split an argument list with one element if at all possible.
223 _SetStronglyConnected(node
.children
[1])
224 if (len(node
.children
[1].children
) > 1 and
225 pytree_utils
.NodeName(node
.children
[1].children
[1]) == 'comp_for'):
226 # Don't penalize splitting before a comp_for expression.
227 _SetSplitPenalty(pytree_utils
.FirstLeafNode(node
.children
[1]), 0)
230 pytree_utils
.FirstLeafNode(node
.children
[1]),
231 ONE_ELEMENT_ARGUMENT
)
232 elif (node
.children
[0].type == grammar_token
.LSQB
and
233 len(node
.children
[1].children
) > 2 and
234 (name
.endswith('_test') or name
.endswith('_expr'))):
235 _SetStronglyConnected(node
.children
[1].children
[0])
236 _SetStronglyConnected(node
.children
[1].children
[2])
238 # Still allow splitting around the operator.
239 split_before
= ((name
.endswith('_test') and
240 style
.Get('SPLIT_BEFORE_LOGICAL_OPERATOR')) or
241 (name
.endswith('_expr') and
242 style
.Get('SPLIT_BEFORE_BITWISE_OPERATOR')))
245 pytree_utils
.LastLeafNode(node
.children
[1].children
[1]), 0)
248 pytree_utils
.FirstLeafNode(node
.children
[1].children
[2]), 0)
250 # Don't split the ending bracket of a subscript list.
251 _RecAnnotate(node
.children
[-1], pytree_utils
.Annotation
.SPLIT_PENALTY
,
252 VERY_STRONGLY_CONNECTED
)
254 'arglist', 'argument', 'term', 'or_test', 'and_test', 'comparison',
257 # Don't split an argument list with one element if at all possible.
258 stypes
= pytree_utils
.GetNodeAnnotation(
259 pytree_utils
.FirstLeafNode(node
), pytree_utils
.Annotation
.SUBTYPE
)
260 if stypes
and subtypes
.SUBSCRIPT_BRACKET
in stypes
:
261 _IncreasePenalty(node
, SUBSCRIPT
)
263 # Bump up the split penalty for the first part of a subscript. We
264 # would rather not split there.
265 _IncreasePenalty(node
.children
[1], CONNECTED
)
267 _SetStronglyConnected(node
.children
[1], node
.children
[2])
269 if name
== 'arglist':
270 _SetStronglyConnected(node
.children
[-1])
272 self
.DefaultNodeVisit(node
)
274 def Visit_power(self
, node
): # pylint: disable=invalid-name,missing-docstring
275 # power ::= atom trailer* ['**' factor]
276 self
.DefaultNodeVisit(node
)
278 # When atom is followed by a trailer, we can not break between them.
279 # E.g. arr[idx] - no break allowed between 'arr' and '['.
280 if (len(node
.children
) > 1 and
281 pytree_utils
.NodeName(node
.children
[1]) == 'trailer'):
282 # children[1] itself is a whole trailer: we don't want to
283 # mark all of it as unbreakable, only its first token: (, [ or .
284 first
= pytree_utils
.FirstLeafNode(node
.children
[1])
285 if first
.value
!= '.':
286 _SetUnbreakable(node
.children
[1].children
[0])
288 # A special case when there are more trailers in the sequence. Given:
290 # The last token of tr1 and the first token of tr2 comprise an unbreakable
291 # region. For example: foo.bar.baz(1)
292 # We can't put breaks between either of the '.', '(', or '[' and the names
295 while prev_trailer_idx
< len(node
.children
) - 1:
296 cur_trailer_idx
= prev_trailer_idx
+ 1
297 cur_trailer
= node
.children
[cur_trailer_idx
]
298 if pytree_utils
.NodeName(cur_trailer
) != 'trailer':
301 # Now we know we have two trailers one after the other
302 prev_trailer
= node
.children
[prev_trailer_idx
]
303 if prev_trailer
.children
[-1].value
!= ')':
304 # Set the previous node unbreakable if it's not a function call:
306 # It may be necessary (though undesirable) to split up a previous
307 # function call's parentheses to the next line.
308 _SetStronglyConnected(prev_trailer
.children
[-1])
309 _SetStronglyConnected(cur_trailer
.children
[0])
310 prev_trailer_idx
= cur_trailer_idx
312 # We don't want to split before the last ')' of a function call. This also
313 # takes care of the special case of:
314 # atom tr1 tr2 ... trn
315 # where the 'tr#' are trailers that may end in a ')'.
316 for trailer
in node
.children
[1:]:
317 if pytree_utils
.NodeName(trailer
) != 'trailer':
319 if trailer
.children
[0].value
in '([':
320 if len(trailer
.children
) > 2:
321 stypes
= pytree_utils
.GetNodeAnnotation(
322 trailer
.children
[0], pytree_utils
.Annotation
.SUBTYPE
)
323 if stypes
and subtypes
.SUBSCRIPT_BRACKET
in stypes
:
324 _SetStronglyConnected(
325 pytree_utils
.FirstLeafNode(trailer
.children
[1]))
327 last_child_node
= pytree_utils
.LastLeafNode(trailer
)
328 if last_child_node
.value
.strip().startswith('#'):
329 last_child_node
= last_child_node
.prev_sibling
330 if not (style
.Get('INDENT_CLOSING_BRACKETS') or
331 style
.Get('DEDENT_CLOSING_BRACKETS')):
332 last
= pytree_utils
.LastLeafNode(last_child_node
.prev_sibling
)
333 if last
.value
!= ',':
334 if last_child_node
.value
== ']':
335 _SetUnbreakable(last_child_node
)
337 _SetSplitPenalty(last_child_node
, VERY_STRONGLY_CONNECTED
)
339 # If the trailer's children are '()', then make it a strongly
340 # connected region. It's sometimes necessary, though undesirable, to
342 _SetStronglyConnected(trailer
.children
[-1])
344 def Visit_subscriptlist(self
, node
): # pylint: disable=invalid-name
345 # subscriptlist ::= subscript (',' subscript)* [',']
346 self
.DefaultNodeVisit(node
)
347 _SetSplitPenalty(pytree_utils
.FirstLeafNode(node
), 0)
349 for child
in node
.children
:
350 if prev_child
and prev_child
.type == grammar_token
.COMMA
:
351 _SetSplitPenalty(pytree_utils
.FirstLeafNode(child
), 0)
354 def Visit_subscript(self
, node
): # pylint: disable=invalid-name
355 # subscript ::= test | [test] ':' [test] [sliceop]
356 _SetStronglyConnected(*node
.children
)
357 self
.DefaultNodeVisit(node
)
359 def Visit_comp_for(self
, node
): # pylint: disable=invalid-name
360 # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter]
361 _SetSplitPenalty(pytree_utils
.FirstLeafNode(node
), 0)
362 _SetStronglyConnected(*node
.children
[1:])
363 self
.DefaultNodeVisit(node
)
365 def Visit_old_comp_for(self
, node
): # pylint: disable=invalid-name
367 self
.Visit_comp_for(node
)
369 def Visit_comp_if(self
, node
): # pylint: disable=invalid-name
370 # comp_if ::= 'if' old_test [comp_iter]
371 _SetSplitPenalty(node
.children
[0],
372 style
.Get('SPLIT_PENALTY_BEFORE_IF_EXPR'))
373 _SetStronglyConnected(*node
.children
[1:])
374 self
.DefaultNodeVisit(node
)
376 def Visit_old_comp_if(self
, node
): # pylint: disable=invalid-name
378 self
.Visit_comp_if(node
)
380 def Visit_test(self
, node
): # pylint: disable=invalid-name
381 # test ::= or_test ['if' or_test 'else' test] | lambdef
382 _IncreasePenalty(node
, OR_TEST
)
383 self
.DefaultNodeVisit(node
)
385 def Visit_or_test(self
, node
): # pylint: disable=invalid-name
386 # or_test ::= and_test ('or' and_test)*
387 self
.DefaultNodeVisit(node
)
388 _IncreasePenalty(node
, OR_TEST
)
390 while index
+ 1 < len(node
.children
):
391 if style
.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
392 _DecrementSplitPenalty(
393 pytree_utils
.FirstLeafNode(node
.children
[index
]), OR_TEST
)
395 _DecrementSplitPenalty(
396 pytree_utils
.FirstLeafNode(node
.children
[index
+ 1]), OR_TEST
)
399 def Visit_and_test(self
, node
): # pylint: disable=invalid-name
400 # and_test ::= not_test ('and' not_test)*
401 self
.DefaultNodeVisit(node
)
402 _IncreasePenalty(node
, AND_TEST
)
404 while index
+ 1 < len(node
.children
):
405 if style
.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
406 _DecrementSplitPenalty(
407 pytree_utils
.FirstLeafNode(node
.children
[index
]), AND_TEST
)
409 _DecrementSplitPenalty(
410 pytree_utils
.FirstLeafNode(node
.children
[index
+ 1]), AND_TEST
)
413 def Visit_not_test(self
, node
): # pylint: disable=invalid-name
414 # not_test ::= 'not' not_test | comparison
415 self
.DefaultNodeVisit(node
)
416 _IncreasePenalty(node
, NOT_TEST
)
418 def Visit_comparison(self
, node
): # pylint: disable=invalid-name
419 # comparison ::= expr (comp_op expr)*
420 self
.DefaultNodeVisit(node
)
421 if len(node
.children
) == 3 and _StronglyConnectedCompOp(node
):
422 _IncreasePenalty(node
.children
[1], VERY_STRONGLY_CONNECTED
)
424 pytree_utils
.FirstLeafNode(node
.children
[2]), STRONGLY_CONNECTED
)
426 _IncreasePenalty(node
, COMPARISON
)
428 def Visit_star_expr(self
, node
): # pylint: disable=invalid-name
429 # star_expr ::= '*' expr
430 self
.DefaultNodeVisit(node
)
431 _IncreasePenalty(node
, STAR_EXPR
)
433 def Visit_expr(self
, node
): # pylint: disable=invalid-name
434 # expr ::= xor_expr ('|' xor_expr)*
435 self
.DefaultNodeVisit(node
)
436 _IncreasePenalty(node
, EXPR
)
437 _SetBitwiseOperandPenalty(node
, '|')
439 def Visit_xor_expr(self
, node
): # pylint: disable=invalid-name
440 # xor_expr ::= and_expr ('^' and_expr)*
441 self
.DefaultNodeVisit(node
)
442 _IncreasePenalty(node
, XOR_EXPR
)
443 _SetBitwiseOperandPenalty(node
, '^')
445 def Visit_and_expr(self
, node
): # pylint: disable=invalid-name
446 # and_expr ::= shift_expr ('&' shift_expr)*
447 self
.DefaultNodeVisit(node
)
448 _IncreasePenalty(node
, AND_EXPR
)
449 _SetBitwiseOperandPenalty(node
, '&')
451 def Visit_shift_expr(self
, node
): # pylint: disable=invalid-name
452 # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)*
453 self
.DefaultNodeVisit(node
)
454 _IncreasePenalty(node
, SHIFT_EXPR
)
456 _ARITH_OPS
= frozenset({'PLUS', 'MINUS'})
458 def Visit_arith_expr(self
, node
): # pylint: disable=invalid-name
459 # arith_expr ::= term (('+'|'-') term)*
460 self
.DefaultNodeVisit(node
)
461 _IncreasePenalty(node
, ARITH_EXPR
)
462 _SetExpressionOperandPenalty(node
, self
._ARITH
_OPS
)
464 _TERM_OPS
= frozenset({'STAR', 'AT', 'SLASH', 'PERCENT', 'DOUBLESLASH'})
466 def Visit_term(self
, node
): # pylint: disable=invalid-name
467 # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)*
468 self
.DefaultNodeVisit(node
)
469 _IncreasePenalty(node
, TERM
)
470 _SetExpressionOperandPenalty(node
, self
._TERM
_OPS
)
472 def Visit_factor(self
, node
): # pyline: disable=invalid-name
473 # factor ::= ('+'|'-'|'~') factor | power
474 self
.DefaultNodeVisit(node
)
475 _IncreasePenalty(node
, FACTOR
)
477 def Visit_atom(self
, node
): # pylint: disable=invalid-name
478 # atom ::= ('(' [yield_expr|testlist_gexp] ')'
479 # '[' [listmaker] ']' |
480 # '{' [dictsetmaker] '}')
481 self
.DefaultNodeVisit(node
)
482 if (node
.children
[0].value
== '(' and
483 not hasattr(node
.children
[0], 'is_pseudo')):
484 if node
.children
[-1].value
== ')':
485 if pytree_utils
.NodeName(node
.parent
) == 'if_stmt':
486 _SetSplitPenalty(node
.children
[-1], STRONGLY_CONNECTED
)
488 if len(node
.children
) > 2:
489 _SetSplitPenalty(pytree_utils
.FirstLeafNode(node
.children
[1]), EXPR
)
490 _SetSplitPenalty(node
.children
[-1], ATOM
)
491 elif node
.children
[0].value
in '[{' and len(node
.children
) == 2:
492 # Keep empty containers together if we can.
493 _SetUnbreakable(node
.children
[-1])
495 def Visit_testlist_gexp(self
, node
): # pylint: disable=invalid-name
496 self
.DefaultNodeVisit(node
)
497 prev_was_comma
= False
498 for child
in node
.children
:
499 if isinstance(child
, pytree
.Leaf
) and child
.value
== ',':
500 _SetUnbreakable(child
)
501 prev_was_comma
= True
504 _SetSplitPenalty(pytree_utils
.FirstLeafNode(child
), TOGETHER
)
505 prev_was_comma
= False
508 def _SetUnbreakable(node
):
509 """Set an UNBREAKABLE penalty annotation for the given node."""
510 _RecAnnotate(node
, pytree_utils
.Annotation
.SPLIT_PENALTY
, UNBREAKABLE
)
513 def _SetStronglyConnected(*nodes
):
514 """Set a STRONGLY_CONNECTED penalty annotation for the given nodes."""
516 _RecAnnotate(node
, pytree_utils
.Annotation
.SPLIT_PENALTY
,
520 def _SetExpressionPenalty(node
, penalty
):
521 """Set a penalty annotation on children nodes."""
523 def RecExpression(node
, first_child_leaf
):
524 if node
is first_child_leaf
:
527 if isinstance(node
, pytree
.Leaf
):
528 if node
.value
in {'(', 'for', 'if'}:
530 penalty_annotation
= pytree_utils
.GetNodeAnnotation(
531 node
, pytree_utils
.Annotation
.SPLIT_PENALTY
, default
=0)
532 if penalty_annotation
< penalty
:
533 _SetSplitPenalty(node
, penalty
)
535 for child
in node
.children
:
536 RecExpression(child
, first_child_leaf
)
538 RecExpression(node
, pytree_utils
.FirstLeafNode(node
))
541 def _SetBitwiseOperandPenalty(node
, op
):
542 for index
in range(1, len(node
.children
) - 1):
543 child
= node
.children
[index
]
544 if isinstance(child
, pytree
.Leaf
) and child
.value
== op
:
545 if style
.Get('SPLIT_BEFORE_BITWISE_OPERATOR'):
546 _SetSplitPenalty(child
, style
.Get('SPLIT_PENALTY_BITWISE_OPERATOR'))
549 pytree_utils
.FirstLeafNode(node
.children
[index
+ 1]),
550 style
.Get('SPLIT_PENALTY_BITWISE_OPERATOR'))
553 def _SetExpressionOperandPenalty(node
, ops
):
554 for index
in range(1, len(node
.children
) - 1):
555 child
= node
.children
[index
]
556 if pytree_utils
.NodeName(child
) in ops
:
557 if style
.Get('SPLIT_BEFORE_ARITHMETIC_OPERATOR'):
558 _SetSplitPenalty(child
, style
.Get('SPLIT_PENALTY_ARITHMETIC_OPERATOR'))
561 pytree_utils
.FirstLeafNode(node
.children
[index
+ 1]),
562 style
.Get('SPLIT_PENALTY_ARITHMETIC_OPERATOR'))
565 def _IncreasePenalty(node
, amt
):
566 """Increase a penalty annotation on children nodes."""
568 def RecExpression(node
, first_child_leaf
):
569 if node
is first_child_leaf
:
572 if isinstance(node
, pytree
.Leaf
):
573 if node
.value
in {'(', 'for'}:
575 penalty
= pytree_utils
.GetNodeAnnotation(
576 node
, pytree_utils
.Annotation
.SPLIT_PENALTY
, default
=0)
577 _SetSplitPenalty(node
, penalty
+ amt
)
579 for child
in node
.children
:
580 RecExpression(child
, first_child_leaf
)
582 RecExpression(node
, pytree_utils
.FirstLeafNode(node
))
585 def _RecAnnotate(tree
, annotate_name
, annotate_value
):
586 """Recursively set the given annotation on all leafs of the subtree.
588 Takes care to only increase the penalty. If the node already has a higher
589 or equal penalty associated with it, this is a no-op.
592 tree: subtree to annotate
593 annotate_name: name of the annotation to set
594 annotate_value: value of the annotation to set
596 for child
in tree
.children
:
597 _RecAnnotate(child
, annotate_name
, annotate_value
)
598 if isinstance(tree
, pytree
.Leaf
):
599 cur_annotate
= pytree_utils
.GetNodeAnnotation(
600 tree
, annotate_name
, default
=0)
601 if cur_annotate
< annotate_value
:
602 pytree_utils
.SetNodeAnnotation(tree
, annotate_name
, annotate_value
)
605 _COMP_OPS
= frozenset({'==', '!=', '<=', '<', '>', '>=', '<>', 'in', 'is'})
608 def _StronglyConnectedCompOp(op
):
609 if (len(op
.children
[1].children
) == 2 and
610 pytree_utils
.NodeName(op
.children
[1]) == 'comp_op'):
611 if (pytree_utils
.FirstLeafNode(op
.children
[1]).value
== 'not' and
612 pytree_utils
.LastLeafNode(op
.children
[1]).value
== 'in'):
614 if (pytree_utils
.FirstLeafNode(op
.children
[1]).value
== 'is' and
615 pytree_utils
.LastLeafNode(op
.children
[1]).value
== 'not'):
617 if (isinstance(op
.children
[1], pytree
.Leaf
) and
618 op
.children
[1].value
in _COMP_OPS
):
623 def _DecrementSplitPenalty(node
, amt
):
624 penalty
= pytree_utils
.GetNodeAnnotation(
625 node
, pytree_utils
.Annotation
.SPLIT_PENALTY
, default
=amt
)
626 penalty
= penalty
- amt
if amt
< penalty
else 0
627 _SetSplitPenalty(node
, penalty
)
630 def _SetSplitPenalty(node
, penalty
):
631 pytree_utils
.SetNodeAnnotation(node
, pytree_utils
.Annotation
.SPLIT_PENALTY
,