1import csv
2
3from ..common.info import ID, UNKNOWN
4from ..common.util import read_tsv
5from .info import Variable
6
7
8# XXX need tests:
9# * read_file()
10# * look_up_variable()
11
12
13COLUMNS = ('filename', 'funcname', 'name', 'kind', 'declaration')
14HEADER = '\t'.join(COLUMNS)
15
16
17def read_file(infile, *,
18              _read_tsv=read_tsv,
19              ):
20    """Yield (kind, id, decl) for each row in the data file.
21
22    The caller is responsible for validating each row.
23    """
24    for row in _read_tsv(infile, HEADER):
25        filename, funcname, name, kind, declaration = row
26        if not funcname or funcname == '-':
27            funcname = None
28        id = ID(filename, funcname, name)
29        yield kind, id, declaration
30
31
32def from_file(infile, *,
33              handle_var=Variable.from_id,
34              _read_file=read_file,
35              ):
36    """Return the info for known declarations in the given file."""
37    known = {
38        'variables': {},
39        #'types': {},
40        #'constants': {},
41        #'macros': {},
42        }
43    for kind, id, decl in _read_file(infile):
44        if kind == 'variable':
45            values = known['variables']
46            value = handle_var(id, decl)
47        else:
48            raise ValueError(f'unsupported kind in row {row}')
49        value.validate()
50        values[id] = value
51    return known
52
53
54def look_up_variable(varid, knownvars, *,
55                     match_files=(lambda f1, f2: f1 == f2),
56                     ):
57    """Return the known Variable matching the given ID.
58
59    "knownvars" is a mapping of ID to Variable.
60
61    "match_files" is used to verify if two filenames point to
62    the same file.
63
64    If no match is found then None is returned.
65    """
66    if not knownvars:
67        return None
68
69    if varid.funcname == UNKNOWN:
70        if not varid.filename or varid.filename == UNKNOWN:
71            for varid in knownvars:
72                if not varid.funcname:
73                    continue
74                if varid.name == varid.name:
75                    return knownvars[varid]
76            else:
77                return None
78        else:
79            for varid in knownvars:
80                if not varid.funcname:
81                    continue
82                if not match_files(varid.filename, varid.filename):
83                    continue
84                if varid.name == varid.name:
85                    return knownvars[varid]
86            else:
87                return None
88    elif not varid.filename or varid.filename == UNKNOWN:
89        raise NotImplementedError
90    else:
91        return knownvars.get(varid.id)
92