import os.path from c_common import fsutil import c_common.tables as _tables import c_parser.info as _info BASE_COLUMNS = [ 'filename', 'funcname', 'name', 'kind', ] END_COLUMNS = { 'parsed': 'data', 'decls': 'declaration', } def _get_columns(group, extra=None): return BASE_COLUMNS + list(extra or ()) + [END_COLUMNS[group]] #return [ # *BASE_COLUMNS, # *extra or (), # END_COLUMNS[group], #] ############################# # high-level def read_parsed(infile): # XXX Support other formats than TSV? columns = _get_columns('parsed') for row in _tables.read_table(infile, columns, sep='\t', fix='-'): yield _info.ParsedItem.from_row(row, columns) def write_parsed(items, outfile): # XXX Support other formats than TSV? columns = _get_columns('parsed') rows = (item.as_row(columns) for item in items) _tables.write_table(outfile, columns, rows, sep='\t', fix='-') def read_decls(infile, fmt=None): if fmt is None: fmt = _get_format(infile) read_all, _ = _get_format_handlers('decls', fmt) for decl, _ in read_all(infile): yield decl def write_decls(decls, outfile, fmt=None, *, backup=False): if fmt is None: fmt = _get_format(infile) _, write_all = _get_format_handlers('decls', fmt) write_all(decls, outfile, backup=backup) ############################# # formats def _get_format(file, default='tsv'): if isinstance(file, str): filename = file else: filename = getattr(file, 'name', '') _, ext = os.path.splitext(filename) return ext[1:] if ext else default def _get_format_handlers(group, fmt): # XXX Use a registry. if group != 'decls': raise NotImplementedError(group) if fmt == 'tsv': return (_iter_decls_tsv, _write_decls_tsv) else: raise NotImplementedError(fmt) # tsv def iter_decls_tsv(infile, extracolumns=None, relroot=fsutil.USE_CWD): if relroot and relroot is not fsutil.USE_CWD: relroot = os.path.abspath(relroot) for info, extra in _iter_decls_tsv(infile, extracolumns): decl = _info.Declaration.from_row(info) decl = decl.fix_filename(relroot, formatted=False, fixroot=False) yield decl, extra def write_decls_tsv(decls, outfile, extracolumns=None, *, relroot=fsutil.USE_CWD, **kwargs ): if relroot and relroot is not fsutil.USE_CWD: relroot = os.path.abspath(relroot) decls = (d.fix_filename(relroot, fixroot=False) for d in decls) # XXX Move the row rendering here. _write_decls_tsv(decls, outfile, extracolumns, kwargs) def _iter_decls_tsv(infile, extracolumns=None): columns = _get_columns('decls', extracolumns) for row in _tables.read_table(infile, columns, sep='\t'): if extracolumns: declinfo = row[:4] + row[-1:] extra = row[4:-1] else: declinfo = row extra = None # XXX Use something like tables.fix_row() here. declinfo = [None if v == '-' else v for v in declinfo] yield declinfo, extra def _write_decls_tsv(decls, outfile, extracolumns, kwargs): columns = _get_columns('decls', extracolumns) if extracolumns: def render_decl(decl): if type(row) is tuple: decl, *extra = decl else: extra = () extra += ('???',) * (len(extraColumns) - len(extra)) *row, declaration = _render_known_row(decl) row += extra + (declaration,) return row else: render_decl = _render_known_decl _tables.write_table( outfile, header='\t'.join(columns), rows=(render_decl(d) for d in decls), sep='\t', **kwargs ) def _render_known_decl(decl, *, # These match BASE_COLUMNS + END_COLUMNS[group]. _columns = 'filename parent name kind data'.split(), ): if not isinstance(decl, _info.Declaration): # e.g. Analyzed decl = decl.decl rowdata = decl.render_rowdata(_columns) return [rowdata[c] or '-' for c in _columns] # XXX #return _tables.fix_row(rowdata[c] for c in columns)