| import re |
| |
| from ._regexes import ( |
| GLOBAL as _GLOBAL, |
| ) |
| from ._common import ( |
| log_match, |
| parse_var_decl, |
| set_capture_groups, |
| ) |
| from ._compound_decl_body import DECL_BODY_PARSERS |
| from ._func_body import parse_function_statics as parse_function_body |
| |
| |
| GLOBAL = set_capture_groups(_GLOBAL, ( |
| 'EMPTY', |
| 'COMPOUND_LEADING', |
| 'COMPOUND_KIND', |
| 'COMPOUND_NAME', |
| 'FORWARD_KIND', |
| 'FORWARD_NAME', |
| 'MAYBE_INLINE_ACTUAL', |
| 'TYPEDEF_DECL', |
| 'TYPEDEF_FUNC_PARAMS', |
| 'VAR_STORAGE', |
| 'FUNC_INLINE', |
| 'VAR_DECL', |
| 'FUNC_PARAMS', |
| 'FUNC_DELIM', |
| 'FUNC_LEGACY_PARAMS', |
| 'VAR_INIT', |
| 'VAR_ENDING', |
| )) |
| GLOBAL_RE = re.compile(rf'^ \s* {GLOBAL}', re.VERBOSE) |
| |
| |
| def parse_globals(source, anon_name): |
| for srcinfo in source: |
| m = GLOBAL_RE.match(srcinfo.text) |
| if not m: |
| # We need more text. |
| continue |
| for item in _parse_next(m, srcinfo, anon_name): |
| if callable(item): |
| parse_body = item |
| yield from parse_body(source) |
| else: |
| yield item |
| else: |
| # We ran out of lines. |
| if srcinfo is not None: |
| srcinfo.done() |
| return |
| |
| |
| def _parse_next(m, srcinfo, anon_name): |
| ( |
| empty, |
| # compound type decl (maybe inline) |
| compound_leading, compound_kind, compound_name, |
| forward_kind, forward_name, maybe_inline_actual, |
| # typedef |
| typedef_decl, typedef_func_params, |
| # vars and funcs |
| storage, func_inline, decl, |
| func_params, func_delim, func_legacy_params, |
| var_init, var_ending, |
| ) = m.groups() |
| remainder = srcinfo.text[m.end():] |
| |
| if empty: |
| log_match('global empty', m) |
| srcinfo.advance(remainder) |
| |
| elif maybe_inline_actual: |
| log_match('maybe_inline_actual', m) |
| # Ignore forward declarations. |
| # XXX Maybe return them too (with an "isforward" flag)? |
| if not maybe_inline_actual.strip().endswith(';'): |
| remainder = maybe_inline_actual + remainder |
| yield srcinfo.resolve(forward_kind, None, forward_name) |
| if maybe_inline_actual.strip().endswith('='): |
| # We use a dummy prefix for a fake typedef. |
| # XXX Ideally this case would not be caught by MAYBE_INLINE_ACTUAL. |
| _, name, data = parse_var_decl(f'{forward_kind} {forward_name} fake_typedef_{forward_name}') |
| yield srcinfo.resolve('typedef', data, name, parent=None) |
| remainder = f'{name} {remainder}' |
| srcinfo.advance(remainder) |
| |
| elif compound_kind: |
| kind = compound_kind |
| name = compound_name or anon_name('inline-') |
| # Immediately emit a forward declaration. |
| yield srcinfo.resolve(kind, name=name, data=None) |
| |
| # un-inline the decl. Note that it might not actually be inline. |
| # We handle the case in the "maybe_inline_actual" branch. |
| srcinfo.nest( |
| remainder, |
| f'{compound_leading or ""} {compound_kind} {name}', |
| ) |
| def parse_body(source): |
| _parse_body = DECL_BODY_PARSERS[compound_kind] |
| |
| data = [] # members |
| ident = f'{kind} {name}' |
| for item in _parse_body(source, anon_name, ident): |
| if item.kind == 'field': |
| data.append(item) |
| else: |
| yield item |
| # XXX Should "parent" really be None for inline type decls? |
| yield srcinfo.resolve(kind, data, name, parent=None) |
| |
| srcinfo.resume() |
| yield parse_body |
| |
| elif typedef_decl: |
| log_match('typedef', m) |
| kind = 'typedef' |
| _, name, data = parse_var_decl(typedef_decl) |
| if typedef_func_params: |
| return_type = data |
| # This matches the data for func declarations. |
| data = { |
| 'storage': None, |
| 'inline': None, |
| 'params': f'({typedef_func_params})', |
| 'returntype': return_type, |
| 'isforward': True, |
| } |
| yield srcinfo.resolve(kind, data, name, parent=None) |
| srcinfo.advance(remainder) |
| |
| elif func_delim or func_legacy_params: |
| log_match('function', m) |
| kind = 'function' |
| _, name, return_type = parse_var_decl(decl) |
| func_params = func_params or func_legacy_params |
| data = { |
| 'storage': storage, |
| 'inline': func_inline, |
| 'params': f'({func_params})', |
| 'returntype': return_type, |
| 'isforward': func_delim == ';', |
| } |
| |
| yield srcinfo.resolve(kind, data, name, parent=None) |
| srcinfo.advance(remainder) |
| |
| if func_delim == '{' or func_legacy_params: |
| def parse_body(source): |
| yield from parse_function_body(source, name, anon_name) |
| yield parse_body |
| |
| elif var_ending: |
| log_match('global variable', m) |
| kind = 'variable' |
| _, name, vartype = parse_var_decl(decl) |
| data = { |
| 'storage': storage, |
| 'vartype': vartype, |
| } |
| yield srcinfo.resolve(kind, data, name, parent=None) |
| |
| if var_ending == ',': |
| # It was a multi-declaration, so queue up the next one. |
| _, qual, typespec, _ = vartype.values() |
| remainder = f'{storage or ""} {qual or ""} {typespec} {remainder}' |
| srcinfo.advance(remainder) |
| |
| if var_init: |
| _data = f'{name} = {var_init.strip()}' |
| yield srcinfo.resolve('statement', _data, name=None) |
| |
| else: |
| # This should be unreachable. |
| raise NotImplementedError |