| from ..common.info import UNKNOWN, ID |
| |
| from . import declarations |
| |
| # XXX need tests: |
| # * variables |
| # * variable |
| # * variable_from_id |
| |
| |
| def _iter_vars(filenames, preprocessed, *, |
| handle_id=None, |
| _iter_decls=declarations.iter_all, |
| ): |
| if handle_id is None: |
| handle_id = ID |
| |
| for filename in filenames or (): |
| for kind, funcname, name, decl in _iter_decls(filename, |
| preprocessed=preprocessed, |
| ): |
| if kind != 'variable': |
| continue |
| varid = handle_id(filename, funcname, name) |
| yield varid, decl |
| |
| |
| # XXX Add a "handle_var" arg like we did for get_resolver()? |
| |
| def variables(*filenames, |
| perfilecache=None, |
| preprocessed=False, |
| known=None, # for types |
| handle_id=None, |
| _iter_vars=_iter_vars, |
| ): |
| """Yield (varid, decl) for each variable found in the given files. |
| |
| If "preprocessed" is provided (and not False/None) then it is used |
| to decide which tool to use to parse the source code after it runs |
| through the C preprocessor. Otherwise the raw |
| """ |
| if len(filenames) == 1 and not (filenames[0], str): |
| filenames, = filenames |
| |
| if perfilecache is None: |
| yield from _iter_vars(filenames, preprocessed) |
| else: |
| # XXX Cache per-file variables (e.g. `{filename: [(varid, decl)]}`). |
| raise NotImplementedError |
| |
| |
| def variable(name, filenames, *, |
| local=False, |
| perfilecache=None, |
| preprocessed=False, |
| handle_id=None, |
| _iter_vars=variables, |
| ): |
| """Return (varid, decl) for the first found variable that matches. |
| |
| If "local" is True then the first matching local variable in the |
| file will always be returned. To avoid that, pass perfilecache and |
| pop each variable from the cache after using it. |
| """ |
| for varid, decl in _iter_vars(filenames, |
| perfilecache=perfilecache, |
| preprocessed=preprocessed, |
| ): |
| if varid.name != name: |
| continue |
| if local: |
| if varid.funcname: |
| if varid.funcname == UNKNOWN: |
| raise NotImplementedError |
| return varid, decl |
| elif not varid.funcname: |
| return varid, decl |
| else: |
| return None, None # No matching variable was found. |
| |
| |
| def variable_from_id(id, filenames, *, |
| perfilecache=None, |
| preprocessed=False, |
| handle_id=None, |
| _get_var=variable, |
| ): |
| """Return (varid, decl) for the first found variable that matches.""" |
| local = False |
| if isinstance(id, str): |
| name = id |
| else: |
| if id.funcname == UNKNOWN: |
| local = True |
| elif id.funcname: |
| raise NotImplementedError |
| |
| name = id.name |
| if id.filename and id.filename != UNKNOWN: |
| filenames = [id.filename] |
| return _get_var(name, filenames, |
| local=local, |
| perfilecache=perfilecache, |
| preprocessed=preprocessed, |
| handle_id=handle_id, |
| ) |