parameters: (formatted_data)
return_statement: return result
docstring: Recursively builds a dictionary tree out of a string using the
      following rules:
      Parameter lists: Token(Arguments...)  become Dictionary entries:
                       Token:Arguments...
      Any parameter list that is a string or list of strings gets saved as
      such.
      This will return a dictionary (even if given a simple string),
      unless given a list of strings. The is_simple_string and is_list detection
      functions and convert_key_to_string and convert_keys_to_list functions
      can be used to process the results further if necessary.
      @param formatted_data - A string of data formatted by the
                              AZCodeGenerator C++ Parser
      @return A dictionary containing all the data parsed out of the
              incoming string.
docstring_summary: Recursively builds a dictionary tree out of a string using the
      following rules:
      Parameter lists: Token(Arguments...)  become Dictionary entries:
                       Token:Arguments...
      Any parameter list that is a string or list of strings gets saved as
      such.
      This will return a dictionary (even if given a simple string),
      unless given a list of strings. The is_simple_string and is_list detection
      functions and convert_key_to_string and convert_keys_to_list functions
      can be used to process the results further if necessary.
docstring_tokens: Recursively builds a dictionary tree out of a string using the following rules : Parameter lists : Token ( Arguments ... ) become Dictionary entries : Token : Arguments ... Any parameter list that is a string or list of strings gets saved as such . This will return a dictionary ( even if given a simple string ) unless given a list of strings . The is_simple_string and is_list detection functions and convert_key_to_string and convert_keys_to_list functions can be used to process the results further if necessary .
function: def build_tree_from_string(formatted_data):
      """ Recursively builds a dictionary tree out of a string using the
      following rules:
      Parameter lists: Token(Arguments...)  become Dictionary entries:
                       Token:Arguments...
      Any parameter list that is a string or list of strings gets saved as
      such.
      This will return a dictionary (even if given a simple string),
      unless given a list of strings. The is_simple_string and is_list detection
      functions and convert_key_to_string and convert_keys_to_list functions
      can be used to process the results further if necessary.
      @param formatted_data - A string of data formatted by the
                              AZCodeGenerator C++ Parser
      @return A dictionary containing all the data parsed out of the
              incoming string.
      """
      # must maintain key order, in case we convert the keys to a list
      result = OrderedDict() 
  
      # The AZCodeGen system can produce empty parameter lists
      # early detection will prevent python crashes
      if formatted_data is None:
          return None
  
      # This seems to happen when someone adds multiple of the same tag
      if not isinstance(formatted_data, str) and not isinstance(formatted_data, str):
          raise TypeError('Expecting string value, got {} ({})\nDid you add multiple of the same tag to an annotation?'.format(type(formatted_data), formatted_data))
  
      # remove external whitespace
      formatted_data = formatted_data.strip()
      # strip surrounding {}s used in initializer_list<>s
      if formatted_data and formatted_data[0] == '{':
          formatted_data = re.sub(r'^\{(.+)\}$', r'\1', formatted_data)
          # remove internal whitespace
          formatted_data = formatted_data.strip()
  
      # The AZCodeGen system can produce empty strings as parameter lists
      # Early detection will speed up execution
      if not formatted_data:
          return None
  
      # AZCodeGen allows spaces, commas, and tabs to be used as major
      # delimiters
      # in lists
      delimiters = " ,\t"
  
      # terminal case (Simple Token)
      if is_simple_token(formatted_data, delimiters):
          result[formatted_data] = None
      # recursive case (New Parameter)
      elif is_token_and_params(formatted_data, delimiters):
          tag = extract_tag(formatted_data, delimiters)
          params = build_tree_from_string(extract_parameters(formatted_data))
          template_params = extract_template_params(formatted_data)
          # Determine if we can flatten the parameter list into a string
          # or a list of strings
          if not isinstance(params, list):
              if is_simple_string(params):
                  params = convert_key_to_string(params)
              elif is_list(params):
                  params = convert_keys_to_list(params)
          
          if template_params:
              result[tag] = {
                  'params': params ,
                  'template_params': template_params,
              }
          else:
              result[tag] = params
          
      # There are multiple tokens At This Level.
      # Separate and parse them individually.
      else:
          args = split_on_major_delimiter(formatted_data, delimiters)
          trees = []
          for arg in args:
              tree = build_tree_from_string(arg)
              trees.append(tree)
  
          # intercept simple lists immediately (this is necessary to prevent duplicate list items from being coalesced
          # into a dictionary)
          if all(is_simple_string(tree) for tree in trees):
              return [convert_key_to_string(tree) for tree in trees]
  
          # pre-format the result dict, if there are multiple values at a key
          # ensure that the result value will be a list
          for tree in trees:
              for tag, value in tree.items():
                  if tag in result and not isinstance(result[tag], list):
                      result[tag] = []
                  elif tag not in result:
                      result[tag] = None
  
          # coalesce value trees into the result
          for tree in trees:
              for tag, value in tree.items():
                  if isinstance(result[tag], list):
                      result[tag].append(value)
                  else:
                      result[tag] = value
  
      return result
function_tokens: def build_tree_from_string ( formatted_data ) : # must maintain key order, in case we convert the keys to a list result = OrderedDict ( ) # The AZCodeGen system can produce empty parameter lists # early detection will prevent python crashes if formatted_data is None : return None # This seems to happen when someone adds multiple of the same tag if not isinstance ( formatted_data , str ) and not isinstance ( formatted_data , str ) : raise TypeError ( 'Expecting string value, got {} ({})\nDid you add multiple of the same tag to an annotation?' . format ( type ( formatted_data ) , formatted_data ) ) # remove external whitespace formatted_data = formatted_data . strip ( ) # strip surrounding {}s used in initializer_list<>s if formatted_data and formatted_data [ 0 ] == '{' : formatted_data = re . sub ( r'^\{(.+)\}$' , r'\1' , formatted_data ) # remove internal whitespace formatted_data = formatted_data . strip ( ) # The AZCodeGen system can produce empty strings as parameter lists # Early detection will speed up execution if not formatted_data : return None # AZCodeGen allows spaces, commas, and tabs to be used as major # delimiters # in lists delimiters = " ,\t" # terminal case (Simple Token) if is_simple_token ( formatted_data , delimiters ) : result [ formatted_data ] = None # recursive case (New Parameter) elif is_token_and_params ( formatted_data , delimiters ) : tag = extract_tag ( formatted_data , delimiters ) params = build_tree_from_string ( extract_parameters ( formatted_data ) ) template_params = extract_template_params ( formatted_data ) # Determine if we can flatten the parameter list into a string # or a list of strings if not isinstance ( params , list ) : if is_simple_string ( params ) : params = convert_key_to_string ( params ) elif is_list ( params ) : params = convert_keys_to_list ( params ) if template_params : result [ tag ] = { 'params' : params , 'template_params' : template_params , } else : result [ tag ] = params # There are multiple tokens At This Level. # Separate and parse them individually. else : args = split_on_major_delimiter ( formatted_data , delimiters ) trees = [ ] for arg in args : tree = build_tree_from_string ( arg ) trees . append ( tree ) # intercept simple lists immediately (this is necessary to prevent duplicate list items from being coalesced # into a dictionary) if all ( is_simple_string ( tree ) for tree in trees ) : return [ convert_key_to_string ( tree ) for tree in trees ] # pre-format the result dict, if there are multiple values at a key # ensure that the result value will be a list for tree in trees : for tag , value in tree . items ( ) : if tag in result and not isinstance ( result [ tag ] , list ) : result [ tag ] = [ ] elif tag not in result : result [ tag ] = None # coalesce value trees into the result for tree in trees : for tag , value in tree . items ( ) : if isinstance ( result [ tag ] , list ) : result [ tag ] . append ( value ) else : result [ tag ] = value return result