1  import re
       2  
       3  from . import info as _info
       4  from .parser._regexes import SIMPLE_TYPE
       5  
       6  
       7  _KIND = _info.KIND
       8  
       9  
      10  def match_storage(decl, expected):
      11      default = _info.get_default_storage(decl)
      12      #assert default
      13      if expected is None:
      14          expected = {default}
      15      elif isinstance(expected, str):
      16          expected = {expected or default}
      17      elif not expected:
      18          expected = _info.STORAGE
      19      else:
      20          expected = {v or default for v in expected}
      21      storage = _info.get_effective_storage(decl, default=default)
      22      return storage in expected
      23  
      24  
      25  ##################################
      26  # decl matchers
      27  
      28  def is_type_decl(item):
      29      return _KIND.is_type_decl(item.kind)
      30  
      31  
      32  def is_decl(item):
      33      return _KIND.is_decl(item.kind)
      34  
      35  
      36  def is_pots(typespec, *,
      37              _regex=re.compile(rf'^{SIMPLE_TYPE}$', re.VERBOSE),
      38              ):
      39  
      40      if not typespec:
      41          return None
      42      if type(typespec) is not str:
      43          _, _, _, typespec, _ = _info.get_parsed_vartype(typespec)
      44      return _regex.match(typespec) is not None
      45  
      46  
      47  def is_funcptr(vartype):
      48      if not vartype:
      49          return None
      50      _, _, _, _, abstract = _info.get_parsed_vartype(vartype)
      51      return _is_funcptr(abstract)
      52  
      53  
      54  def _is_funcptr(declstr):
      55      if not declstr:
      56          return None
      57      # XXX Support "(<name>*)(".
      58      return '(*)(' in declstr.replace(' ', '')
      59  
      60  
      61  def is_forward_decl(decl):
      62      if decl.kind is _KIND.TYPEDEF:
      63          return False
      64      elif is_type_decl(decl):
      65          return not decl.data
      66      elif decl.kind is _KIND.FUNCTION:
      67          # XXX This doesn't work with ParsedItem.
      68          return decl.signature.isforward
      69      elif decl.kind is _KIND.VARIABLE:
      70          # No var decls are considered forward (or all are...).
      71          return False
      72      else:
      73          raise NotImplementedError(decl)
      74  
      75  
      76  def can_have_symbol(decl):
      77      return decl.kind in (_KIND.VARIABLE, _KIND.FUNCTION)
      78  
      79  
      80  def has_external_symbol(decl):
      81      if not can_have_symbol(decl):
      82          return False
      83      if _info.get_effective_storage(decl) != 'extern':
      84          return False
      85      if decl.kind is _KIND.FUNCTION:
      86          return not decl.signature.isforward
      87      else:
      88          # It must be a variable, which can only be implicitly extern here.
      89          return decl.storage != 'extern'
      90  
      91  
      92  def has_internal_symbol(decl):
      93      if not can_have_symbol(decl):
      94          return False
      95      return _info.get_actual_storage(decl) == 'static'
      96  
      97  
      98  def is_external_reference(decl):
      99      if not can_have_symbol(decl):
     100          return False
     101      # We have to check the declared storage rather tnan the effective.
     102      if decl.storage != 'extern':
     103          return False
     104      if decl.kind is _KIND.FUNCTION:
     105          return decl.signature.isforward
     106      # Otherwise it's a variable.
     107      return True
     108  
     109  
     110  def is_local_var(decl):
     111      if not decl.kind is _KIND.VARIABLE:
     112          return False
     113      return True if decl.parent else False
     114  
     115  
     116  def is_global_var(decl):
     117      if not decl.kind is _KIND.VARIABLE:
     118          return False
     119      return False if decl.parent else True
     120  
     121  
     122  ##################################
     123  # filtering with matchers
     124  
     125  def filter_by_kind(items, kind):
     126      if kind == 'type':
     127          kinds = _KIND._TYPE_DECLS
     128      elif kind == 'decl':
     129          kinds = _KIND._TYPE_DECLS
     130      try:
     131          okay = kind in _KIND
     132      except TypeError:
     133          kinds = set(kind)
     134      else:
     135          kinds = {kind} if okay else set(kind)
     136      for item in items:
     137          if item.kind in kinds:
     138              yield item
     139  
     140  
     141  ##################################
     142  # grouping with matchers
     143  
     144  def group_by_category(decls, categories, *, ignore_non_match=True):
     145      collated = {}
     146      for decl in decls:
     147          # Matchers should be mutually exclusive.  (First match wins.)
     148          for category, match in categories.items():
     149              if match(decl):
     150                  if category not in collated:
     151                      collated[category] = [decl]
     152                  else:
     153                      collated[category].append(decl)
     154                  break
     155          else:
     156              if not ignore_non_match:
     157                  raise Exception(f'no match for {decl!r}')
     158      return collated
     159  
     160  
     161  def group_by_kind(items):
     162      collated = {kind: [] for kind in _KIND}
     163      for item in items:
     164          try:
     165              collated[item.kind].append(item)
     166          except KeyError:
     167              raise ValueError(f'unsupported kind in {item!r}')
     168      return collated
     169  
     170  
     171  def group_by_kinds(items):
     172      # Collate into kind groups (decl, type, etc.).
     173      collated = {_KIND.get_group(k): [] for k in _KIND}
     174      for item in items:
     175          group = _KIND.get_group(item.kind)
     176          collated[group].append(item)
     177      return collated