docs: def _doc_parse(doc, module=None, qualname=None):
      """ Parse docstring into a dict
  
      :rtype: data.FDocstring
      """
  
      # Build the rex
      known_tags = {
          'param': 'arg',
          'type': 'arg-type',
          'return': 'ret',
          'returns': 'ret',
          'rtype': 'ret-type',
          'exception': 'exc',
          'except': 'exc',
          'raise': 'exc',
          'raises': 'exc',
      }
      tag_rex = re.compile(r'^\s*:(' + '|'.join(map(re.escape, known_tags)) + r')\s*(\S+)?\s*:', re.MULTILINE)
  
      # Match tags
      collect_args = {}
      collect_ret = {}
      doc_args = []
      doc_exc = []
      for m in reversed(list(tag_rex.finditer(doc))):
          # Fetch data
          tag, arg = m.groups()
          tag = known_tags[tag]  # Normalized tag name
  
          # Fetch docstring part
          value = doc[m.end():].strip()  # Copy text after the tag
          doc = doc[:m.start()].strip()  # truncate the string
  
          # Handle tag: collect data
          if tag == 'exc':
              doc_exc.append(data.ExceptionDoc(arg, value))
          elif tag in ('ret', 'ret-type'):
              # Collect fields 1 by 1
              collect_ret[{'ret': 'doc', 'ret-type': 'type'}[tag]] = value
          elif tag in ('arg', 'arg-type'):
              # Init new collection
              if arg not in collect_args:
                  doc_args.append(arg)  # add name for now, then map() replace with classes
                  collect_args[arg] = {}
              # Collect fields 1 by 1
              collect_args[arg][{'arg': 'doc', 'arg-type': 'type'}[tag]] = value
          else:
              raise AssertionError('Unknown tag type: {}'.format(tag))
  
      # Merge collected data
      doc_ret = data.ValueDoc(**collect_ret) if collect_ret else None
      doc_args = map(lambda name: data.ArgumentDoc(name=name, **collect_args[name]), collect_args)
  
      # Finish
      return data.FDocstring(module=module, qualname=qualname, doc=doc, args=doc_args, exc=doc_exc, ret=doc_ret)