nodes: 0, module; 1, function_definition; 2, function_name:parse_tags; 3, parameters; 4, block; 5, identifier:tagstring; 6, expression_statement; 7, if_statement; 8, expression_statement; 9, expression_statement; 10, expression_statement; 11, comment:# Defer splitting of non-quoted sections until we know if there are; 12, comment:# any unquoted commas.; 13, expression_statement; 14, expression_statement; 15, try_statement; 16, if_statement; 17, expression_statement; 18, expression_statement; 19, return_statement; 20, comment:"""
      Parses tag input, with multiple word input being activated and
      delineated by commas and double quotes. Quotes take precedence, so
      they may contain commas.
  
      Returns a sorted list of unique tag names.
  
      Adapted from Taggit, modified to not split strings on spaces.
  
      Ported from Jonathan Buchanan's `django-tagging
      <http://django-tagging.googlecode.com/>`_
      """; 21, not_operator; 22, block; 23, assignment; 24, assignment; 25, assignment; 26, assignment; 27, assignment; 28, block; 29, except_clause; 30, identifier:to_be_split; 31, block; 32, assignment; 33, call; 34, identifier:words; 35, identifier:tagstring; 36, return_statement; 37, identifier:tagstring; 38, call; 39, identifier:words; 40, list; 41, identifier:buffer; 42, list; 43, identifier:to_be_split; 44, list; 45, identifier:i; 46, call; 47, while_statement; 48, identifier:StopIteration; 49, comment:# If we were parsing an open quote which was never closed treat; 50, comment:# the buffer as unquoted.; 51, block; 52, for_statement; 53, identifier:words; 54, call; 55, attribute; 56, argument_list; 57, list; 58, identifier:force_text; 59, argument_list; 60, identifier:iter; 61, argument_list; 62, True; 63, block; 64, if_statement; 65, identifier:chunk; 66, identifier:to_be_split; 67, block; 68, identifier:list; 69, argument_list; 70, identifier:words; 71, identifier:sort; 72, identifier:tagstring; 73, identifier:tagstring; 74, expression_statement; 75, if_statement; 76, identifier:buffer; 77, block; 78, expression_statement; 79, call; 80, assignment; 81, comparison_operator:c == '"'; 82, block; 83, else_clause; 84, expression_statement; 85, call; 86, identifier:set; 87, argument_list; 88, identifier:c; 89, call; 90, identifier:c; 91, string:'"'; 92, if_statement; 93, expression_statement; 94, while_statement; 95, if_statement; 96, block; 97, call; 98, attribute; 99, argument_list; 100, identifier:words; 101, attribute; 102, argument_list; 103, identifier:buffer; 104, block; 105, assignment; 106, comparison_operator:c != '"'; 107, block; 108, identifier:buffer; 109, block; 110, expression_statement; 111, attribute; 112, argument_list; 113, identifier:words; 114, identifier:extend; 115, call; 116, identifier:six; 117, identifier:next; 118, identifier:i; 119, expression_statement; 120, expression_statement; 121, identifier:c; 122, call; 123, identifier:c; 124, string:'"'; 125, expression_statement; 126, expression_statement; 127, expression_statement; 128, if_statement; 129, expression_statement; 130, call; 131, identifier:to_be_split; 132, identifier:append; 133, call; 134, identifier:split_strip; 135, argument_list; 136, call; 137, assignment; 138, attribute; 139, argument_list; 140, call; 141, assignment; 142, assignment; 143, identifier:word; 144, block; 145, assignment; 146, attribute; 147, argument_list; 148, attribute; 149, argument_list; 150, identifier:chunk; 151, subscript; 152, attribute; 153, argument_list; 154, identifier:buffer; 155, list; 156, identifier:six; 157, identifier:next; 158, identifier:i; 159, attribute; 160, argument_list; 161, identifier:c; 162, call; 163, identifier:word; 164, call; 165, expression_statement; 166, identifier:buffer; 167, list; 168, identifier:buffer; 169, identifier:append; 170, identifier:c; 171, string; 172, identifier:join; 173, identifier:buffer; 174, attribute; 175, string; 176, identifier:to_be_split; 177, identifier:append; 178, call; 179, identifier:buffer; 180, identifier:append; 181, identifier:c; 182, attribute; 183, argument_list; 184, attribute; 185, argument_list; 186, call; 187, identifier:settings; 188, identifier:TAGGIT_SELECTIZE; 189, string_content:DELIMITER; 190, attribute; 191, argument_list; 192, identifier:six; 193, identifier:next; 194, identifier:i; 195, call; 196, identifier:strip; 197, attribute; 198, argument_list; 199, string; 200, identifier:join; 201, identifier:buffer; 202, attribute; 203, argument_list; 204, identifier:words; 205, identifier:append; 206, identifier:word; 207, string; 208, identifier:join; 209, identifier:buffer
code: def parse_tags(tagstring):
      """
      Parses tag input, with multiple word input being activated and
      delineated by commas and double quotes. Quotes take precedence, so
      they may contain commas.
  
      Returns a sorted list of unique tag names.
  
      Adapted from Taggit, modified to not split strings on spaces.
  
      Ported from Jonathan Buchanan's `django-tagging
      <http://django-tagging.googlecode.com/>`_
      """
      if not tagstring:
          return []
  
      tagstring = force_text(tagstring)
  
      words = []
      buffer = []
      # Defer splitting of non-quoted sections until we know if there are
      # any unquoted commas.
      to_be_split = []
      i = iter(tagstring)
      try:
          while True:
              c = six.next(i)
              if c == '"':
                  if buffer:
                      to_be_split.append(''.join(buffer))
                      buffer = []
                  c = six.next(i)
                  while c != '"':
                      buffer.append(c)
                      c = six.next(i)
                  if buffer:
                      word = ''.join(buffer).strip()
                      if word:
                          words.append(word)
                      buffer = []
              else:
                  buffer.append(c)
      except StopIteration:
          # If we were parsing an open quote which was never closed treat
          # the buffer as unquoted.
          if buffer:
              to_be_split.append(''.join(buffer))
      if to_be_split:
          for chunk in to_be_split:
              words.extend(split_strip(chunk, settings.TAGGIT_SELECTIZE['DELIMITER']))
      words = list(set(words))
      words.sort()
      return words