1import re 2 3from ._regexes import ( 4 GLOBAL as _GLOBAL, 5) 6from ._common import ( 7 log_match, 8 parse_var_decl, 9 set_capture_groups, 10) 11from ._compound_decl_body import DECL_BODY_PARSERS 12#from ._func_body import parse_function_body 13from ._func_body import parse_function_statics as parse_function_body 14 15 16GLOBAL = set_capture_groups(_GLOBAL, ( 17 'EMPTY', 18 'COMPOUND_LEADING', 19 'COMPOUND_KIND', 20 'COMPOUND_NAME', 21 'FORWARD_KIND', 22 'FORWARD_NAME', 23 'MAYBE_INLINE_ACTUAL', 24 'TYPEDEF_DECL', 25 'TYPEDEF_FUNC_PARAMS', 26 'VAR_STORAGE', 27 'FUNC_INLINE', 28 'VAR_DECL', 29 'FUNC_PARAMS', 30 'FUNC_DELIM', 31 'FUNC_LEGACY_PARAMS', 32 'VAR_INIT', 33 'VAR_ENDING', 34)) 35GLOBAL_RE = re.compile(rf'^ \s* {GLOBAL}', re.VERBOSE) 36 37 38def parse_globals(source, anon_name): 39 for srcinfo in source: 40 m = GLOBAL_RE.match(srcinfo.text) 41 if not m: 42 # We need more text. 43 continue 44 for item in _parse_next(m, srcinfo, anon_name): 45 if callable(item): 46 parse_body = item 47 yield from parse_body(source) 48 else: 49 yield item 50 else: 51 # We ran out of lines. 52 if srcinfo is not None: 53 srcinfo.done() 54 return 55 56 57def _parse_next(m, srcinfo, anon_name): 58 ( 59 empty, 60 # compound type decl (maybe inline) 61 compound_leading, compound_kind, compound_name, 62 forward_kind, forward_name, maybe_inline_actual, 63 # typedef 64 typedef_decl, typedef_func_params, 65 # vars and funcs 66 storage, func_inline, decl, 67 func_params, func_delim, func_legacy_params, 68 var_init, var_ending, 69 ) = m.groups() 70 remainder = srcinfo.text[m.end():] 71 72 if empty: 73 log_match('global empty', m) 74 srcinfo.advance(remainder) 75 76 elif maybe_inline_actual: 77 log_match('maybe_inline_actual', m) 78 # Ignore forward declarations. 79 # XXX Maybe return them too (with an "isforward" flag)? 80 if not maybe_inline_actual.strip().endswith(';'): 81 remainder = maybe_inline_actual + remainder 82 yield srcinfo.resolve(forward_kind, None, forward_name) 83 if maybe_inline_actual.strip().endswith('='): 84 # We use a dummy prefix for a fake typedef. 85 # XXX Ideally this case would not be caught by MAYBE_INLINE_ACTUAL. 86 _, name, data = parse_var_decl(f'{forward_kind} {forward_name} fake_typedef_{forward_name}') 87 yield srcinfo.resolve('typedef', data, name, parent=None) 88 remainder = f'{name} {remainder}' 89 srcinfo.advance(remainder) 90 91 elif compound_kind: 92 kind = compound_kind 93 name = compound_name or anon_name('inline-') 94 # Immediately emit a forward declaration. 95 yield srcinfo.resolve(kind, name=name, data=None) 96 97 # un-inline the decl. Note that it might not actually be inline. 98 # We handle the case in the "maybe_inline_actual" branch. 99 srcinfo.nest( 100 remainder, 101 f'{compound_leading or ""} {compound_kind} {name}', 102 ) 103 def parse_body(source): 104 _parse_body = DECL_BODY_PARSERS[compound_kind] 105 106 data = [] # members 107 ident = f'{kind} {name}' 108 for item in _parse_body(source, anon_name, ident): 109 if item.kind == 'field': 110 data.append(item) 111 else: 112 yield item 113 # XXX Should "parent" really be None for inline type decls? 114 yield srcinfo.resolve(kind, data, name, parent=None) 115 116 srcinfo.resume() 117 yield parse_body 118 119 elif typedef_decl: 120 log_match('typedef', m) 121 kind = 'typedef' 122 _, name, data = parse_var_decl(typedef_decl) 123 if typedef_func_params: 124 return_type = data 125 # This matches the data for func declarations. 126 data = { 127 'storage': None, 128 'inline': None, 129 'params': f'({typedef_func_params})', 130 'returntype': return_type, 131 'isforward': True, 132 } 133 yield srcinfo.resolve(kind, data, name, parent=None) 134 srcinfo.advance(remainder) 135 136 elif func_delim or func_legacy_params: 137 log_match('function', m) 138 kind = 'function' 139 _, name, return_type = parse_var_decl(decl) 140 func_params = func_params or func_legacy_params 141 data = { 142 'storage': storage, 143 'inline': func_inline, 144 'params': f'({func_params})', 145 'returntype': return_type, 146 'isforward': func_delim == ';', 147 } 148 149 yield srcinfo.resolve(kind, data, name, parent=None) 150 srcinfo.advance(remainder) 151 152 if func_delim == '{' or func_legacy_params: 153 def parse_body(source): 154 yield from parse_function_body(source, name, anon_name) 155 yield parse_body 156 157 elif var_ending: 158 log_match('global variable', m) 159 kind = 'variable' 160 _, name, vartype = parse_var_decl(decl) 161 data = { 162 'storage': storage, 163 'vartype': vartype, 164 } 165 yield srcinfo.resolve(kind, data, name, parent=None) 166 167 if var_ending == ',': 168 # It was a multi-declaration, so queue up the next one. 169 _, qual, typespec, _ = vartype.values() 170 remainder = f'{storage or ""} {qual or ""} {typespec} {remainder}' 171 srcinfo.advance(remainder) 172 173 if var_init: 174 _data = f'{name} = {var_init.strip()}' 175 yield srcinfo.resolve('statement', _data, name=None) 176 177 else: 178 # This should be unreachable. 179 raise NotImplementedError 180