(root)/
Python-3.11.7/
Tools/
c-analyzer/
c_parser/
preprocessor/
__main__.py
       1  import logging
       2  import sys
       3  
       4  from c_common.scriptutil import (
       5      CLIArgSpec as Arg,
       6      add_verbosity_cli,
       7      add_traceback_cli,
       8      add_kind_filtering_cli,
       9      add_files_cli,
      10      add_failure_filtering_cli,
      11      add_commands_cli,
      12      process_args_by_key,
      13      configure_logger,
      14      get_prog,
      15      main_for_filenames,
      16  )
      17  from . import (
      18      errors as _errors,
      19      get_preprocessor as _get_preprocessor,
      20  )
      21  
      22  
      23  FAIL = {
      24      'err': _errors.ErrorDirectiveError,
      25      'deps': _errors.MissingDependenciesError,
      26      'os': _errors.OSMismatchError,
      27  }
      28  FAIL_DEFAULT = tuple(v for v in FAIL if v != 'os')
      29  
      30  
      31  logger = logging.getLogger(__name__)
      32  
      33  
      34  ##################################
      35  # CLI helpers
      36  
      37  def add_common_cli(parser, *, get_preprocessor=_get_preprocessor):
      38      parser.add_argument('--macros', action='append')
      39      parser.add_argument('--incldirs', action='append')
      40      parser.add_argument('--same', action='append')
      41      process_fail_arg = add_failure_filtering_cli(parser, FAIL)
      42  
      43      def process_args(args, *, argv):
      44          ns = vars(args)
      45  
      46          process_fail_arg(args, argv=argv)
      47          ignore_exc = ns.pop('ignore_exc')
      48          # We later pass ignore_exc to _get_preprocessor().
      49  
      50          args.get_file_preprocessor = get_preprocessor(
      51              file_macros=ns.pop('macros'),
      52              file_incldirs=ns.pop('incldirs'),
      53              file_same=ns.pop('same'),
      54              ignore_exc=ignore_exc,
      55              log_err=print,
      56          )
      57      return process_args
      58  
      59  
      60  def _iter_preprocessed(filename, *,
      61                         get_preprocessor,
      62                         match_kind=None,
      63                         pure=False,
      64                         ):
      65      preprocess = get_preprocessor(filename)
      66      for line in preprocess(tool=not pure) or ():
      67          if match_kind is not None and not match_kind(line.kind):
      68              continue
      69          yield line
      70  
      71  
      72  #######################################
      73  # the commands
      74  
      75  def _cli_preprocess(parser, excluded=None, **prepr_kwargs):
      76      parser.add_argument('--pure', action='store_true')
      77      parser.add_argument('--no-pure', dest='pure', action='store_const', const=False)
      78      process_kinds = add_kind_filtering_cli(parser)
      79      process_common = add_common_cli(parser, **prepr_kwargs)
      80      parser.add_argument('--raw', action='store_true')
      81      process_files = add_files_cli(parser, excluded=excluded)
      82  
      83      return [
      84          process_kinds,
      85          process_common,
      86          process_files,
      87      ]
      88  
      89  
      90  def cmd_preprocess(filenames, *,
      91                     raw=False,
      92                     iter_filenames=None,
      93                     **kwargs
      94                     ):
      95      if 'get_file_preprocessor' not in kwargs:
      96          kwargs['get_file_preprocessor'] = _get_preprocessor()
      97      if raw:
      98          def show_file(filename, lines):
      99              for line in lines:
     100                  print(line)
     101                  #print(line.raw)
     102      else:
     103          def show_file(filename, lines):
     104              for line in lines:
     105                  linefile = ''
     106                  if line.filename != filename:
     107                      linefile = f' ({line.filename})'
     108                  text = line.data
     109                  if line.kind == 'comment':
     110                      text = '/* ' + line.data.splitlines()[0]
     111                      text += ' */' if '\n' in line.data else r'\n... */'
     112                  print(f' {line.lno:>4} {line.kind:10} | {text}')
     113  
     114      filenames = main_for_filenames(filenames, iter_filenames)
     115      for filename in filenames:
     116          lines = _iter_preprocessed(filename, **kwargs)
     117          show_file(filename, lines)
     118  
     119  
     120  def _cli_data(parser):
     121      ...
     122  
     123      return None
     124  
     125  
     126  def cmd_data(filenames,
     127               **kwargs
     128               ):
     129      # XXX
     130      raise NotImplementedError
     131  
     132  
     133  COMMANDS = {
     134      'preprocess': (
     135          'preprocess the given C source & header files',
     136          [_cli_preprocess],
     137          cmd_preprocess,
     138      ),
     139      'data': (
     140          'check/manage local data (e.g. excludes, macros)',
     141          [_cli_data],
     142          cmd_data,
     143      ),
     144  }
     145  
     146  
     147  #######################################
     148  # the script
     149  
     150  def parse_args(argv=sys.argv[1:], prog=sys.argv[0], *,
     151                 subset='preprocess',
     152                 excluded=None,
     153                 **prepr_kwargs
     154                 ):
     155      import argparse
     156      parser = argparse.ArgumentParser(
     157          prog=prog or get_prog(),
     158      )
     159  
     160      processors = add_commands_cli(
     161          parser,
     162          commands={k: v[1] for k, v in COMMANDS.items()},
     163          commonspecs=[
     164              add_verbosity_cli,
     165              add_traceback_cli,
     166          ],
     167          subset=subset,
     168      )
     169  
     170      args = parser.parse_args(argv)
     171      ns = vars(args)
     172  
     173      cmd = ns.pop('cmd')
     174  
     175      verbosity, traceback_cm = process_args_by_key(
     176          args,
     177          argv,
     178          processors[cmd],
     179          ['verbosity', 'traceback_cm'],
     180      )
     181  
     182      return cmd, ns, verbosity, traceback_cm
     183  
     184  
     185  def main(cmd, cmd_kwargs):
     186      try:
     187          run_cmd = COMMANDS[cmd][0]
     188      except KeyError:
     189          raise ValueError(f'unsupported cmd {cmd!r}')
     190      run_cmd(**cmd_kwargs)
     191  
     192  
     193  if __name__ == '__main__':
     194      cmd, cmd_kwargs, verbosity, traceback_cm = parse_args()
     195      configure_logger(verbosity)
     196      with traceback_cm:
     197          main(cmd, cmd_kwargs)