1import re 2 3from ._regexes import ( 4 _ind, 5 STRING_LITERAL, 6 VAR_DECL as _VAR_DECL, 7) 8 9 10def log_match(group, m, depth_before=None, depth_after=None): 11 from . import _logger 12 13 if m is not None: 14 text = m.group(0) 15 if text.startswith(('(', ')')) or text.endswith(('(', ')')): 16 _logger.debug(f'matched <{group}> ({text!r})') 17 else: 18 _logger.debug(f'matched <{group}> ({text})') 19 20 elif depth_before is not None or depth_after is not None: 21 if depth_before is None: 22 depth_before = '???' 23 elif depth_after is None: 24 depth_after = '???' 25 _logger.log(1, f'depth: %s -> %s', depth_before, depth_after) 26 27 else: 28 raise NotImplementedError('this should not have been hit') 29 30 31############################# 32# regex utils 33 34def set_capture_group(pattern, group, *, strict=True): 35 old = f'(?: # <{group}>' 36 if strict and f'(?: # <{group}>' not in pattern: 37 raise ValueError(f'{old!r} not found in pattern') 38 return pattern.replace(old, f'( # <{group}>', 1) 39 40 41def set_capture_groups(pattern, groups, *, strict=True): 42 for group in groups: 43 pattern = set_capture_group(pattern, group, strict=strict) 44 return pattern 45 46 47############################# 48# syntax-related utils 49 50_PAREN_RE = re.compile(rf''' 51 (?: 52 (?: 53 [^'"()]* 54 {_ind(STRING_LITERAL, 3)} 55 )* 56 [^'"()]* 57 (?: 58 ( [(] ) 59 | 60 ( [)] ) 61 ) 62 ) 63 ''', re.VERBOSE) 64 65 66def match_paren(text, depth=0): 67 pos = 0 68 while (m := _PAREN_RE.match(text, pos)): 69 pos = m.end() 70 _open, _close = m.groups() 71 if _open: 72 depth += 1 73 else: # _close 74 depth -= 1 75 if depth == 0: 76 return pos 77 else: 78 raise ValueError(f'could not find matching parens for {text!r}') 79 80 81VAR_DECL = set_capture_groups(_VAR_DECL, ( 82 'STORAGE', 83 'TYPE_QUAL', 84 'TYPE_SPEC', 85 'DECLARATOR', 86 'IDENTIFIER', 87 'WRAPPED_IDENTIFIER', 88 'FUNC_IDENTIFIER', 89)) 90 91 92def parse_var_decl(decl): 93 m = re.match(VAR_DECL, decl, re.VERBOSE) 94 (storage, typequal, typespec, declarator, 95 name, 96 wrappedname, 97 funcptrname, 98 ) = m.groups() 99 if name: 100 kind = 'simple' 101 elif wrappedname: 102 kind = 'wrapped' 103 name = wrappedname 104 elif funcptrname: 105 kind = 'funcptr' 106 name = funcptrname 107 else: 108 raise NotImplementedError 109 abstract = declarator.replace(name, '') 110 vartype = { 111 'storage': storage, 112 'typequal': typequal, 113 'typespec': typespec, 114 'abstract': abstract, 115 } 116 return (kind, name, vartype) 117 118 119############################# 120# parser state utils 121 122# XXX Drop this or use it! 123def iter_results(results): 124 if not results: 125 return 126 if callable(results): 127 results = results() 128 129 for result, text in results(): 130 if result: 131 yield result, text 132