| 
									
										
										
										
											2020-10-22 18:42:51 -06:00
										 |  |  | import logging | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from c_common.scriptutil import ( | 
					
						
							|  |  |  |     add_verbosity_cli, | 
					
						
							|  |  |  |     add_traceback_cli, | 
					
						
							|  |  |  |     add_kind_filtering_cli, | 
					
						
							|  |  |  |     add_files_cli, | 
					
						
							|  |  |  |     add_commands_cli, | 
					
						
							|  |  |  |     process_args_by_key, | 
					
						
							|  |  |  |     configure_logger, | 
					
						
							|  |  |  |     get_prog, | 
					
						
							|  |  |  |     main_for_filenames, | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | from .preprocessor.__main__ import ( | 
					
						
							|  |  |  |     add_common_cli as add_preprocessor_cli, | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | from .info import KIND | 
					
						
							|  |  |  | from . import parse_file as _iter_parsed | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | logger = logging.getLogger(__name__) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _format_vartype(vartype): | 
					
						
							|  |  |  |     if isinstance(vartype, str): | 
					
						
							|  |  |  |         return vartype | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     data = vartype | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         vartype = data['vartype'] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         storage, typequal, typespec, abstract = vartype.values() | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         storage = data.get('storage') | 
					
						
							|  |  |  |         if storage: | 
					
						
							|  |  |  |             _, typequal, typespec, abstract = vartype.values() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             storage, typequal, typespec, abstract = vartype.values() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vartype = f'{typespec} {abstract}' | 
					
						
							|  |  |  |     if typequal: | 
					
						
							|  |  |  |         vartype = f'{typequal} {vartype}' | 
					
						
							|  |  |  |     if storage: | 
					
						
							|  |  |  |         vartype = f'{storage} {vartype}' | 
					
						
							|  |  |  |     return vartype | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _get_preprocessor(filename, **kwargs): | 
					
						
							|  |  |  |     return get_processor(filename, | 
					
						
							|  |  |  |                          log_err=print, | 
					
						
							|  |  |  |                          **kwargs | 
					
						
							|  |  |  |                          ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ####################################### | 
					
						
							|  |  |  | # the formats | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def fmt_raw(filename, item, *, showfwd=None): | 
					
						
							|  |  |  |     yield str(tuple(item)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def fmt_summary(filename, item, *, showfwd=None): | 
					
						
							| 
									
										
										
										
											2020-11-20 15:39:28 -07:00
										 |  |  |     if item.filename != filename: | 
					
						
							| 
									
										
										
										
											2020-10-22 18:42:51 -06:00
										 |  |  |         yield f'> {item.filename}' | 
					
						
							| 
									
										
										
										
											2020-11-20 15:39:28 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-22 18:42:51 -06:00
										 |  |  |     if showfwd is None: | 
					
						
							|  |  |  |         LINE = ' {lno:>5} {kind:10} {funcname:40} {fwd:1} {name:40} {data}' | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         LINE = ' {lno:>5} {kind:10} {funcname:40} {name:40} {data}' | 
					
						
							|  |  |  |     lno = kind = funcname = fwd = name = data = '' | 
					
						
							|  |  |  |     MIN_LINE = len(LINE.format(**locals())) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fileinfo, kind, funcname, name, data = item | 
					
						
							|  |  |  |     lno = fileinfo.lno if fileinfo and fileinfo.lno >= 0 else '' | 
					
						
							|  |  |  |     funcname = funcname or ' --' | 
					
						
							|  |  |  |     name = name or ' --' | 
					
						
							|  |  |  |     isforward = False | 
					
						
							|  |  |  |     if kind is KIND.FUNCTION: | 
					
						
							|  |  |  |         storage, inline, params, returntype, isforward = data.values() | 
					
						
							|  |  |  |         returntype = _format_vartype(returntype) | 
					
						
							|  |  |  |         data = returntype + params | 
					
						
							|  |  |  |         if inline: | 
					
						
							|  |  |  |             data = f'inline {data}' | 
					
						
							|  |  |  |         if storage: | 
					
						
							|  |  |  |             data = f'{storage} {data}' | 
					
						
							|  |  |  |     elif kind is KIND.VARIABLE: | 
					
						
							|  |  |  |         data = _format_vartype(data) | 
					
						
							|  |  |  |     elif kind is KIND.STRUCT or kind is KIND.UNION: | 
					
						
							|  |  |  |         if data is None: | 
					
						
							|  |  |  |             isforward = True | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             fields = data | 
					
						
							|  |  |  |             data = f'({len(data)}) {{ ' | 
					
						
							|  |  |  |             indent = ',\n' + ' ' * (MIN_LINE + len(data)) | 
					
						
							|  |  |  |             data += ', '.join(f.name for f in fields[:5]) | 
					
						
							|  |  |  |             fields = fields[5:] | 
					
						
							|  |  |  |             while fields: | 
					
						
							|  |  |  |                 data = f'{data}{indent}{", ".join(f.name for f in fields[:5])}' | 
					
						
							|  |  |  |                 fields = fields[5:] | 
					
						
							|  |  |  |             data += ' }' | 
					
						
							|  |  |  |     elif kind is KIND.ENUM: | 
					
						
							|  |  |  |         if data is None: | 
					
						
							|  |  |  |             isforward = True | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             names = [d if isinstance(d, str) else d.name | 
					
						
							|  |  |  |                      for d in data] | 
					
						
							|  |  |  |             data = f'({len(data)}) {{ ' | 
					
						
							|  |  |  |             indent = ',\n' + ' ' * (MIN_LINE + len(data)) | 
					
						
							|  |  |  |             data += ', '.join(names[:5]) | 
					
						
							|  |  |  |             names = names[5:] | 
					
						
							|  |  |  |             while names: | 
					
						
							|  |  |  |                 data = f'{data}{indent}{", ".join(names[:5])}' | 
					
						
							|  |  |  |                 names = names[5:] | 
					
						
							|  |  |  |             data += ' }' | 
					
						
							|  |  |  |     elif kind is KIND.TYPEDEF: | 
					
						
							|  |  |  |         data = f'typedef {data}' | 
					
						
							|  |  |  |     elif kind == KIND.STATEMENT: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         raise NotImplementedError(item) | 
					
						
							|  |  |  |     if isforward: | 
					
						
							|  |  |  |         fwd = '*' | 
					
						
							|  |  |  |         if not showfwd and showfwd is not None: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |     elif showfwd: | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     kind = kind.value | 
					
						
							|  |  |  |     yield LINE.format(**locals()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def fmt_full(filename, item, *, showfwd=None): | 
					
						
							|  |  |  |     raise NotImplementedError | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | FORMATS = { | 
					
						
							|  |  |  |     'raw': fmt_raw, | 
					
						
							|  |  |  |     'summary': fmt_summary, | 
					
						
							|  |  |  |     'full': fmt_full, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def add_output_cli(parser): | 
					
						
							|  |  |  |     parser.add_argument('--format', dest='fmt', default='summary', choices=tuple(FORMATS)) | 
					
						
							|  |  |  |     parser.add_argument('--showfwd', action='store_true', default=None) | 
					
						
							|  |  |  |     parser.add_argument('--no-showfwd', dest='showfwd', action='store_false', default=None) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-24 11:04:19 -07:00
										 |  |  |     def process_args(args, *, argv=None): | 
					
						
							| 
									
										
										
										
											2020-10-22 18:42:51 -06:00
										 |  |  |         pass | 
					
						
							|  |  |  |     return process_args | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ####################################### | 
					
						
							|  |  |  | # the commands | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _cli_parse(parser, excluded=None, **prepr_kwargs): | 
					
						
							|  |  |  |     process_output = add_output_cli(parser) | 
					
						
							|  |  |  |     process_kinds = add_kind_filtering_cli(parser) | 
					
						
							|  |  |  |     process_preprocessor = add_preprocessor_cli(parser, **prepr_kwargs) | 
					
						
							|  |  |  |     process_files = add_files_cli(parser, excluded=excluded) | 
					
						
							|  |  |  |     return [ | 
					
						
							|  |  |  |         process_output, | 
					
						
							|  |  |  |         process_kinds, | 
					
						
							|  |  |  |         process_preprocessor, | 
					
						
							|  |  |  |         process_files, | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def cmd_parse(filenames, *, | 
					
						
							|  |  |  |               fmt='summary', | 
					
						
							|  |  |  |               showfwd=None, | 
					
						
							|  |  |  |               iter_filenames=None, | 
					
						
							| 
									
										
										
										
											2020-11-20 15:39:28 -07:00
										 |  |  |               relroot=None, | 
					
						
							| 
									
										
										
										
											2020-10-22 18:42:51 -06:00
										 |  |  |               **kwargs | 
					
						
							|  |  |  |               ): | 
					
						
							|  |  |  |     if 'get_file_preprocessor' not in kwargs: | 
					
						
							|  |  |  |         kwargs['get_file_preprocessor'] = _get_preprocessor() | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         do_fmt = FORMATS[fmt] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         raise ValueError(f'unsupported fmt {fmt!r}') | 
					
						
							| 
									
										
										
										
											2020-11-20 15:39:28 -07:00
										 |  |  |     for filename, relfile in main_for_filenames(filenames, iter_filenames, relroot): | 
					
						
							| 
									
										
										
										
											2020-10-22 18:42:51 -06:00
										 |  |  |         for item in _iter_parsed(filename, **kwargs): | 
					
						
							| 
									
										
										
										
											2020-11-20 15:39:28 -07:00
										 |  |  |             item = item.fix_filename(relroot, fixroot=False, normalize=False) | 
					
						
							|  |  |  |             for line in do_fmt(relfile, item, showfwd=showfwd): | 
					
						
							| 
									
										
										
										
											2020-10-22 18:42:51 -06:00
										 |  |  |                 print(line) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _cli_data(parser): | 
					
						
							|  |  |  |     ... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def cmd_data(filenames, | 
					
						
							|  |  |  |              **kwargs | 
					
						
							|  |  |  |              ): | 
					
						
							|  |  |  |     # XXX | 
					
						
							|  |  |  |     raise NotImplementedError | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | COMMANDS = { | 
					
						
							|  |  |  |     'parse': ( | 
					
						
							|  |  |  |         'parse the given C source & header files', | 
					
						
							|  |  |  |         [_cli_parse], | 
					
						
							|  |  |  |         cmd_parse, | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  |     'data': ( | 
					
						
							|  |  |  |         'check/manage local data (e.g. excludes, macros)', | 
					
						
							|  |  |  |         [_cli_data], | 
					
						
							|  |  |  |         cmd_data, | 
					
						
							|  |  |  |     ), | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ####################################### | 
					
						
							|  |  |  | # the script | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def parse_args(argv=sys.argv[1:], prog=sys.argv[0], *, subset='parse'): | 
					
						
							|  |  |  |     import argparse | 
					
						
							|  |  |  |     parser = argparse.ArgumentParser( | 
					
						
							|  |  |  |         prog=prog or get_prog, | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     processors = add_commands_cli( | 
					
						
							|  |  |  |         parser, | 
					
						
							|  |  |  |         commands={k: v[1] for k, v in COMMANDS.items()}, | 
					
						
							|  |  |  |         commonspecs=[ | 
					
						
							|  |  |  |             add_verbosity_cli, | 
					
						
							|  |  |  |             add_traceback_cli, | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         subset=subset, | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     args = parser.parse_args(argv) | 
					
						
							|  |  |  |     ns = vars(args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cmd = ns.pop('cmd') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     verbosity, traceback_cm = process_args_by_key( | 
					
						
							|  |  |  |         args, | 
					
						
							| 
									
										
										
										
											2020-12-24 11:04:19 -07:00
										 |  |  |         argv, | 
					
						
							| 
									
										
										
										
											2020-10-22 18:42:51 -06:00
										 |  |  |         processors[cmd], | 
					
						
							|  |  |  |         ['verbosity', 'traceback_cm'], | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return cmd, ns, verbosity, traceback_cm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def main(cmd, cmd_kwargs): | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         run_cmd = COMMANDS[cmd][0] | 
					
						
							|  |  |  |     except KeyError: | 
					
						
							|  |  |  |         raise ValueError(f'unsupported cmd {cmd!r}') | 
					
						
							|  |  |  |     run_cmd(**cmd_kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     cmd, cmd_kwargs, verbosity, traceback_cm = parse_args() | 
					
						
							|  |  |  |     configure_logger(verbosity) | 
					
						
							|  |  |  |     with traceback_cm: | 
					
						
							|  |  |  |         main(cmd, cmd_kwargs) |