logical_line.py 25 KB

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