xref: /aosp_15_r20/external/yapf/yapf/yapflib/logical_line.py (revision 7249d1a64f4850ccf838e62a46276f891f72998e)
1# Copyright 2015 Google Inc. All Rights Reserved.
2#
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
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
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"""LogicalLine primitive for formatting.
15
16A logical line is the containing data structure produced by the parser. It
17collects all nodes (stored in FormatToken objects) that could appear on a single
18line if there were no line length restrictions. It's then used by the parser to
19perform the wrapping required to comply with the style guide.
20"""
21
22from yapf.yapflib import format_token
23from yapf.yapflib import py3compat
24from yapf.yapflib import pytree_utils
25from yapf.yapflib import split_penalty
26from yapf.yapflib import style
27from yapf.yapflib import subtypes
28
29from lib2to3.fixer_util import syms as python_symbols
30
31
32class LogicalLine(object):
33  """Represents a single logical line in the output.
34
35  Attributes:
36    depth: indentation depth of this line. This is just a numeric value used to
37      distinguish lines that are more deeply nested than others. It is not the
38      actual amount of spaces, which is style-dependent.
39  """
40
41  def __init__(self, depth, tokens=None):
42    """Constructor.
43
44    Creates a new logical line with the given depth an initial list of tokens.
45    Constructs the doubly-linked lists for format tokens using their built-in
46    next_token and previous_token attributes.
47
48    Arguments:
49      depth: indentation depth of this line
50      tokens: initial list of tokens
51    """
52    self.depth = depth
53    self._tokens = tokens or []
54    self.disable = False
55
56    if self._tokens:
57      # Set up a doubly linked list.
58      for index, tok in enumerate(self._tokens[1:]):
59        # Note, 'index' is the index to the previous token.
60        tok.previous_token = self._tokens[index]
61        self._tokens[index].next_token = tok
62
63  def CalculateFormattingInformation(self):
64    """Calculate the split penalty and total length for the tokens."""
65    # Say that the first token in the line should have a space before it. This
66    # means only that if this logical line is joined with a predecessor line,
67    # then there will be a space between them.
68    self.first.spaces_required_before = 1
69    self.first.total_length = len(self.first.value)
70
71    prev_token = self.first
72    prev_length = self.first.total_length
73    for token in self._tokens[1:]:
74      if (token.spaces_required_before == 0 and
75          _SpaceRequiredBetween(prev_token, token, self.disable)):
76        token.spaces_required_before = 1
77
78      tok_len = len(token.value) if not token.is_pseudo else 0
79
80      spaces_required_before = token.spaces_required_before
81      if isinstance(spaces_required_before, list):
82        assert token.is_comment, token
83
84        # If here, we are looking at a comment token that appears on a line
85        # with other tokens (but because it is a comment, it is always the last
86        # token).  Rather than specifying the actual number of spaces here,
87        # hard code a value of 0 and then set it later. This logic only works
88        # because this comment token is guaranteed to be the last token in the
89        # list.
90        spaces_required_before = 0
91
92      token.total_length = prev_length + tok_len + spaces_required_before
93
94      # The split penalty has to be computed before {must|can}_break_before,
95      # because these may use it for their decision.
96      token.split_penalty += _SplitPenalty(prev_token, token)
97      token.must_break_before = _MustBreakBefore(prev_token, token)
98      token.can_break_before = (
99          token.must_break_before or _CanBreakBefore(prev_token, token))
100
101      prev_length = token.total_length
102      prev_token = token
103
104  def Split(self):
105    """Split the line at semicolons."""
106    if not self.has_semicolon or self.disable:
107      return [self]
108
109    llines = []
110    lline = LogicalLine(self.depth)
111    for tok in self._tokens:
112      if tok.value == ';':
113        llines.append(lline)
114        lline = LogicalLine(self.depth)
115      else:
116        lline.AppendToken(tok)
117
118    if lline.tokens:
119      llines.append(lline)
120
121    for lline in llines:
122      lline.first.previous_token = None
123      lline.last.next_token = None
124
125    return llines
126
127  ############################################################################
128  # Token Access and Manipulation Methods                                    #
129  ############################################################################
130
131  def AppendToken(self, token):
132    """Append a new FormatToken to the tokens contained in this line."""
133    if self._tokens:
134      token.previous_token = self.last
135      self.last.next_token = token
136    self._tokens.append(token)
137
138  def AppendNode(self, node):
139    """Convenience method to append a pytree node directly.
140
141    Wraps the node with a FormatToken.
142
143    Arguments:
144      node: the node to append
145    """
146    self.AppendToken(format_token.FormatToken(node))
147
148  @property
149  def first(self):
150    """Returns the first non-whitespace token."""
151    return self._tokens[0]
152
153  @property
154  def last(self):
155    """Returns the last non-whitespace token."""
156    return self._tokens[-1]
157
158  ############################################################################
159  # Token -> String Methods                                                  #
160  ############################################################################
161
162  def AsCode(self, indent_per_depth=2):
163    """Return a "code" representation of this line.
164
165    The code representation shows how the line would be printed out as code.
166
167    TODO(eliben): for now this is rudimentary for debugging - once we add
168    formatting capabilities, this method will have other uses (not all tokens
169    have spaces around them, for example).
170
171    Arguments:
172      indent_per_depth: how much spaces to indend per depth level.
173
174    Returns:
175      A string representing the line as code.
176    """
177    indent = ' ' * indent_per_depth * self.depth
178    tokens_str = ' '.join(tok.value for tok in self._tokens)
179    return indent + tokens_str
180
181  def __str__(self):  # pragma: no cover
182    return self.AsCode()
183
184  def __repr__(self):  # pragma: no cover
185    tokens_repr = ','.join(
186        '{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens)
187    return 'LogicalLine(depth={0}, tokens=[{1}])'.format(
188        self.depth, tokens_repr)
189
190  ############################################################################
191  # Properties                                                               #
192  ############################################################################
193
194  @property
195  def tokens(self):
196    """Access the tokens contained within this line.
197
198    The caller must not modify the tokens list returned by this method.
199
200    Returns:
201      List of tokens in this line.
202    """
203    return self._tokens
204
205  @property
206  def lineno(self):
207    """Return the line number of this logical line.
208
209    Returns:
210      The line number of the first token in this logical line.
211    """
212    return self.first.lineno
213
214  @property
215  def start(self):
216    """The start of the logical line.
217
218    Returns:
219      A tuple of the starting line number and column.
220    """
221    return (self.first.lineno, self.first.column)
222
223  @property
224  def end(self):
225    """The end of the logical line.
226
227    Returns:
228      A tuple of the ending line number and column.
229    """
230    return (self.last.lineno, self.last.column + len(self.last.value))
231
232  @property
233  def is_comment(self):
234    return self.first.is_comment
235
236  @property
237  def has_semicolon(self):
238    return any(tok.value == ';' for tok in self._tokens)
239
240
241def _IsIdNumberStringToken(tok):
242  return tok.is_keyword or tok.is_name or tok.is_number or tok.is_string
243
244
245def _IsUnaryOperator(tok):
246  return subtypes.UNARY_OPERATOR in tok.subtypes
247
248
249def _HasPrecedence(tok):
250  """Whether a binary operation has precedence within its context."""
251  node = tok.node
252
253  # We let ancestor be the statement surrounding the operation that tok is the
254  # operator in.
255  ancestor = node.parent.parent
256
257  while ancestor is not None:
258    # Search through the ancestor nodes in the parse tree for operators with
259    # lower precedence.
260    predecessor_type = pytree_utils.NodeName(ancestor)
261    if predecessor_type in ['arith_expr', 'term']:
262      # An ancestor "arith_expr" or "term" means we have found an operator
263      # with lower precedence than our tok.
264      return True
265    if predecessor_type != 'atom':
266      # We understand the context to look for precedence within as an
267      # arbitrary nesting of "arith_expr", "term", and "atom" nodes. If we
268      # leave this context we have not found a lower precedence operator.
269      return False
270    # Under normal usage we expect a complete parse tree to be available and
271    # we will return before we get an AttributeError from the root.
272    ancestor = ancestor.parent
273
274
275def _PriorityIndicatingNoSpace(tok):
276  """Whether to remove spaces around an operator due to precedence."""
277  if not tok.is_arithmetic_op or not tok.is_simple_expr:
278    # Limit space removal to highest priority arithmetic operators
279    return False
280  return _HasPrecedence(tok)
281
282
283def _IsSubscriptColonAndValuePair(token1, token2):
284  return (token1.is_number or token1.is_name) and token2.is_subscript_colon
285
286
287def _SpaceRequiredBetween(left, right, is_line_disabled):
288  """Return True if a space is required between the left and right token."""
289  lval = left.value
290  rval = right.value
291  if (left.is_pseudo and _IsIdNumberStringToken(right) and
292      left.previous_token and _IsIdNumberStringToken(left.previous_token)):
293    # Space between keyword... tokens and pseudo parens.
294    return True
295  if left.is_pseudo or right.is_pseudo:
296    # There should be a space after the ':' in a dictionary.
297    if left.OpensScope():
298      return True
299    # The closing pseudo-paren shouldn't affect spacing.
300    return False
301  if left.is_continuation or right.is_continuation:
302    # The continuation node's value has all of the spaces it needs.
303    return False
304  if right.name in pytree_utils.NONSEMANTIC_TOKENS:
305    # No space before a non-semantic token.
306    return False
307  if _IsIdNumberStringToken(left) and _IsIdNumberStringToken(right):
308    # Spaces between keyword, string, number, and identifier tokens.
309    return True
310  if lval == ',' and rval == ':':
311    # We do want a space between a comma and colon.
312    return True
313  if style.Get('SPACE_INSIDE_BRACKETS'):
314    # Supersede the "no space before a colon or comma" check.
315    if lval in pytree_utils.OPENING_BRACKETS and rval == ':':
316      return True
317    if rval in pytree_utils.CLOSING_BRACKETS and lval == ':':
318      return True
319  if (style.Get('SPACES_AROUND_SUBSCRIPT_COLON') and
320      (_IsSubscriptColonAndValuePair(left, right) or
321       _IsSubscriptColonAndValuePair(right, left))):
322    # Supersede the "never want a space before a colon or comma" check.
323    return True
324  if rval in ':,':
325    # Otherwise, we never want a space before a colon or comma.
326    return False
327  if lval == ',' and rval in ']})':
328    # Add a space between ending ',' and closing bracket if requested.
329    return style.Get('SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET')
330  if lval == ',':
331    # We want a space after a comma.
332    return True
333  if lval == 'from' and rval == '.':
334    # Space before the '.' in an import statement.
335    return True
336  if lval == '.' and rval == 'import':
337    # Space after the '.' in an import statement.
338    return True
339  if (lval == '=' and rval in {'.', ',,,'} and
340      subtypes.DEFAULT_OR_NAMED_ASSIGN not in left.subtypes):
341    # Space between equal and '.' as in "X = ...".
342    return True
343  if lval == ':' and rval in {'.', '...'}:
344    # Space between : and ...
345    return True
346  if ((right.is_keyword or right.is_name) and
347      (left.is_keyword or left.is_name)):
348    # Don't merge two keywords/identifiers.
349    return True
350  if (subtypes.SUBSCRIPT_COLON in left.subtypes or
351      subtypes.SUBSCRIPT_COLON in right.subtypes):
352    # A subscript shouldn't have spaces separating its colons.
353    return False
354  if (subtypes.TYPED_NAME in left.subtypes or
355      subtypes.TYPED_NAME in right.subtypes):
356    # A typed argument should have a space after the colon.
357    return True
358  if left.is_string:
359    if (rval == '=' and
360        subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in right.subtypes):
361      # If there is a type hint, then we don't want to add a space between the
362      # equal sign and the hint.
363      return False
364    if rval not in '[)]}.' and not right.is_binary_op:
365      # A string followed by something other than a subscript, closing bracket,
366      # dot, or a binary op should have a space after it.
367      return True
368    if rval in pytree_utils.CLOSING_BRACKETS:
369      # A string followed by closing brackets should have a space after it
370      # depending on SPACE_INSIDE_BRACKETS.  A string followed by opening
371      # brackets, however, should not.
372      return style.Get('SPACE_INSIDE_BRACKETS')
373    if subtypes.SUBSCRIPT_BRACKET in right.subtypes:
374      # It's legal to do this in Python: 'hello'[a]
375      return False
376  if left.is_binary_op and lval != '**' and _IsUnaryOperator(right):
377    # Space between the binary operator and the unary operator.
378    return True
379  if left.is_keyword and _IsUnaryOperator(right):
380    # Handle things like "not -3 < x".
381    return True
382  if _IsUnaryOperator(left) and _IsUnaryOperator(right):
383    # No space between two unary operators.
384    return False
385  if left.is_binary_op or right.is_binary_op:
386    if lval == '**' or rval == '**':
387      # Space around the "power" operator.
388      return style.Get('SPACES_AROUND_POWER_OPERATOR')
389    # Enforce spaces around binary operators except the blocked ones.
390    block_list = style.Get('NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS')
391    if lval in block_list or rval in block_list:
392      return False
393    if style.Get('ARITHMETIC_PRECEDENCE_INDICATION'):
394      if _PriorityIndicatingNoSpace(left) or _PriorityIndicatingNoSpace(right):
395        return False
396      else:
397        return True
398    else:
399      return True
400  if (_IsUnaryOperator(left) and lval != 'not' and
401      (right.is_name or right.is_number or rval == '(')):
402    # The previous token was a unary op. No space is desired between it and
403    # the current token.
404    return False
405  if (subtypes.DEFAULT_OR_NAMED_ASSIGN in left.subtypes and
406      subtypes.TYPED_NAME not in right.subtypes):
407    # A named argument or default parameter shouldn't have spaces around it.
408    return style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN')
409  if (subtypes.DEFAULT_OR_NAMED_ASSIGN in right.subtypes and
410      subtypes.TYPED_NAME not in left.subtypes):
411    # A named argument or default parameter shouldn't have spaces around it.
412    return style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN')
413  if (subtypes.VARARGS_LIST in left.subtypes or
414      subtypes.VARARGS_LIST in right.subtypes):
415    return False
416  if (subtypes.VARARGS_STAR in left.subtypes or
417      subtypes.KWARGS_STAR_STAR in left.subtypes):
418    # Don't add a space after a vararg's star or a keyword's star-star.
419    return False
420  if lval == '@' and subtypes.DECORATOR in left.subtypes:
421    # Decorators shouldn't be separated from the 'at' sign.
422    return False
423  if left.is_keyword and rval == '.':
424    # Add space between keywords and dots.
425    return lval not in {'None', 'print'}
426  if lval == '.' and right.is_keyword:
427    # Add space between keywords and dots.
428    return rval not in {'None', 'print'}
429  if lval == '.' or rval == '.':
430    # Don't place spaces between dots.
431    return False
432  if ((lval == '(' and rval == ')') or (lval == '[' and rval == ']') or
433      (lval == '{' and rval == '}')):
434    # Empty objects shouldn't be separated by spaces.
435    return False
436  if not is_line_disabled and (left.OpensScope() or right.ClosesScope()):
437    if (style.GetOrDefault('SPACES_AROUND_DICT_DELIMITERS', False) and (
438        (lval == '{' and _IsDictListTupleDelimiterTok(left, is_opening=True)) or
439        (rval == '}' and
440         _IsDictListTupleDelimiterTok(right, is_opening=False)))):
441      return True
442    if (style.GetOrDefault('SPACES_AROUND_LIST_DELIMITERS', False) and (
443        (lval == '[' and _IsDictListTupleDelimiterTok(left, is_opening=True)) or
444        (rval == ']' and
445         _IsDictListTupleDelimiterTok(right, is_opening=False)))):
446      return True
447    if (style.GetOrDefault('SPACES_AROUND_TUPLE_DELIMITERS', False) and (
448        (lval == '(' and _IsDictListTupleDelimiterTok(left, is_opening=True)) or
449        (rval == ')' and
450         _IsDictListTupleDelimiterTok(right, is_opening=False)))):
451      return True
452  if (lval in pytree_utils.OPENING_BRACKETS and
453      rval in pytree_utils.OPENING_BRACKETS):
454    # Nested objects' opening brackets shouldn't be separated, unless enabled
455    # by SPACE_INSIDE_BRACKETS.
456    return style.Get('SPACE_INSIDE_BRACKETS')
457  if (lval in pytree_utils.CLOSING_BRACKETS and
458      rval in pytree_utils.CLOSING_BRACKETS):
459    # Nested objects' closing brackets shouldn't be separated, unless enabled
460    # by SPACE_INSIDE_BRACKETS.
461    return style.Get('SPACE_INSIDE_BRACKETS')
462  if lval in pytree_utils.CLOSING_BRACKETS and rval in '([':
463    # A call, set, dictionary, or subscript that has a call or subscript after
464    # it shouldn't have a space between them.
465    return False
466  if lval in pytree_utils.OPENING_BRACKETS and _IsIdNumberStringToken(right):
467    # Don't separate the opening bracket from the first item, unless enabled
468    # by SPACE_INSIDE_BRACKETS.
469    return style.Get('SPACE_INSIDE_BRACKETS')
470  if left.is_name and rval in '([':
471    # Don't separate a call or array access from the name.
472    return False
473  if rval in pytree_utils.CLOSING_BRACKETS:
474    # Don't separate the closing bracket from the last item, unless enabled
475    # by SPACE_INSIDE_BRACKETS.
476    # FIXME(morbo): This might be too permissive.
477    return style.Get('SPACE_INSIDE_BRACKETS')
478  if lval == 'print' and rval == '(':
479    # Special support for the 'print' function.
480    return False
481  if lval in pytree_utils.OPENING_BRACKETS and _IsUnaryOperator(right):
482    # Don't separate a unary operator from the opening bracket, unless enabled
483    # by SPACE_INSIDE_BRACKETS.
484    return style.Get('SPACE_INSIDE_BRACKETS')
485  if (lval in pytree_utils.OPENING_BRACKETS and
486      (subtypes.VARARGS_STAR in right.subtypes or
487       subtypes.KWARGS_STAR_STAR in right.subtypes)):
488    # Don't separate a '*' or '**' from the opening bracket, unless enabled
489    # by SPACE_INSIDE_BRACKETS.
490    return style.Get('SPACE_INSIDE_BRACKETS')
491  if rval == ';':
492    # Avoid spaces before a semicolon. (Why is there a semicolon?!)
493    return False
494  if lval == '(' and rval == 'await':
495    # Special support for the 'await' keyword. Don't separate the 'await'
496    # keyword from an opening paren, unless enabled by SPACE_INSIDE_BRACKETS.
497    return style.Get('SPACE_INSIDE_BRACKETS')
498  return True
499
500
501def _MustBreakBefore(prev_token, cur_token):
502  """Return True if a line break is required before the current token."""
503  if prev_token.is_comment or (prev_token.previous_token and
504                               prev_token.is_pseudo and
505                               prev_token.previous_token.is_comment):
506    # Must break if the previous token was a comment.
507    return True
508  if (cur_token.is_string and prev_token.is_string and
509      IsSurroundedByBrackets(cur_token)):
510    # We want consecutive strings to be on separate lines. This is a
511    # reasonable assumption, because otherwise they should have written them
512    # all on the same line, or with a '+'.
513    return True
514  return cur_token.must_break_before
515
516
517def _CanBreakBefore(prev_token, cur_token):
518  """Return True if a line break may occur before the current token."""
519  pval = prev_token.value
520  cval = cur_token.value
521  if py3compat.PY3:
522    if pval == 'yield' and cval == 'from':
523      # Don't break before a yield argument.
524      return False
525    if pval in {'async', 'await'} and cval in {'def', 'with', 'for'}:
526      # Don't break after sync keywords.
527      return False
528  if cur_token.split_penalty >= split_penalty.UNBREAKABLE:
529    return False
530  if pval == '@':
531    # Don't break right after the beginning of a decorator.
532    return False
533  if cval == ':':
534    # Don't break before the start of a block of code.
535    return False
536  if cval == ',':
537    # Don't break before a comma.
538    return False
539  if prev_token.is_name and cval == '(':
540    # Don't break in the middle of a function definition or call.
541    return False
542  if prev_token.is_name and cval == '[':
543    # Don't break in the middle of an array dereference.
544    return False
545  if cur_token.is_comment and prev_token.lineno == cur_token.lineno:
546    # Don't break a comment at the end of the line.
547    return False
548  if subtypes.UNARY_OPERATOR in prev_token.subtypes:
549    # Don't break after a unary token.
550    return False
551  if not style.Get('ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS'):
552    if (subtypes.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes or
553        subtypes.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes):
554      return False
555  return True
556
557
558def IsSurroundedByBrackets(tok):
559  """Return True if the token is surrounded by brackets."""
560  paren_count = 0
561  brace_count = 0
562  sq_bracket_count = 0
563  previous_token = tok.previous_token
564  while previous_token:
565    if previous_token.value == ')':
566      paren_count -= 1
567    elif previous_token.value == '}':
568      brace_count -= 1
569    elif previous_token.value == ']':
570      sq_bracket_count -= 1
571
572    if previous_token.value == '(':
573      if paren_count == 0:
574        return previous_token
575      paren_count += 1
576    elif previous_token.value == '{':
577      if brace_count == 0:
578        return previous_token
579      brace_count += 1
580    elif previous_token.value == '[':
581      if sq_bracket_count == 0:
582        return previous_token
583      sq_bracket_count += 1
584
585    previous_token = previous_token.previous_token
586  return None
587
588
589def _IsDictListTupleDelimiterTok(tok, is_opening):
590  assert tok
591
592  if tok.matching_bracket is None:
593    return False
594
595  if is_opening:
596    open_tok = tok
597    close_tok = tok.matching_bracket
598  else:
599    open_tok = tok.matching_bracket
600    close_tok = tok
601
602  # There must be something in between the tokens
603  if open_tok.next_token == close_tok:
604    return False
605
606  assert open_tok.next_token.node
607  assert open_tok.next_token.node.parent
608
609  return open_tok.next_token.node.parent.type in [
610      python_symbols.dictsetmaker,
611      python_symbols.listmaker,
612      python_symbols.testlist_gexp,
613  ]
614
615
616_LOGICAL_OPERATORS = frozenset({'and', 'or'})
617_BITWISE_OPERATORS = frozenset({'&', '|', '^'})
618_ARITHMETIC_OPERATORS = frozenset({'+', '-', '*', '/', '%', '//', '@'})
619
620
621def _SplitPenalty(prev_token, cur_token):
622  """Return the penalty for breaking the line before the current token."""
623  pval = prev_token.value
624  cval = cur_token.value
625  if pval == 'not':
626    return split_penalty.UNBREAKABLE
627
628  if cur_token.node_split_penalty > 0:
629    return cur_token.node_split_penalty
630
631  if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
632    # Prefer to split before 'and' and 'or'.
633    if pval in _LOGICAL_OPERATORS:
634      return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')
635    if cval in _LOGICAL_OPERATORS:
636      return 0
637  else:
638    # Prefer to split after 'and' and 'or'.
639    if pval in _LOGICAL_OPERATORS:
640      return 0
641    if cval in _LOGICAL_OPERATORS:
642      return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')
643
644  if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'):
645    # Prefer to split before '&', '|', and '^'.
646    if pval in _BITWISE_OPERATORS:
647      return style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')
648    if cval in _BITWISE_OPERATORS:
649      return 0
650  else:
651    # Prefer to split after '&', '|', and '^'.
652    if pval in _BITWISE_OPERATORS:
653      return 0
654    if cval in _BITWISE_OPERATORS:
655      return style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')
656
657  if (subtypes.COMP_FOR in cur_token.subtypes or
658      subtypes.COMP_IF in cur_token.subtypes):
659    # We don't mind breaking before the 'for' or 'if' of a list comprehension.
660    return 0
661  if subtypes.UNARY_OPERATOR in prev_token.subtypes:
662    # Try not to break after a unary operator.
663    return style.Get('SPLIT_PENALTY_AFTER_UNARY_OPERATOR')
664  if pval == ',':
665    # Breaking after a comma is fine, if need be.
666    return 0
667  if pval == '**' or cval == '**':
668    return split_penalty.STRONGLY_CONNECTED
669  if (subtypes.VARARGS_STAR in prev_token.subtypes or
670      subtypes.KWARGS_STAR_STAR in prev_token.subtypes):
671    # Don't split after a varargs * or kwargs **.
672    return split_penalty.UNBREAKABLE
673  if prev_token.OpensScope() and cval != '(':
674    # Slightly prefer
675    return style.Get('SPLIT_PENALTY_AFTER_OPENING_BRACKET')
676  if cval == ':':
677    # Don't split before a colon.
678    return split_penalty.UNBREAKABLE
679  if cval == '=':
680    # Don't split before an assignment.
681    return split_penalty.UNBREAKABLE
682  if (subtypes.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes or
683      subtypes.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes):
684    # Don't break before or after an default or named assignment.
685    return split_penalty.UNBREAKABLE
686  if cval == '==':
687    # We would rather not split before an equality operator.
688    return split_penalty.STRONGLY_CONNECTED
689  if cur_token.ClosesScope():
690    # Give a slight penalty for splitting before the closing scope.
691    return 100
692  return 0
693