mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			158 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import re
 | |
| 
 | |
| from ._regexes import (
 | |
|     STRUCT_MEMBER_DECL as _STRUCT_MEMBER_DECL,
 | |
|     ENUM_MEMBER_DECL as _ENUM_MEMBER_DECL,
 | |
| )
 | |
| from ._common import (
 | |
|     log_match,
 | |
|     parse_var_decl,
 | |
|     set_capture_groups,
 | |
| )
 | |
| 
 | |
| 
 | |
| #############################
 | |
| # struct / union
 | |
| 
 | |
| STRUCT_MEMBER_DECL = set_capture_groups(_STRUCT_MEMBER_DECL, (
 | |
|     'COMPOUND_TYPE_KIND',
 | |
|     'COMPOUND_TYPE_NAME',
 | |
|     'SPECIFIER_QUALIFIER',
 | |
|     'DECLARATOR',
 | |
|     'SIZE',
 | |
|     'ENDING',
 | |
|     'CLOSE',
 | |
| ))
 | |
| STRUCT_MEMBER_RE = re.compile(rf'^ \s* {STRUCT_MEMBER_DECL}', re.VERBOSE)
 | |
| 
 | |
| 
 | |
| def parse_struct_body(source, anon_name, parent):
 | |
|     done = False
 | |
|     while not done:
 | |
|         done = True
 | |
|         for srcinfo in source:
 | |
|             m = STRUCT_MEMBER_RE.match(srcinfo.text)
 | |
|             if m:
 | |
|                 break
 | |
|         else:
 | |
|             # We ran out of lines.
 | |
|             if srcinfo is not None:
 | |
|                 srcinfo.done()
 | |
|             return
 | |
|         for item in _parse_struct_next(m, srcinfo, anon_name, parent):
 | |
|             if callable(item):
 | |
|                 parse_body = item
 | |
|                 yield from parse_body(source)
 | |
|             else:
 | |
|                 yield item
 | |
|             done = False
 | |
| 
 | |
| 
 | |
| def _parse_struct_next(m, srcinfo, anon_name, parent):
 | |
|     (inline_kind, inline_name,
 | |
|      qualspec, declarator,
 | |
|      size,
 | |
|      ending,
 | |
|      close,
 | |
|      ) = m.groups()
 | |
|     remainder = srcinfo.text[m.end():]
 | |
| 
 | |
|     if close:
 | |
|         log_match('compound close', m)
 | |
|         srcinfo.advance(remainder)
 | |
| 
 | |
|     elif inline_kind:
 | |
|         log_match('compound inline', m)
 | |
|         kind = inline_kind
 | |
|         name = inline_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'{kind} {name}',
 | |
|         )
 | |
|         def parse_body(source):
 | |
|             _parse_body = DECL_BODY_PARSERS[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
 | |
| 
 | |
|     else:
 | |
|         # not inline (member)
 | |
|         log_match('compound member', m)
 | |
|         if qualspec:
 | |
|             _, name, data = parse_var_decl(f'{qualspec} {declarator}')
 | |
|             if not name:
 | |
|                 name = anon_name('struct-field-')
 | |
|             if size:
 | |
| #                data = (data, size)
 | |
|                 data['size'] = int(size) if size.isdigit() else size
 | |
|         else:
 | |
|             # This shouldn't happen (we expect each field to have a name).
 | |
|             raise NotImplementedError
 | |
|             name = sized_name or anon_name('struct-field-')
 | |
|             data = int(size)
 | |
| 
 | |
|         yield srcinfo.resolve('field', data, name, parent)  # XXX Restart?
 | |
|         if ending == ',':
 | |
|             remainder = rf'{qualspec} {remainder}'
 | |
|         srcinfo.advance(remainder)
 | |
| 
 | |
| 
 | |
| #############################
 | |
| # enum
 | |
| 
 | |
| ENUM_MEMBER_DECL = set_capture_groups(_ENUM_MEMBER_DECL, (
 | |
|     'CLOSE',
 | |
|     'NAME',
 | |
|     'INIT',
 | |
|     'ENDING',
 | |
| ))
 | |
| ENUM_MEMBER_RE = re.compile(rf'{ENUM_MEMBER_DECL}', re.VERBOSE)
 | |
| 
 | |
| 
 | |
| def parse_enum_body(source, _anon_name, _parent):
 | |
|     ending = None
 | |
|     while ending != '}':
 | |
|         for srcinfo in source:
 | |
|             m = ENUM_MEMBER_RE.match(srcinfo.text)
 | |
|             if m:
 | |
|                 break
 | |
|         else:
 | |
|             # We ran out of lines.
 | |
|             if srcinfo is not None:
 | |
|                 srcinfo.done()
 | |
|             return
 | |
|         remainder = srcinfo.text[m.end():]
 | |
| 
 | |
|         (close,
 | |
|          name, init, ending,
 | |
|          ) = m.groups()
 | |
|         if close:
 | |
|             ending = '}'
 | |
|         else:
 | |
|             data = init
 | |
|             yield srcinfo.resolve('field', data, name, _parent)
 | |
|         srcinfo.advance(remainder)
 | |
| 
 | |
| 
 | |
| #############################
 | |
| 
 | |
| DECL_BODY_PARSERS = {
 | |
|     'struct': parse_struct_body,
 | |
|     'union': parse_struct_body,
 | |
|     'enum': parse_enum_body,
 | |
| }
 | 
