You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
510 lines
20 KiB
510 lines
20 KiB
# Copyright 2015 Google Inc. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
"""Subtype assigner for lib2to3 trees.
|
|
|
|
This module assigns extra type information to the lib2to3 trees. This
|
|
information is more specific than whether something is an operator or an
|
|
identifier. For instance, it can specify if a node in the tree is part of a
|
|
subscript.
|
|
|
|
AssignSubtypes(): the main function exported by this module.
|
|
|
|
Annotations:
|
|
subtype: The subtype of a pytree token. See 'format_token' module for a list
|
|
of subtypes.
|
|
"""
|
|
|
|
from lib2to3 import pytree
|
|
from lib2to3.pgen2 import token
|
|
from lib2to3.pygram import python_symbols as syms
|
|
|
|
from yapf.yapflib import format_token
|
|
from yapf.yapflib import pytree_utils
|
|
from yapf.yapflib import pytree_visitor
|
|
from yapf.yapflib import style
|
|
|
|
|
|
def AssignSubtypes(tree):
|
|
"""Run the subtype assigner visitor over the tree, modifying it in place.
|
|
|
|
Arguments:
|
|
tree: the top-level pytree node to annotate with subtypes.
|
|
"""
|
|
subtype_assigner = _SubtypeAssigner()
|
|
subtype_assigner.Visit(tree)
|
|
|
|
|
|
# Map tokens in argument lists to their respective subtype.
|
|
_ARGLIST_TOKEN_TO_SUBTYPE = {
|
|
'=': format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN,
|
|
':': format_token.Subtype.TYPED_NAME,
|
|
'*': format_token.Subtype.VARARGS_STAR,
|
|
'**': format_token.Subtype.KWARGS_STAR_STAR,
|
|
}
|
|
|
|
|
|
class _SubtypeAssigner(pytree_visitor.PyTreeVisitor):
|
|
"""_SubtypeAssigner - see file-level docstring for detailed description.
|
|
|
|
The subtype is added as an annotation to the pytree token.
|
|
"""
|
|
|
|
def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name
|
|
# dictsetmaker ::= (test ':' test (comp_for |
|
|
# (',' test ':' test)* [','])) |
|
|
# (test (comp_for | (',' test)* [',']))
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
|
|
comp_for = False
|
|
dict_maker = False
|
|
|
|
for child in node.children:
|
|
if pytree_utils.NodeName(child) == 'comp_for':
|
|
comp_for = True
|
|
_AppendFirstLeafTokenSubtype(child,
|
|
format_token.Subtype.DICT_SET_GENERATOR)
|
|
elif pytree_utils.NodeName(child) in ('COLON', 'DOUBLESTAR'):
|
|
dict_maker = True
|
|
|
|
if not comp_for and dict_maker:
|
|
last_was_colon = False
|
|
unpacking = False
|
|
for child in node.children:
|
|
if pytree_utils.NodeName(child) == 'DOUBLESTAR':
|
|
_AppendFirstLeafTokenSubtype(child,
|
|
format_token.Subtype.KWARGS_STAR_STAR)
|
|
if last_was_colon:
|
|
if style.Get('INDENT_DICTIONARY_VALUE'):
|
|
_InsertPseudoParentheses(child)
|
|
else:
|
|
_AppendFirstLeafTokenSubtype(child,
|
|
format_token.Subtype.DICTIONARY_VALUE)
|
|
elif (isinstance(child, pytree.Node) or
|
|
(not child.value.startswith('#') and child.value not in '{:,')):
|
|
# Mark the first leaf of a key entry as a DICTIONARY_KEY. We
|
|
# normally want to split before them if the dictionary cannot exist
|
|
# on a single line.
|
|
if not unpacking or pytree_utils.FirstLeafNode(child).value == '**':
|
|
_AppendFirstLeafTokenSubtype(child,
|
|
format_token.Subtype.DICTIONARY_KEY)
|
|
_AppendSubtypeRec(child, format_token.Subtype.DICTIONARY_KEY_PART)
|
|
last_was_colon = pytree_utils.NodeName(child) == 'COLON'
|
|
if pytree_utils.NodeName(child) == 'DOUBLESTAR':
|
|
unpacking = True
|
|
elif last_was_colon:
|
|
unpacking = False
|
|
|
|
def Visit_expr_stmt(self, node): # pylint: disable=invalid-name
|
|
# expr_stmt ::= testlist_star_expr (augassign (yield_expr|testlist)
|
|
# | ('=' (yield_expr|testlist_star_expr))*)
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value == '=':
|
|
_AppendTokenSubtype(child, format_token.Subtype.ASSIGN_OPERATOR)
|
|
|
|
def Visit_or_test(self, node): # pylint: disable=invalid-name
|
|
# or_test ::= and_test ('or' and_test)*
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value == 'or':
|
|
_AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
|
|
|
|
def Visit_and_test(self, node): # pylint: disable=invalid-name
|
|
# and_test ::= not_test ('and' not_test)*
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value == 'and':
|
|
_AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
|
|
|
|
def Visit_not_test(self, node): # pylint: disable=invalid-name
|
|
# not_test ::= 'not' not_test | comparison
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value == 'not':
|
|
_AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR)
|
|
|
|
def Visit_comparison(self, node): # pylint: disable=invalid-name
|
|
# comparison ::= expr (comp_op expr)*
|
|
# comp_op ::= '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not in'|'is'|'is not'
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if (isinstance(child, pytree.Leaf) and
|
|
child.value in {'<', '>', '==', '>=', '<=', '<>', '!=', 'in', 'is'}):
|
|
_AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
|
|
elif pytree_utils.NodeName(child) == 'comp_op':
|
|
for grandchild in child.children:
|
|
_AppendTokenSubtype(grandchild, format_token.Subtype.BINARY_OPERATOR)
|
|
|
|
def Visit_star_expr(self, node): # pylint: disable=invalid-name
|
|
# star_expr ::= '*' expr
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value == '*':
|
|
_AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR)
|
|
_AppendTokenSubtype(child, format_token.Subtype.VARARGS_STAR)
|
|
|
|
def Visit_expr(self, node): # pylint: disable=invalid-name
|
|
# expr ::= xor_expr ('|' xor_expr)*
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value == '|':
|
|
_AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
|
|
|
|
def Visit_xor_expr(self, node): # pylint: disable=invalid-name
|
|
# xor_expr ::= and_expr ('^' and_expr)*
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value == '^':
|
|
_AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
|
|
|
|
def Visit_and_expr(self, node): # pylint: disable=invalid-name
|
|
# and_expr ::= shift_expr ('&' shift_expr)*
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value == '&':
|
|
_AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
|
|
|
|
def Visit_shift_expr(self, node): # pylint: disable=invalid-name
|
|
# shift_expr ::= arith_expr (('<<'|'>>') arith_expr)*
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value in {'<<', '>>'}:
|
|
_AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
|
|
|
|
def Visit_arith_expr(self, node): # pylint: disable=invalid-name
|
|
# arith_expr ::= term (('+'|'-') term)*
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if _IsAExprOperator(child):
|
|
_AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
|
|
_AppendTokenSubtype(child, format_token.Subtype.A_EXPR_OPERATOR)
|
|
|
|
if _IsSimpleExpression(node):
|
|
for child in node.children:
|
|
if _IsAExprOperator(child):
|
|
_AppendTokenSubtype(child, format_token.Subtype.SIMPLE_EXPRESSION)
|
|
|
|
def Visit_term(self, node): # pylint: disable=invalid-name
|
|
# term ::= factor (('*'|'/'|'%'|'//'|'@') factor)*
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if _IsMExprOperator(child):
|
|
_AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
|
|
_AppendTokenSubtype(child, format_token.Subtype.M_EXPR_OPERATOR)
|
|
|
|
if _IsSimpleExpression(node):
|
|
for child in node.children:
|
|
if _IsMExprOperator(child):
|
|
_AppendTokenSubtype(child, format_token.Subtype.SIMPLE_EXPRESSION)
|
|
|
|
def Visit_factor(self, node): # pylint: disable=invalid-name
|
|
# factor ::= ('+'|'-'|'~') factor | power
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value in '+-~':
|
|
_AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR)
|
|
|
|
def Visit_power(self, node): # pylint: disable=invalid-name
|
|
# power ::= atom trailer* ['**' factor]
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value == '**':
|
|
_AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
|
|
|
|
def Visit_trailer(self, node): # pylint: disable=invalid-name
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value in '[]':
|
|
_AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_BRACKET)
|
|
|
|
def Visit_subscript(self, node): # pylint: disable=invalid-name
|
|
# subscript ::= test | [test] ':' [test] [sliceop]
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value == ':':
|
|
_AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_COLON)
|
|
|
|
def Visit_sliceop(self, node): # pylint: disable=invalid-name
|
|
# sliceop ::= ':' [test]
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value == ':':
|
|
_AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_COLON)
|
|
|
|
def Visit_argument(self, node): # pylint: disable=invalid-name
|
|
# argument ::=
|
|
# test [comp_for] | test '=' test
|
|
self._ProcessArgLists(node)
|
|
|
|
def Visit_arglist(self, node): # pylint: disable=invalid-name
|
|
# arglist ::=
|
|
# (argument ',')* (argument [',']
|
|
# | '*' test (',' argument)* [',' '**' test]
|
|
# | '**' test)
|
|
self._ProcessArgLists(node)
|
|
_SetArgListSubtype(node, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN,
|
|
format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST)
|
|
|
|
def Visit_tname(self, node): # pylint: disable=invalid-name
|
|
self._ProcessArgLists(node)
|
|
_SetArgListSubtype(node, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN,
|
|
format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST)
|
|
|
|
def Visit_decorator(self, node): # pylint: disable=invalid-name
|
|
# decorator ::=
|
|
# '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
|
|
for child in node.children:
|
|
if isinstance(child, pytree.Leaf) and child.value == '@':
|
|
_AppendTokenSubtype(child, subtype=format_token.Subtype.DECORATOR)
|
|
self.Visit(child)
|
|
|
|
def Visit_funcdef(self, node): # pylint: disable=invalid-name
|
|
# funcdef ::=
|
|
# 'def' NAME parameters ['->' test] ':' suite
|
|
for child in node.children:
|
|
if pytree_utils.NodeName(child) == 'NAME' and child.value != 'def':
|
|
_AppendTokenSubtype(child, format_token.Subtype.FUNC_DEF)
|
|
break
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
|
|
def Visit_parameters(self, node): # pylint: disable=invalid-name
|
|
# parameters ::= '(' [typedargslist] ')'
|
|
self._ProcessArgLists(node)
|
|
if len(node.children) > 2:
|
|
_AppendFirstLeafTokenSubtype(node.children[1],
|
|
format_token.Subtype.PARAMETER_START)
|
|
_AppendLastLeafTokenSubtype(node.children[-2],
|
|
format_token.Subtype.PARAMETER_STOP)
|
|
|
|
def Visit_typedargslist(self, node): # pylint: disable=invalid-name
|
|
# typedargslist ::=
|
|
# ((tfpdef ['=' test] ',')*
|
|
# ('*' [tname] (',' tname ['=' test])* [',' '**' tname]
|
|
# | '**' tname)
|
|
# | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
|
|
self._ProcessArgLists(node)
|
|
_SetArgListSubtype(node, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN,
|
|
format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST)
|
|
tname = False
|
|
if not node.children:
|
|
return
|
|
|
|
_AppendFirstLeafTokenSubtype(node.children[0],
|
|
format_token.Subtype.PARAMETER_START)
|
|
_AppendLastLeafTokenSubtype(node.children[-1],
|
|
format_token.Subtype.PARAMETER_STOP)
|
|
|
|
i = 1
|
|
tname = pytree_utils.NodeName(node.children[0]) == 'tname'
|
|
while i < len(node.children):
|
|
prev_child = node.children[i - 1]
|
|
child = node.children[i]
|
|
i += 1
|
|
|
|
if pytree_utils.NodeName(prev_child) == 'COMMA':
|
|
_AppendFirstLeafTokenSubtype(child,
|
|
format_token.Subtype.PARAMETER_START)
|
|
elif pytree_utils.NodeName(child) == 'COMMA':
|
|
_AppendLastLeafTokenSubtype(prev_child,
|
|
format_token.Subtype.PARAMETER_STOP)
|
|
|
|
if pytree_utils.NodeName(child) == 'tname':
|
|
tname = True
|
|
_SetArgListSubtype(child, format_token.Subtype.TYPED_NAME,
|
|
format_token.Subtype.TYPED_NAME_ARG_LIST)
|
|
elif pytree_utils.NodeName(child) == 'COMMA':
|
|
tname = False
|
|
elif pytree_utils.NodeName(child) == 'EQUAL' and tname:
|
|
_AppendTokenSubtype(child, subtype=format_token.Subtype.TYPED_NAME)
|
|
tname = False
|
|
|
|
def Visit_varargslist(self, node): # pylint: disable=invalid-name
|
|
# varargslist ::=
|
|
# ((vfpdef ['=' test] ',')*
|
|
# ('*' [vname] (',' vname ['=' test])* [',' '**' vname]
|
|
# | '**' vname)
|
|
# | vfpdef ['=' test] (',' vfpdef ['=' test])* [','])
|
|
self._ProcessArgLists(node)
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf) and child.value == '=':
|
|
_AppendTokenSubtype(child, format_token.Subtype.VARARGS_LIST)
|
|
|
|
def Visit_comp_for(self, node): # pylint: disable=invalid-name
|
|
# comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter]
|
|
_AppendSubtypeRec(node, format_token.Subtype.COMP_FOR)
|
|
# Mark the previous node as COMP_EXPR unless this is a nested comprehension
|
|
# as these will have the outer comprehension as their previous node.
|
|
attr = pytree_utils.GetNodeAnnotation(node.parent,
|
|
pytree_utils.Annotation.SUBTYPE)
|
|
if not attr or format_token.Subtype.COMP_FOR not in attr:
|
|
_AppendSubtypeRec(node.parent.children[0], format_token.Subtype.COMP_EXPR)
|
|
self.DefaultNodeVisit(node)
|
|
|
|
def Visit_old_comp_for(self, node): # pylint: disable=invalid-name
|
|
# Python 3.7
|
|
self.Visit_comp_for(node)
|
|
|
|
def Visit_comp_if(self, node): # pylint: disable=invalid-name
|
|
# comp_if ::= 'if' old_test [comp_iter]
|
|
_AppendSubtypeRec(node, format_token.Subtype.COMP_IF)
|
|
self.DefaultNodeVisit(node)
|
|
|
|
def Visit_old_comp_if(self, node): # pylint: disable=invalid-name
|
|
# Python 3.7
|
|
self.Visit_comp_if(node)
|
|
|
|
def _ProcessArgLists(self, node):
|
|
"""Common method for processing argument lists."""
|
|
for child in node.children:
|
|
self.Visit(child)
|
|
if isinstance(child, pytree.Leaf):
|
|
_AppendTokenSubtype(
|
|
child,
|
|
subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value,
|
|
format_token.Subtype.NONE))
|
|
|
|
|
|
def _SetArgListSubtype(node, node_subtype, list_subtype):
|
|
"""Set named assign subtype on elements in a arg list."""
|
|
|
|
def HasSubtype(node):
|
|
"""Return True if the arg list has a named assign subtype."""
|
|
if isinstance(node, pytree.Leaf):
|
|
return node_subtype in pytree_utils.GetNodeAnnotation(
|
|
node, pytree_utils.Annotation.SUBTYPE, set())
|
|
|
|
for child in node.children:
|
|
node_name = pytree_utils.NodeName(child)
|
|
if node_name not in {'atom', 'arglist', 'power'}:
|
|
if HasSubtype(child):
|
|
return True
|
|
|
|
return False
|
|
|
|
if not HasSubtype(node):
|
|
return
|
|
|
|
for child in node.children:
|
|
node_name = pytree_utils.NodeName(child)
|
|
if node_name not in {'atom', 'COMMA'}:
|
|
_AppendFirstLeafTokenSubtype(child, list_subtype)
|
|
|
|
|
|
def _AppendTokenSubtype(node, subtype):
|
|
"""Append the token's subtype only if it's not already set."""
|
|
pytree_utils.AppendNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE,
|
|
subtype)
|
|
|
|
|
|
def _AppendFirstLeafTokenSubtype(node, subtype):
|
|
"""Append the first leaf token's subtypes."""
|
|
if isinstance(node, pytree.Leaf):
|
|
_AppendTokenSubtype(node, subtype)
|
|
return
|
|
_AppendFirstLeafTokenSubtype(node.children[0], subtype)
|
|
|
|
|
|
def _AppendLastLeafTokenSubtype(node, subtype):
|
|
"""Append the last leaf token's subtypes."""
|
|
if isinstance(node, pytree.Leaf):
|
|
_AppendTokenSubtype(node, subtype)
|
|
return
|
|
_AppendLastLeafTokenSubtype(node.children[-1], subtype)
|
|
|
|
|
|
def _AppendSubtypeRec(node, subtype, force=True):
|
|
"""Append the leafs in the node to the given subtype."""
|
|
if isinstance(node, pytree.Leaf):
|
|
_AppendTokenSubtype(node, subtype)
|
|
return
|
|
for child in node.children:
|
|
_AppendSubtypeRec(child, subtype, force=force)
|
|
|
|
|
|
def _InsertPseudoParentheses(node):
|
|
"""Insert pseudo parentheses so that dicts can be formatted correctly."""
|
|
comment_node = None
|
|
if isinstance(node, pytree.Node):
|
|
if node.children[-1].type == token.COMMENT:
|
|
comment_node = node.children[-1].clone()
|
|
node.children[-1].remove()
|
|
|
|
first = pytree_utils.FirstLeafNode(node)
|
|
last = pytree_utils.LastLeafNode(node)
|
|
|
|
if first == last and first.type == token.COMMENT:
|
|
# A comment was inserted before the value, which is a pytree.Leaf.
|
|
# Encompass the dictionary's value into an ATOM node.
|
|
last = first.next_sibling
|
|
last_clone = last.clone()
|
|
new_node = pytree.Node(syms.atom, [first.clone(), last_clone])
|
|
for orig_leaf, clone_leaf in zip(last.leaves(), last_clone.leaves()):
|
|
pytree_utils.CopyYapfAnnotations(orig_leaf, clone_leaf)
|
|
if hasattr(orig_leaf, 'is_pseudo'):
|
|
clone_leaf.is_pseudo = orig_leaf.is_pseudo
|
|
|
|
node.replace(new_node)
|
|
node = new_node
|
|
last.remove()
|
|
|
|
first = pytree_utils.FirstLeafNode(node)
|
|
last = pytree_utils.LastLeafNode(node)
|
|
|
|
lparen = pytree.Leaf(
|
|
token.LPAR, u'(', context=('', (first.get_lineno(), first.column - 1)))
|
|
last_lineno = last.get_lineno()
|
|
if last.type == token.STRING and '\n' in last.value:
|
|
last_lineno += last.value.count('\n')
|
|
|
|
if last.type == token.STRING and '\n' in last.value:
|
|
last_column = len(last.value.split('\n')[-1]) + 1
|
|
else:
|
|
last_column = last.column + len(last.value) + 1
|
|
rparen = pytree.Leaf(
|
|
token.RPAR, u')', context=('', (last_lineno, last_column)))
|
|
|
|
lparen.is_pseudo = True
|
|
rparen.is_pseudo = True
|
|
|
|
if isinstance(node, pytree.Node):
|
|
node.insert_child(0, lparen)
|
|
node.append_child(rparen)
|
|
if comment_node:
|
|
node.append_child(comment_node)
|
|
_AppendFirstLeafTokenSubtype(node, format_token.Subtype.DICTIONARY_VALUE)
|
|
else:
|
|
clone = node.clone()
|
|
for orig_leaf, clone_leaf in zip(node.leaves(), clone.leaves()):
|
|
pytree_utils.CopyYapfAnnotations(orig_leaf, clone_leaf)
|
|
new_node = pytree.Node(syms.atom, [lparen, clone, rparen])
|
|
node.replace(new_node)
|
|
_AppendFirstLeafTokenSubtype(clone, format_token.Subtype.DICTIONARY_VALUE)
|
|
|
|
|
|
def _IsAExprOperator(node):
|
|
return isinstance(node, pytree.Leaf) and node.value in {'+', '-'}
|
|
|
|
|
|
def _IsMExprOperator(node):
|
|
return isinstance(node,
|
|
pytree.Leaf) and node.value in {'*', '/', '%', '//', '@'}
|
|
|
|
|
|
def _IsSimpleExpression(node):
|
|
"""A node with only leafs as children."""
|
|
return all(isinstance(child, pytree.Leaf) for child in node.children)
|