1import re 2 3from ._regexes import ( 4 STRUCT_MEMBER_DECL as _STRUCT_MEMBER_DECL, 5 ENUM_MEMBER_DECL as _ENUM_MEMBER_DECL, 6) 7from ._common import ( 8 log_match, 9 parse_var_decl, 10 set_capture_groups, 11) 12 13 14############################# 15# struct / union 16 17STRUCT_MEMBER_DECL = set_capture_groups(_STRUCT_MEMBER_DECL, ( 18 'COMPOUND_TYPE_KIND', 19 'COMPOUND_TYPE_NAME', 20 'SPECIFIER_QUALIFIER', 21 'DECLARATOR', 22 'SIZE', 23 'ENDING', 24 'CLOSE', 25)) 26STRUCT_MEMBER_RE = re.compile(rf'^ \s* {STRUCT_MEMBER_DECL}', re.VERBOSE) 27 28 29def parse_struct_body(source, anon_name, parent): 30 done = False 31 while not done: 32 done = True 33 for srcinfo in source: 34 m = STRUCT_MEMBER_RE.match(srcinfo.text) 35 if m: 36 break 37 else: 38 # We ran out of lines. 39 if srcinfo is not None: 40 srcinfo.done() 41 return 42 for item in _parse_struct_next(m, srcinfo, anon_name, parent): 43 if callable(item): 44 parse_body = item 45 yield from parse_body(source) 46 else: 47 yield item 48 done = False 49 50 51def _parse_struct_next(m, srcinfo, anon_name, parent): 52 (inline_kind, inline_name, 53 qualspec, declarator, 54 size, 55 ending, 56 close, 57 ) = m.groups() 58 remainder = srcinfo.text[m.end():] 59 60 if close: 61 log_match('compound close', m) 62 srcinfo.advance(remainder) 63 64 elif inline_kind: 65 log_match('compound inline', m) 66 kind = inline_kind 67 name = inline_name or anon_name('inline-') 68 # Immediately emit a forward declaration. 69 yield srcinfo.resolve(kind, name=name, data=None) 70 71 # un-inline the decl. Note that it might not actually be inline. 72 # We handle the case in the "maybe_inline_actual" branch. 73 srcinfo.nest( 74 remainder, 75 f'{kind} {name}', 76 ) 77 def parse_body(source): 78 _parse_body = DECL_BODY_PARSERS[kind] 79 80 data = [] # members 81 ident = f'{kind} {name}' 82 for item in _parse_body(source, anon_name, ident): 83 if item.kind == 'field': 84 data.append(item) 85 else: 86 yield item 87 # XXX Should "parent" really be None for inline type decls? 88 yield srcinfo.resolve(kind, data, name, parent=None) 89 90 srcinfo.resume() 91 yield parse_body 92 93 else: 94 # not inline (member) 95 log_match('compound member', m) 96 if qualspec: 97 _, name, data = parse_var_decl(f'{qualspec} {declarator}') 98 if not name: 99 name = anon_name('struct-field-') 100 if size: 101# data = (data, size) 102 data['size'] = int(size) 103 else: 104 # This shouldn't happen (we expect each field to have a name). 105 raise NotImplementedError 106 name = sized_name or anon_name('struct-field-') 107 data = int(size) 108 109 yield srcinfo.resolve('field', data, name, parent) # XXX Restart? 110 if ending == ',': 111 remainder = rf'{qualspec} {remainder}' 112 srcinfo.advance(remainder) 113 114 115############################# 116# enum 117 118ENUM_MEMBER_DECL = set_capture_groups(_ENUM_MEMBER_DECL, ( 119 'CLOSE', 120 'NAME', 121 'INIT', 122 'ENDING', 123)) 124ENUM_MEMBER_RE = re.compile(rf'{ENUM_MEMBER_DECL}', re.VERBOSE) 125 126 127def parse_enum_body(source, _anon_name, _parent): 128 ending = None 129 while ending != '}': 130 for srcinfo in source: 131 m = ENUM_MEMBER_RE.match(srcinfo.text) 132 if m: 133 break 134 else: 135 # We ran out of lines. 136 if srcinfo is not None: 137 srcinfo.done() 138 return 139 remainder = srcinfo.text[m.end():] 140 141 (close, 142 name, init, ending, 143 ) = m.groups() 144 if close: 145 ending = '}' 146 else: 147 data = init 148 yield srcinfo.resolve('field', data, name, _parent) 149 srcinfo.advance(remainder) 150 151 152############################# 153 154DECL_BODY_PARSERS = { 155 'struct': parse_struct_body, 156 'union': parse_struct_body, 157 'enum': parse_enum_body, 158} 159