• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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