1from ..common.info import UNKNOWN, ID 2 3from . import declarations 4 5# XXX need tests: 6# * variables 7# * variable 8# * variable_from_id 9 10 11def _iter_vars(filenames, preprocessed, *, 12 handle_id=None, 13 _iter_decls=declarations.iter_all, 14 ): 15 if handle_id is None: 16 handle_id = ID 17 18 for filename in filenames or (): 19 for kind, funcname, name, decl in _iter_decls(filename, 20 preprocessed=preprocessed, 21 ): 22 if kind != 'variable': 23 continue 24 varid = handle_id(filename, funcname, name) 25 yield varid, decl 26 27 28# XXX Add a "handle_var" arg like we did for get_resolver()? 29 30def variables(*filenames, 31 perfilecache=None, 32 preprocessed=False, 33 known=None, # for types 34 handle_id=None, 35 _iter_vars=_iter_vars, 36 ): 37 """Yield (varid, decl) for each variable found in the given files. 38 39 If "preprocessed" is provided (and not False/None) then it is used 40 to decide which tool to use to parse the source code after it runs 41 through the C preprocessor. Otherwise the raw 42 """ 43 if len(filenames) == 1 and not (filenames[0], str): 44 filenames, = filenames 45 46 if perfilecache is None: 47 yield from _iter_vars(filenames, preprocessed) 48 else: 49 # XXX Cache per-file variables (e.g. `{filename: [(varid, decl)]}`). 50 raise NotImplementedError 51 52 53def variable(name, filenames, *, 54 local=False, 55 perfilecache=None, 56 preprocessed=False, 57 handle_id=None, 58 _iter_vars=variables, 59 ): 60 """Return (varid, decl) for the first found variable that matches. 61 62 If "local" is True then the first matching local variable in the 63 file will always be returned. To avoid that, pass perfilecache and 64 pop each variable from the cache after using it. 65 """ 66 for varid, decl in _iter_vars(filenames, 67 perfilecache=perfilecache, 68 preprocessed=preprocessed, 69 ): 70 if varid.name != name: 71 continue 72 if local: 73 if varid.funcname: 74 if varid.funcname == UNKNOWN: 75 raise NotImplementedError 76 return varid, decl 77 elif not varid.funcname: 78 return varid, decl 79 else: 80 return None, None # No matching variable was found. 81 82 83def variable_from_id(id, filenames, *, 84 perfilecache=None, 85 preprocessed=False, 86 handle_id=None, 87 _get_var=variable, 88 ): 89 """Return (varid, decl) for the first found variable that matches.""" 90 local = False 91 if isinstance(id, str): 92 name = id 93 else: 94 if id.funcname == UNKNOWN: 95 local = True 96 elif id.funcname: 97 raise NotImplementedError 98 99 name = id.name 100 if id.filename and id.filename != UNKNOWN: 101 filenames = [id.filename] 102 return _get_var(name, filenames, 103 local=local, 104 perfilecache=perfilecache, 105 preprocessed=preprocessed, 106 handle_id=handle_id, 107 ) 108