nodes: 0, module; 1, function_definition; 2, function_name:do_minus; 3, parameters; 4, block; 5, identifier:self; 6, identifier:parser; 7, identifier:group; 8, expression_statement; 9, expression_statement; 10, expression_statement; 11, for_statement; 12, if_statement; 13, return_statement; 14, string:'''This filter sorts nodes in a flat group into "required", "default",
          and "banned" subgroups based on the presence of plus and minus nodes.
          '''; 15, assignment; 16, assignment; 17, identifier:node; 18, identifier:group; 19, block; 20, comparison_operator:next_not is not None; 21, comment:# Remove the empty NotGroup; 22, block; 23, identifier:grouper; 24, identifier:grouper; 25, call; 26, identifier:next_not; 27, None; 28, if_statement; 29, identifier:next_not; 30, None; 31, expression_statement; 32, attribute; 33, argument_list; 34, call; 35, block; 36, else_clause; 37, call; 38, identifier:group; 39, identifier:__class__; 40, identifier:isinstance; 41, argument_list; 42, if_statement; 43, expression_statement; 44, expression_statement; 45, comment:# Nodes with children: search for nested Minus nodes; 46, block; 47, attribute; 48, argument_list; 49, identifier:node; 50, attribute; 51, comparison_operator:next_not is not None; 52, comment:# Two Minuses in a row; skip the second one; 53, block; 54, assignment; 55, call; 56, if_statement; 57, if_statement; 58, identifier:grouper; 59, identifier:pop; 60, identifier:self; 61, identifier:Minus; 62, identifier:next_not; 63, None; 64, continue_statement; 65, identifier:next_not; 66, call; 67, attribute; 68, argument_list; 69, call; 70, block; 71, comparison_operator:next_not is not None; 72, block; 73, else_clause; 74, attribute; 75, argument_list; 76, identifier:grouper; 77, identifier:append; 78, identifier:next_not; 79, identifier:isinstance; 80, argument_list; 81, expression_statement; 82, identifier:next_not; 83, None; 84, expression_statement; 85, expression_statement; 86, block; 87, attribute; 88, identifier:NotGroup; 89, identifier:node; 90, attribute; 91, assignment; 92, call; 93, assignment; 94, expression_statement; 95, attribute; 96, identifier:syntax; 97, attribute; 98, identifier:GroupNode; 99, identifier:node; 100, call; 101, attribute; 102, argument_list; 103, identifier:next_not; 104, None; 105, call; 106, identifier:whoosh; 107, identifier:qparser; 108, attribute; 109, identifier:syntax; 110, attribute; 111, argument_list; 112, identifier:next_not; 113, identifier:append; 114, identifier:node; 115, attribute; 116, argument_list; 117, identifier:whoosh; 118, identifier:qparser; 119, identifier:self; 120, identifier:do_minus; 121, identifier:parser; 122, identifier:node; 123, identifier:grouper; 124, identifier:append; 125, identifier:node
code: def do_minus(self, parser, group):
          '''This filter sorts nodes in a flat group into "required", "default",
          and "banned" subgroups based on the presence of plus and minus nodes.
          '''
          grouper = group.__class__()
          
          next_not = None
          for node in group:
              if isinstance(node, self.Minus):
                  if next_not is not None:
                      # Two Minuses in a row; skip the second one
                      continue
                  next_not = whoosh.qparser.syntax.NotGroup()
                  grouper.append(next_not)
              else:
                  # Nodes with children: search for nested Minus nodes
                  if isinstance(node, whoosh.qparser.syntax.GroupNode):
                      node = self.do_minus(parser, node)
                  if next_not is not None:
                      next_not.append(node)
                      next_not = None
                  else:
                      grouper.append(node)
          if next_not is not None:
              # Remove the empty NotGroup
              grouper.pop()
          
          return grouper