• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import re
2
3from . import info as _info
4from .parser._regexes import SIMPLE_TYPE
5
6
7_KIND = _info.KIND
8
9
10def match_storage(decl, expected):
11    default = _info.get_default_storage(decl)
12    #assert default
13    if expected is None:
14        expected = {default}
15    elif isinstance(expected, str):
16        expected = {expected or default}
17    elif not expected:
18        expected = _info.STORAGE
19    else:
20        expected = {v or default for v in expected}
21    storage = _info.get_effective_storage(decl, default=default)
22    return storage in expected
23
24
25##################################
26# decl matchers
27
28def is_type_decl(item):
29    return _KIND.is_type_decl(item.kind)
30
31
32def is_decl(item):
33    return _KIND.is_decl(item.kind)
34
35
36def is_pots(typespec, *,
37            _regex=re.compile(rf'^{SIMPLE_TYPE}$', re.VERBOSE),
38            ):
39
40    if not typespec:
41        return None
42    if type(typespec) is not str:
43        _, _, _, typespec, _ = _info.get_parsed_vartype(typespec)
44    return _regex.match(typespec) is not None
45
46
47def is_funcptr(vartype):
48    if not vartype:
49        return None
50    _, _, _, _, abstract = _info.get_parsed_vartype(vartype)
51    return _is_funcptr(abstract)
52
53
54def _is_funcptr(declstr):
55    if not declstr:
56        return None
57    # XXX Support "(<name>*)(".
58    return '(*)(' in declstr.replace(' ', '')
59
60
61def is_forward_decl(decl):
62    if decl.kind is _KIND.TYPEDEF:
63        return False
64    elif is_type_decl(decl):
65        return not decl.data
66    elif decl.kind is _KIND.FUNCTION:
67        # XXX This doesn't work with ParsedItem.
68        return decl.signature.isforward
69    elif decl.kind is _KIND.VARIABLE:
70        # No var decls are considered forward (or all are...).
71        return False
72    else:
73        raise NotImplementedError(decl)
74
75
76def can_have_symbol(decl):
77    return decl.kind in (_KIND.VARIABLE, _KIND.FUNCTION)
78
79
80def has_external_symbol(decl):
81    if not can_have_symbol(decl):
82        return False
83    if _info.get_effective_storage(decl) != 'extern':
84        return False
85    if decl.kind is _KIND.FUNCTION:
86        return not decl.signature.isforward
87    else:
88        # It must be a variable, which can only be implicitly extern here.
89        return decl.storage != 'extern'
90
91
92def has_internal_symbol(decl):
93    if not can_have_symbol(decl):
94        return False
95    return _info.get_actual_storage(decl) == 'static'
96
97
98def is_external_reference(decl):
99    if not can_have_symbol(decl):
100        return False
101    # We have to check the declared storage rather tnan the effective.
102    if decl.storage != 'extern':
103        return False
104    if decl.kind is _KIND.FUNCTION:
105        return decl.signature.isforward
106    # Otherwise it's a variable.
107    return True
108
109
110def is_local_var(decl):
111    if not decl.kind is _KIND.VARIABLE:
112        return False
113    return True if decl.parent else False
114
115
116def is_global_var(decl):
117    if not decl.kind is _KIND.VARIABLE:
118        return False
119    return False if decl.parent else True
120
121
122##################################
123# filtering with matchers
124
125def filter_by_kind(items, kind):
126    if kind == 'type':
127        kinds = _KIND._TYPE_DECLS
128    elif kind == 'decl':
129        kinds = _KIND._TYPE_DECLS
130    try:
131        okay = kind in _KIND
132    except TypeError:
133        kinds = set(kind)
134    else:
135        kinds = {kind} if okay else set(kind)
136    for item in items:
137        if item.kind in kinds:
138            yield item
139
140
141##################################
142# grouping with matchers
143
144def group_by_category(decls, categories, *, ignore_non_match=True):
145    collated = {}
146    for decl in decls:
147        # Matchers should be mutually exclusive.  (First match wins.)
148        for category, match in categories.items():
149            if match(decl):
150                if category not in collated:
151                    collated[category] = [decl]
152                else:
153                    collated[category].append(decl)
154                break
155        else:
156            if not ignore_non_match:
157                raise Exception(f'no match for {decl!r}')
158    return collated
159
160
161def group_by_kind(items):
162    collated = {kind: [] for kind in _KIND}
163    for item in items:
164        try:
165            collated[item.kind].append(item)
166        except KeyError:
167            raise ValueError(f'unsupported kind in {item!r}')
168    return collated
169
170
171def group_by_kinds(items):
172    # Collate into kind groups (decl, type, etc.).
173    collated = {_KIND.get_group(k): [] for k in _KIND}
174    for item in items:
175        group = _KIND.get_group(item.kind)
176        collated[group].append(item)
177    return collated
178