mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			178 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			178 lines
		
	
	
	
		
			5.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
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
 |