(root)/
Python-3.12.0/
Tools/
c-analyzer/
c_parser/
parser/
_global.py
       1  import re
       2  
       3  from ._regexes import (
       4      GLOBAL as _GLOBAL,
       5  )
       6  from ._common import (
       7      log_match,
       8      parse_var_decl,
       9      set_capture_groups,
      10  )
      11  from ._compound_decl_body import DECL_BODY_PARSERS
      12  from ._func_body import parse_function_statics as parse_function_body
      13  
      14  
      15  GLOBAL = set_capture_groups(_GLOBAL, (
      16      'EMPTY',
      17      'COMPOUND_LEADING',
      18      'COMPOUND_KIND',
      19      'COMPOUND_NAME',
      20      'FORWARD_KIND',
      21      'FORWARD_NAME',
      22      'MAYBE_INLINE_ACTUAL',
      23      'TYPEDEF_DECL',
      24      'TYPEDEF_FUNC_PARAMS',
      25      'VAR_STORAGE',
      26      'FUNC_INLINE',
      27      'VAR_DECL',
      28      'FUNC_PARAMS',
      29      'FUNC_DELIM',
      30      'FUNC_LEGACY_PARAMS',
      31      'VAR_INIT',
      32      'VAR_ENDING',
      33  ))
      34  GLOBAL_RE = re.compile(rf'^ \s* {GLOBAL}', re.VERBOSE)
      35  
      36  
      37  def parse_globals(source, anon_name):
      38      for srcinfo in source:
      39          m = GLOBAL_RE.match(srcinfo.text)
      40          if not m:
      41              # We need more text.
      42              continue
      43          for item in _parse_next(m, srcinfo, anon_name):
      44              if callable(item):
      45                  parse_body = item
      46                  yield from parse_body(source)
      47              else:
      48                  yield item
      49      else:
      50          # We ran out of lines.
      51          if srcinfo is not None:
      52              srcinfo.done()
      53          return
      54  
      55  
      56  def _parse_next(m, srcinfo, anon_name):
      57      (
      58       empty,
      59       # compound type decl (maybe inline)
      60       compound_leading, compound_kind, compound_name,
      61       forward_kind, forward_name, maybe_inline_actual,
      62       # typedef
      63       typedef_decl, typedef_func_params,
      64       # vars and funcs
      65       storage, func_inline, decl,
      66       func_params, func_delim, func_legacy_params,
      67       var_init, var_ending,
      68       ) = m.groups()
      69      remainder = srcinfo.text[m.end():]
      70  
      71      if empty:
      72          log_match('global empty', m)
      73          srcinfo.advance(remainder)
      74  
      75      elif maybe_inline_actual:
      76          log_match('maybe_inline_actual', m)
      77          # Ignore forward declarations.
      78          # XXX Maybe return them too (with an "isforward" flag)?
      79          if not maybe_inline_actual.strip().endswith(';'):
      80              remainder = maybe_inline_actual + remainder
      81          yield srcinfo.resolve(forward_kind, None, forward_name)
      82          if maybe_inline_actual.strip().endswith('='):
      83              # We use a dummy prefix for a fake typedef.
      84              # XXX Ideally this case would not be caught by MAYBE_INLINE_ACTUAL.
      85              _, name, data = parse_var_decl(f'{forward_kind} {forward_name} fake_typedef_{forward_name}')
      86              yield srcinfo.resolve('typedef', data, name, parent=None)
      87              remainder = f'{name} {remainder}'
      88          srcinfo.advance(remainder)
      89  
      90      elif compound_kind:
      91          kind = compound_kind
      92          name = compound_name or anon_name('inline-')
      93          # Immediately emit a forward declaration.
      94          yield srcinfo.resolve(kind, name=name, data=None)
      95  
      96          # un-inline the decl.  Note that it might not actually be inline.
      97          # We handle the case in the "maybe_inline_actual" branch.
      98          srcinfo.nest(
      99              remainder,
     100              f'{compound_leading or ""} {compound_kind} {name}',
     101          )
     102          def parse_body(source):
     103              _parse_body = DECL_BODY_PARSERS[compound_kind]
     104  
     105              data = []  # members
     106              ident = f'{kind} {name}'
     107              for item in _parse_body(source, anon_name, ident):
     108                  if item.kind == 'field':
     109                      data.append(item)
     110                  else:
     111                      yield item
     112              # XXX Should "parent" really be None for inline type decls?
     113              yield srcinfo.resolve(kind, data, name, parent=None)
     114  
     115              srcinfo.resume()
     116          yield parse_body
     117  
     118      elif typedef_decl:
     119          log_match('typedef', m)
     120          kind = 'typedef'
     121          _, name, data = parse_var_decl(typedef_decl)
     122          if typedef_func_params:
     123              return_type = data
     124              # This matches the data for func declarations.
     125              data = {
     126                  'storage': None,
     127                  'inline': None,
     128                  'params': f'({typedef_func_params})',
     129                  'returntype': return_type,
     130                  'isforward': True,
     131              }
     132          yield srcinfo.resolve(kind, data, name, parent=None)
     133          srcinfo.advance(remainder)
     134  
     135      elif func_delim or func_legacy_params:
     136          log_match('function', m)
     137          kind = 'function'
     138          _, name, return_type = parse_var_decl(decl)
     139          func_params = func_params or func_legacy_params
     140          data = {
     141              'storage': storage,
     142              'inline': func_inline,
     143              'params': f'({func_params})',
     144              'returntype': return_type,
     145              'isforward': func_delim == ';',
     146          }
     147  
     148          yield srcinfo.resolve(kind, data, name, parent=None)
     149          srcinfo.advance(remainder)
     150  
     151          if func_delim == '{' or func_legacy_params:
     152              def parse_body(source):
     153                  yield from parse_function_body(source, name, anon_name)
     154              yield parse_body
     155  
     156      elif var_ending:
     157          log_match('global variable', m)
     158          kind = 'variable'
     159          _, name, vartype = parse_var_decl(decl)
     160          data = {
     161              'storage': storage,
     162              'vartype': vartype,
     163          }
     164          yield srcinfo.resolve(kind, data, name, parent=None)
     165  
     166          if var_ending == ',':
     167              # It was a multi-declaration, so queue up the next one.
     168              _, qual, typespec, _ = vartype.values()
     169              remainder = f'{storage or ""} {qual or ""} {typespec} {remainder}'
     170          srcinfo.advance(remainder)
     171  
     172          if var_init:
     173              _data = f'{name} = {var_init.strip()}'
     174              yield srcinfo.resolve('statement', _data, name=None)
     175  
     176      else:
     177          # This should be unreachable.
     178          raise NotImplementedError