Beispiel #1
0
def _StronglyConnectedCompOp(op):
  if (len(op.children[1].children) == 2 and
      pytree_utils.NodeName(op.children[1]) == 'comp_op'):
    if (pytree_utils.FirstLeafNode(op.children[1]).value == 'not' and
        pytree_utils.LastLeafNode(op.children[1]).value == 'in'):
      return True
    if (pytree_utils.FirstLeafNode(op.children[1]).value == 'is' and
        pytree_utils.LastLeafNode(op.children[1]).value == 'not'):
      return True
  if (isinstance(op.children[1], pytree.Leaf) and
      op.children[1].value in {'==', 'in'}):
    return True
  return False
Beispiel #2
0
 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)
Beispiel #3
0
    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
Beispiel #4
0
 def Visit_dictsetmaker(self, node):  # pylint: disable=invalid-name
     # dictsetmaker ::= (test ':' test (comp_for |
     #                                   (',' test ':' test)* [','])) |
     #                  (test (comp_for | (',' test)* [',']))
     dict_maker = False
     if len(node.children) > 1:
         index = 0
         while index < len(node.children):
             if node.children[index].type != token.COMMENT:
                 break
             index += 1
         if index < len(node.children):
             child = node.children[index + 1]
             dict_maker = isinstance(child,
                                     pytree.Leaf) and child.value == ':'
     last_was_comma = False
     last_was_colon = False
     for child in node.children:
         if pytree_utils.NodeName(child) == 'comp_for':
             _AppendFirstLeafTokenSubtype(
                 child, format_token.Subtype.DICT_SET_GENERATOR)
         else:
             if dict_maker:
                 if last_was_comma:
                     _AppendFirstLeafTokenSubtype(
                         child, format_token.Subtype.DICTIONARY_KEY)
                 elif last_was_colon:
                     if pytree_utils.NodeName(child) == 'power':
                         _AppendSubtypeRec(child, format_token.Subtype.NONE)
                     else:
                         _AppendFirstLeafTokenSubtype(
                             child, format_token.Subtype.DICTIONARY_VALUE)
                     if style.Get('INDENT_DICTIONARY_VALUE'):
                         _InsertPseudoParentheses(child)
             last_was_comma = isinstance(child,
                                         pytree.Leaf) and child.value == ','
             last_was_colon = isinstance(child,
                                         pytree.Leaf) and child.value == ':'
         self.Visit(child)
Beispiel #5
0
def _FindStmtParent(node):
  """Find the nearest parent of node that is a statement node.

  Arguments:
    node: node to start from

  Returns:
    Nearest parent (or node itself, if suitable).
  """
  if pytree_utils.NodeName(node) in _STATEMENT_NODES:
    return node
  else:
    return _FindStmtParent(node.parent)
Beispiel #6
0
 def HasDefaultOrNamedAssignSubtype(node):
   """Return True if the arg list has a named assign subtype."""
   if isinstance(node, pytree.Leaf):
     if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in
         pytree_utils.GetNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE,
                                        set())):
       return True
     return False
   has_subtype = False
   for child in node.children:
     if pytree_utils.NodeName(child) != 'arglist':
       has_subtype |= HasDefaultOrNamedAssignSubtype(child)
   return has_subtype
Beispiel #7
0
    def Visit_term(self, node):  # pylint: disable=invalid-name
        # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)*
        self.DefaultNodeVisit(node)
        _IncreasePenalty(node, TERM)

        index = 1
        while index < len(node.children) - 1:
            child = node.children[index]
            if pytree_utils.NodeName(child) in self._TERM_OPS:
                next_node = pytree_utils.FirstLeafNode(node.children[index +
                                                                     1])
                _SetSplitPenalty(next_node, TERM)
            index += 1
Beispiel #8
0
    def Visit_arith_expr(self, node):  # pylint: disable=invalid-name
        # arith_expr ::= term (('+'|'-') term)*
        self.DefaultNodeVisit(node)
        _IncreasePenalty(node, ARITH_EXPR)

        index = 1
        while index < len(node.children) - 1:
            child = node.children[index]
            if pytree_utils.NodeName(child) in self._ARITH_OPS:
                next_node = pytree_utils.FirstLeafNode(node.children[index +
                                                                     1])
                _SetSplitPenalty(next_node, ARITH_EXPR)
            index += 1
Beispiel #9
0
  def Visit_simple_stmt(self, node):
    # A 'simple_stmt' conveniently represents a non-compound Python statement,
    # i.e. a statement that does not contain other statements.

    # When compound nodes have a single statement as their suite, the parser
    # can leave it in the tree directly without creating a suite. But we have
    # to increase depth in these cases as well. However, don't increase the
    # depth of we have a simple_stmt that's a comment node. This represents a
    # standalone comment and in the case of it coming directly after the
    # funcdef, it is a "top" comment for the whole function.
    # TODO(eliben): add more relevant compound statements here.
    single_stmt_suite = (node.parent and pytree_utils.NodeName(node.parent) in {
        'if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'expect_clause',
        'with_stmt', 'funcdef', 'classdef'
    })
    is_comment_stmt = pytree_utils.NodeName(node.children[0]) == 'COMMENT'
    if single_stmt_suite and not is_comment_stmt:
      self._cur_depth += 1
    self._StartNewLine()
    self.DefaultNodeVisit(node)
    if single_stmt_suite and not is_comment_stmt:
      self._cur_depth -= 1
Beispiel #10
0
    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) == 'COLON':
                dict_maker = True

        if not comp_for and dict_maker:
            last_was_colon = False
            for child in node.children:
                if dict_maker:
                    if last_was_colon:
                        if style.Get('INDENT_DICTIONARY_VALUE'):
                            _InsertPseudoParentheses(child)
                        else:
                            _AppendFirstLeafTokenSubtype(
                                child, format_token.Subtype.DICTIONARY_VALUE)
                    elif (child is not None
                          and (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.
                        _AppendFirstLeafTokenSubtype(
                            child, format_token.Subtype.DICTIONARY_KEY)
                last_was_colon = pytree_utils.NodeName(child) == 'COLON'
Beispiel #11
0
 def Visit_trailer(self, node):  # pylint: disable=invalid-name
     # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
     self.DefaultNodeVisit(node)
     if node.children[0].value == '.':
         self._SetStronglyConnected(node.children[0], node.children[-1])
     elif node.children[0].value == '[':
         self._SetStronglyConnected(node.children[-1])
     elif len(node.children) == 2:
         # Don't split an empty argument list if at all possible.
         self._SetStronglyConnected(node.children[1])
     elif len(node.children) == 3:
         if pytree_utils.NodeName(node.children[1]) == 'NAME':
             # Don't split an argument list with one element if at all possible.
             self._SetStronglyConnected(node.children[1], node.children[2])
 def Visit_atom(self, node):  # pylint: disable=invalid-name
     # atom ::= ('(' [yield_expr|testlist_gexp] ')'
     #           '[' [listmaker] ']' |
     #           '{' [dictsetmaker] '}')
     self.DefaultNodeVisit(node)
     if node.children[0].value == '(':
         if node.children[-1].value == ')':
             if pytree_utils.NodeName(node.parent) == 'if_stmt':
                 _SetSplitPenalty(node.children[-1], UNBREAKABLE)
             else:
                 _SetSplitPenalty(node.children[-1], ATOM)
     elif node.children[0].value in '[{' and len(node.children) == 2:
         # Keep empty containers together if we can.
         _SetUnbreakable(node.children[-1])
Beispiel #13
0
 def Visit_funcdef(self, node):  # pylint: disable=invalid-name
     index = self._SetBlankLinesBetweenCommentAndClassFunc(node)
     if (py3compat.PY3 and node.prev_sibling
             and pytree_utils.NodeName(node.prev_sibling) == 'ASYNC'):
         # Move the number of blank lines to the async keyword.
         num_newlines = pytree_utils.GetNodeAnnotation(
             node.children[0], pytree_utils.Annotation.NEWLINES)
         self._SetNumNewlines(node.prev_sibling, num_newlines)
         self._SetNumNewlines(node.children[0], None)
     self.last_was_decorator = False
     self.function_level += 1
     for child in node.children[index:]:
         self.Visit(child)
     self.function_level -= 1
     self.last_was_class_or_function = True
Beispiel #14
0
    def DefaultNodeVisit(self, node):
        """Override the default visitor for Node.

    This will set the blank lines required if the last entity was a class or
    function.

    Arguments:
      node: (pytree.Node) The node to visit.
    """
        if self.last_was_class_or_function:
            if pytree_utils.NodeName(node) in _PYTHON_STATEMENTS:
                leaf = _GetFirstChildLeaf(node)
                self._SetNumNewlines(leaf, self._GetNumNewlines(leaf))
        self.last_was_class_or_function = False
        super(_BlankLineCalculator, self).DefaultNodeVisit(node)
Beispiel #15
0
    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, subtypes.DEFAULT_OR_NAMED_ASSIGN,
                           subtypes.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST)
        tname = False
        if not node.children:
            return

        _AppendFirstLeafTokenSubtype(node.children[0],
                                     subtypes.PARAMETER_START)
        _AppendLastLeafTokenSubtype(node.children[-1], subtypes.PARAMETER_STOP)

        tname = pytree_utils.NodeName(node.children[0]) == 'tname'
        for i in range(1, len(node.children)):
            prev_child = node.children[i - 1]
            child = node.children[i]
            if prev_child.type == grammar_token.COMMA:
                _AppendFirstLeafTokenSubtype(child, subtypes.PARAMETER_START)
            elif child.type == grammar_token.COMMA:
                _AppendLastLeafTokenSubtype(prev_child,
                                            subtypes.PARAMETER_STOP)

            if pytree_utils.NodeName(child) == 'tname':
                tname = True
                _SetArgListSubtype(child, subtypes.TYPED_NAME,
                                   subtypes.TYPED_NAME_ARG_LIST)
            elif child.type == grammar_token.COMMA:
                tname = False
            elif child.type == grammar_token.EQUAL and tname:
                _AppendTokenSubtype(child, subtype=subtypes.TYPED_NAME)
                tname = False
Beispiel #16
0
  def Visit_lambdef(self, node):  # pylint: disable=invalid-name
    # lambdef ::= 'lambda' [varargslist] ':' test
    # Loop over the lambda up to and including the colon.
    allow_multiline_lambdas = style.Get('ALLOW_MULTILINE_LAMBDAS')
    if not allow_multiline_lambdas:
      for child in node.children:
        if pytree_utils.NodeName(child) == 'COMMENT':
          if re.search(r'pylint:.*disable=.*\bg-long-lambda', child.value):
            allow_multiline_lambdas = True
            break

    if allow_multiline_lambdas:
      _SetExpressionPenalty(node, STRONGLY_CONNECTED)
    else:
      _SetExpressionPenalty(node, VERY_STRONGLY_CONNECTED)
Beispiel #17
0
  def Visit_lambdef(self, node):  # pylint: disable=invalid-name
    # lambdef ::= 'lambda' [varargslist] ':' test
    # Loop over the lambda up to and including the colon.
    allow_multiline_lambdas = style.Get('ALLOW_MULTILINE_LAMBDAS')
    if not allow_multiline_lambdas:
      for child in node.children:
        if pytree_utils.NodeName(child) == 'COMMENT':
          if re.search(r'pylint:.*disable=.*\bg-long-lambda', child.value):
            allow_multiline_lambdas = True
            break

    if allow_multiline_lambdas:
      _SetStronglyConnected(node)
    else:
      self._SetUnbreakableOnChildren(node)
    def Visit_trailer(self, node):  # pylint: disable=invalid-name
        for child in node.children:
            self.Visit(child)

        if len(node.children) != 3:
            return
        if node.children[0].type != grammar_token.LPAR:
            return

        if pytree_utils.NodeName(node.children[1]) == 'arglist':
            for child in node.children[1].children:
                pytree_utils.SetOpeningBracket(
                    pytree_utils.FirstLeafNode(child), node.children[0])
        else:
            pytree_utils.SetOpeningBracket(
                pytree_utils.FirstLeafNode(node.children[1]), node.children[0])
Beispiel #19
0
 def Visit_funcdef(self, node):  # pylint: disable=invalid-name
     # funcdef ::= 'def' NAME parameters ['->' test] ':' suite
     #
     # Can't break before the function name and before the colon. The parameters
     # are handled by child iteration.
     colon_idx = 1
     while pytree_utils.NodeName(node.children[colon_idx]) == 'simple_stmt':
         colon_idx += 1
     self._SetUnbreakable(node.children[colon_idx])
     while colon_idx < len(node.children):
         if (isinstance(node.children[colon_idx], pytree.Leaf)
                 and node.children[colon_idx].value == ':'):
             break
         colon_idx += 1
     self._SetUnbreakable(node.children[colon_idx])
     self.DefaultNodeVisit(node)
Beispiel #20
0
    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,
                                             subtypes.DICT_SET_GENERATOR)
            elif child.type in (grammar_token.COLON, grammar_token.DOUBLESTAR):
                dict_maker = True

        if not comp_for and dict_maker:
            last_was_colon = False
            unpacking = False
            for child in node.children:
                if child.type == grammar_token.DOUBLESTAR:
                    _AppendFirstLeafTokenSubtype(child,
                                                 subtypes.KWARGS_STAR_STAR)
                if last_was_colon:
                    if style.Get('INDENT_DICTIONARY_VALUE'):
                        _InsertPseudoParentheses(child)
                    else:
                        _AppendFirstLeafTokenSubtype(child,
                                                     subtypes.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,
                                                     subtypes.DICTIONARY_KEY)
                    _AppendSubtypeRec(child, subtypes.DICTIONARY_KEY_PART)
                last_was_colon = child.type == grammar_token.COLON
                if child.type == grammar_token.DOUBLESTAR:
                    unpacking = True
                elif last_was_colon:
                    unpacking = False
Beispiel #21
0
 def Visit_atom(self, node):  # pylint: disable=invalid-name
     # atom ::= ('(' [yield_expr|testlist_gexp] ')'
     #           '[' [listmaker] ']' |
     #           '{' [dictsetmaker] '}')
     self.DefaultNodeVisit(node)
     if node.children[0].value == '(':
         if node.children[0].lineno == node.children[-1].lineno:
             self._SetExpressionPenalty(node, CONTIGUOUS_LIST)
         if (pytree_utils.NodeName(node.parent) == 'if_stmt'
                 and node.children[-1].value == ')'):
             pytree_utils.SetNodeAnnotation(
                 node.children[-1], pytree_utils.Annotation.SPLIT_PENALTY,
                 UNBREAKABLE)
     elif node.children[0].value in '[{':
         # Keep empty containers together if we can.
         if len(node.children) == 2:
             self._SetStronglyConnected(node.children[-1])
Beispiel #22
0
  def _SetDefaultOrNamedAssignArgListSubtype(self, node):
    def HasDefaultOrNamedAssignSubtype(node):
      if isinstance(node, pytree.Leaf):
        if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in
            self._GetFirstLeafTokenSubtypes(node)):
          return True
        return False
      has_subtype = False
      for child in node.children:
        has_subtype |= HasDefaultOrNamedAssignSubtype(child)
      return has_subtype

    if HasDefaultOrNamedAssignSubtype(node):
      for child in node.children:
        if pytree_utils.NodeName(child) != 'COMMA':
          self._AppendFirstLeafTokenSubtype(
              child, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST)
def _FindNodeWithStandaloneLineParent(node):
  """Find a node whose parent is a 'standalone line' node.

  See the comment above _STANDALONE_LINE_NODES for more details.

  Arguments:
    node: node to start from

  Returns:
    Suitable node that's either the node itself or one of its ancestors.
  """
  if pytree_utils.NodeName(node.parent) in _STANDALONE_LINE_NODES:
    return node
  else:
    # This is guaranteed to terminate because 'file_input' is the root node of
    # any pytree.
    return _FindNodeWithStandaloneLineParent(node.parent)
Beispiel #24
0
def _DetermineMustSplitAnnotation(node):
    """Enforce a split in the list if the list ends with a comma."""
    if not (isinstance(node.children[-1], pytree.Leaf)
            and node.children[-1].value == ','):
        return
    num_children = len(node.children)
    index = 0
    while index < num_children - 1:
        child = node.children[index]
        if isinstance(child, pytree.Leaf) and child.value == ',':
            next_child = node.children[index + 1]
            if pytree_utils.NodeName(next_child) == 'COMMENT':
                index += 1
                if index >= num_children:
                    break
            _SetMustSplitOnFirstLeaf(node.children[index + 1])
        index += 1
Beispiel #25
0
 def Visit_atom(self, node):  # pylint: disable=invalid-name
   # atom ::= ('(' [yield_expr|testlist_gexp] ')'
   #           '[' [listmaker] ']' |
   #           '{' [dictsetmaker] '}')
   self.DefaultNodeVisit(node)
   if (node.children[0].value == '(' and
       not hasattr(node.children[0], 'is_pseudo')):
     if node.children[-1].value == ')':
       if pytree_utils.NodeName(node.parent) == 'if_stmt':
         _SetSplitPenalty(node.children[-1], STRONGLY_CONNECTED)
       else:
         if len(node.children) > 2:
           _SetSplitPenalty(pytree_utils.FirstLeafNode(node.children[1]), EXPR)
         _SetSplitPenalty(node.children[-1], ATOM)
   elif node.children[0].value in '[{' and len(node.children) == 2:
     # Keep empty containers together if we can.
     _SetUnbreakable(node.children[-1])
Beispiel #26
0
  def Visit_arglist(self, node):  # pylint: disable=invalid-name
    # arglist ::= argument (',' argument)* [',']
    if node.children[0].type == grammar_token.STAR:
      # Python 3 treats a star expression as a specific expression type.
      # Process it in that method.
      self.Visit_star_expr(node)
      return

    self.DefaultNodeVisit(node)

    for index in py3compat.range(1, len(node.children)):
      child = node.children[index]
      if isinstance(child, pytree.Leaf) and child.value == ',':
        _SetUnbreakable(child)

    for child in node.children:
      if pytree_utils.NodeName(child) == 'atom':
        _IncreasePenalty(child, CONNECTED)
Beispiel #27
0
 def Visit_trailer(self, node):  # pylint: disable=invalid-name
     # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
     self.DefaultNodeVisit(node)
     if node.children[0].value == '.':
         self._SetUnbreakableOnChildren(node,
                                        num_children=len(node.children))
     elif node.children[0].value == '[':
         for child in node.children:
             self._SetExpressionPenalty(node, SUBSCRIPT_LIST)
         self._SetUnbreakable(node.children[0])
         self._SetUnbreakable(node.children[-1])
     elif len(node.children) == 2:
         # Don't split an empty argument list if at all possible.
         self._SetStronglyConnected(node.children[1])
     elif len(node.children) == 3:
         if pytree_utils.NodeName(node.children[1]) == 'NAME':
             # Don't split an argument list with one element if at all possible.
             self._SetStronglyConnected(node.children[1], node.children[2])
Beispiel #28
0
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):
            if node_subtype in pytree_utils.GetNodeAnnotation(
                    node, pytree_utils.Annotation.SUBTYPE, set()):
                return True
            return False
        has_subtype = False
        for child in node.children:
            if pytree_utils.NodeName(child) != 'arglist':
                has_subtype |= HasSubtype(child)
        return has_subtype

    if HasSubtype(node):
        for child in node.children:
            if pytree_utils.NodeName(child) != 'COMMA':
                _AppendFirstLeafTokenSubtype(child, list_subtype)
Beispiel #29
0
 def Visit_dictsetmaker(self, node):  # pylint: disable=invalid-name
     # dictsetmaker ::= (test ':' test (comp_for |
     #                                   (',' test ':' test)* [','])) |
     #                  (test (comp_for | (',' test)* [',']))
     dict_maker = (len(node.children) > 1
                   and isinstance(node.children[1], pytree.Leaf)
                   and node.children[1].value == ':')
     last_was_comma = False
     for child in node.children:
         self.Visit(child)
         if pytree_utils.NodeName(child) == 'comp_for':
             self._SetFirstLeafTokenSubtype(
                 child, format_token.Subtype.DICT_SET_GENERATOR)
         else:
             if dict_maker and last_was_comma:
                 self._SetFirstLeafTokenSubtype(
                     child, format_token.Subtype.DICTIONARY_KEY)
             last_was_comma = isinstance(child,
                                         pytree.Leaf) and child.value == ','
Beispiel #30
0
def _DetermineMustSplitAnnotation(node):
  """Enforce a split in the list if the list ends with a comma."""
  if not _ContainsComments(node):
    if sum(1 for ch in node.children
           if pytree_utils.NodeName(ch) == 'COMMA') < 2:
      return
    if (not isinstance(node.children[-1], pytree.Leaf) or
        node.children[-1].value != ','):
      return
  num_children = len(node.children)
  index = 0
  _SetMustSplitOnFirstLeaf(node.children[0])
  while index < num_children - 1:
    child = node.children[index]
    if isinstance(child, pytree.Leaf) and child.value == ',':
      next_child = node.children[index + 1]
      if next_child.type == grammar_token.COMMENT:
        index += 1
        if index >= num_children - 1:
          break
      _SetMustSplitOnFirstLeaf(node.children[index + 1])
    index += 1